原生API的手动实现
Posted by Mars . Modified at
部分原生API的手动实现
一、数组 reduce()方法
二、对象 深拷贝
一、数组Array
1. reduce()方法
function myReduce(arr, fn = (accu, item, index, array) => {}, init) {
// 判断arr是否是数组;
if (Object.prototype.toString.call(arr).slice(8,-1) !== 'Array') {
throw new Error('Must be called to an array.');
}
// 判断fn是否是函数;
if (Object.prototype.toString.call(fn).slice(8,-1) !== 'Function') {
throw new Error('No callback function.');
}
// 当没有提供初始值,初始值设为arr[0],并且从1位置开始遍历;
// 提供了初始值,从0位置开始遍历;
let start = 0;
if (init === undefined) {
if (arr.length === 0) throw new Error('Call reduce with no init value to an empty array.');
init = arr[0];
start = 1;
}
// 执行函数,迭代修改init。
for (let i=start; i<arr.length; i++) {
init = fn(init, arr[i], i, arr);
}
// 返回最终结果。
return init;
}
2. map()方法
// for循环实现
function myMap(arr, fn = i => i) {
if (!Array.isArray(arr)) throw new Error(`myMap must be called on Array instance.`);
if (typeof fn !== 'function') throw new Error(`the second parameter must be function.`);
let res = new Array(arr.length);
for (let i=0; i<arr.length; i++) {
res[i] = fn(arr[i], i, arr);
}
return res;
}
// reduce方法实现
function myMap2(arr, fn = i => i) {
if (!Array.isArray(arr)) throw new Error(`myMap must be called on Array instance.`);
if (typeof fn !== 'function') throw new Error(`the second parameter must be function.`);
return arr.reduce((res, item, index, array) => {
return [...res, fn(item, index, array)];
}, []);
}
3. filter()方法
function myFilter(arr, fn) {
if (Object.prototype.toString.call(arr).slice(8,-1) !== 'Array') {
throw new Error('Must be called to an array.');
}
if (Object.prototype.toString.call(fn).slice(8,-1) !== 'Function') {
throw new Error('No callback function.');
}
let res = [];
for (let i=0; i<arr.length; i++) {
let cur = fn(arr[i], i, arr);
if (cur) res.push(arr[i]);
}
return res;
}
二、对象
1. call、apply 和 bind
1.1 call 和 apply
基本思路:
- 如果传入上下文context,则把方法挂载到context,如果没有则挂载到window;
- 为临时挂载的方法设置一个独一无二的symbol键名;
- 通过context调用this指向的方法;
- 调用完成,删除context上临时挂载的方法。
// call.js
Function.prototype.myCall = function(context, ...args) {
let c = context || window;
let sym = Symbol('callFn');
context[sym] = this;
let res = context[sym](...args);
delete context[sym];
return res;
};
apply相似,把第二个参数设置为数组即可。
1.2 bind
基本思路:
- 传入一个上下文context,如果没有则为window;
- myBind内部this指向需要被绑定的原始函数fn;
- 返回一个函数binded,通过fn.call(context),手动指定其内部的this指向;
- 返回这个函数即可。
// bind.js
Function.prototype.myBind = function(context) {
let c = context || window;
let fn = this;
let binded = function(){
fn.call(c);
}
return binded;
}