面试题答案
一键面试1. Polyfill 实现
every
:
if (!Array.prototype.every) {
Array.prototype.every = function (callback, thisArg) {
for (let i = 0; i < this.length; i++) {
if (!callback.call(thisArg, this[i], i, this)) {
return false;
}
}
return true;
};
}
some
:
if (!Array.prototype.some) {
Array.prototype.some = function (callback, thisArg) {
for (let i = 0; i < this.length; i++) {
if (callback.call(thisArg, this[i], i, this)) {
return true;
}
}
return false;
};
}
filter
:
if (!Array.prototype.filter) {
Array.prototype.filter = function (callback, thisArg) {
let result = [];
for (let i = 0; i < this.length; i++) {
if (callback.call(thisArg, this[i], i, this)) {
result.push(this[i]);
}
}
return result;
};
}
map
:
if (!Array.prototype.map) {
Array.prototype.map = function (callback, thisArg) {
let result = [];
for (let i = 0; i < this.length; i++) {
result.push(callback.call(thisArg, this[i], i, this));
}
return result;
};
}
reduce
:
if (!Array.prototype.reduce) {
Array.prototype.reduce = function (callback, initialValue) {
let accumulator = initialValue;
let startIndex = 0;
if (initialValue === undefined) {
accumulator = this[0];
startIndex = 1;
}
for (let i = startIndex; i < this.length; i++) {
accumulator = callback(accumulator, this[i], i, this);
}
return accumulator;
};
}
2. 避免全局污染
- 模块封装:将这些 polyfill 代码封装到一个模块中。例如,使用 ES6 模块:
// arrayPolyfills.js
export const addArrayPolyfills = () => {
if (!Array.prototype.every) {
Array.prototype.every = function (callback, thisArg) {
for (let i = 0; i < this.length; i++) {
if (!callback.call(thisArg, this[i], i, this)) {
return false;
}
}
return true;
};
}
// 其他方法类似
};
在需要使用的地方引入并调用 addArrayPolyfills
函数:
import {addArrayPolyfills} from './arrayPolyfills.js';
addArrayPolyfills();
- 使用 IIFE(立即执行函数表达式):
(function () {
if (!Array.prototype.every) {
Array.prototype.every = function (callback, thisArg) {
for (let i = 0; i < this.length; i++) {
if (!callback.call(thisArg, this[i], i, this)) {
return false;
}
}
return true;
};
}
// 其他方法类似
})();
3. 性能优化
- 减少不必要计算:在 polyfill 实现中,尽量减少重复计算。例如在
reduce
中,合理处理initialValue
来避免多余的循环。 - 缓存长度:在循环中缓存数组长度,避免每次循环都读取
this.length
,如:
let len = this.length;
for (let i = 0; i < len; i++) {
// 循环体
}
4. 工具
- Babel:可以自动为目标环境添加 polyfill。配置
.babelrc
文件,设置presets
为@babel/preset - env
,并指定目标环境,如:
{
"presets": [
[
"@babel/preset - env",
{
"targets": {
"browsers": ["ie >= 9"]
}
}
]
]
}
- Webpack:结合 Babel 插件,用于打包项目,确保 polyfill 正确引入和处理。
5. 性能测试和对比
- 工具:
- Benchmark.js:是一个简单而强大的 JavaScript 基准测试套件。例如:
import Benchmark from 'benchmark';
const suite = new Benchmark.Suite;
const arr = Array.from({length: 1000}, (_, i) => i + 1);
suite
.add('native every', function () {
arr.every((num) => num > 0);
})
.add('polyfill every', function () {
if (!Array.prototype.every) {
// polyfill code here
}
arr.every((num) => num > 0);
})
.on('cycle', function (event) {
console.log(String(event.target));
})
.on('complete', function () {
console.log('Fastest is'+ this.filter('fastest').map('name'));
})
.run({ 'async': true });
- 对比方式:
- 分别对原生方法和 polyfill 方法进行多次测试,记录执行时间。
- 在不同规模的数组(如长度为 100、1000、10000 等)上进行测试,观察性能变化趋势。
- 在不同环境(如不同版本的浏览器、Node.js 环境)下测试,确保 polyfill 在老旧环境性能也能接受。