(1) call的实现
Function.prototype.myCall = function(context,...args){
const ctx= context || window; // 需要绑定到的上下文环境,无则默认为window
const func = Symbol(); // 使用Symbol定义,避免重复key值
ctx[func] = this; // 此时this为传入的待执行的函数,使用对象属性的方式存储起来
// 通过执行对象的函数,使得this指向该对象,即传入的context上下文
const res = args.length > 0 ? ctx[func](...args):ctx[func]();
delete ctx[func]; // 执行完清除存储的待执行函数
return res;
}
// 验证
function A(x,y){
console.log(this,x,y)
}
function B(){}
A(); // window,undefined,undefined
A.call(B,1,2); // ƒ B(){} 1 2
A.myCall(B,1,2); // ƒ B(){} 1 2
(2) apply的实现
Function.prototype.myApply = function(context,args=[]){
const ctx= context || window; // 需要绑定到的上下文环境,无则默认为window
const func = Symbol(); // 使用Symbol定义,避免重复key值
ctx[func] = this; // 此时this为传入的待执行的函数,使用对象属性的方式存储起来
// 通过执行对象的函数,使得this指向该对象,即传入的context上下文
const res = args.length > 0 ? ctx[func](...args):ctx[func]();
delete ctx[func]; // 执行完清除存储的待执行函数
return res;
}
// 验证
function A(x,y){
console.log(this,x,y)
}
function B(){}
A(); // window,undefined,undefined
A.apply(B,[1,2]); // ƒ B(){} 1 2
A.myApply(B,[1,2]); // ƒ B(){} 1 2
(3) bind 的实现
Function.prototype.myBind = function(){
const func = this; // 当前待执行的函数
const ctx = [].shift.call(arguments); // this指向需要改为参数列表传入的第一个值
const args = arguments; // arguments此时包含除上下文之外的其他参数
// 返回新的待执行的函数(已改变this指向)
return function newFn(...newArgs){
// 如果新的上下文指向已经是当前原型对象的实例,则无需更改指向
if (this instanceof newFn) {
return new func(...args, ...newFnArgs)
}
return func.apply(ctx,[...args,...newArgs])
}
}
// 验证1
function A(x,y){
console.log(this)
console.log('x:',x,' y:',y);
}
function B(){}
A(); // window x: undefined y: undefined
A.myBind(B)(1,2) // ƒ B(){} x: 1 y: 2
A.myBind(B)([1,2]) // ƒ B(){} x: [1, 2] y: undefined
// 验证2
function A(x,y,...restNum){
console.log(this, 'x:',x, ' y:',y, ' restNum:',restNum)
}
function B(){}
// 4,5为args,1,2,3为newArgs
A.myBind(B,4,5)(1,2,3) // ƒ B(){} "x:" 4 " y:" 5 " restNum:" [1, 2, 3]
(4) new的实现
function myNew(){
const obj = {}; // 创建一个新的空对象
const ctx = [].shift.call(arguments); // 获取到父类的上下文
obj.__proto__ = ctx.prototype; // 将父类的原型对象绑定到新的对象上
const args = arguments;
const res = ctx.apply(obj,args); // 使this指向新对象以此执行Parent的构造函数
return res instanceof Object ? res: obj; // Parent构造函数有返回值则使用res否则返回新对象
}
function father(name){ this.name = name; }
var son = myNew(father,'cwh')
console.log(son instanceof father) // true
console.log(son.name) // cwh
console.log(son.__proto__ === father.prototype) // true
(5) promise的实现
https://github.com/CWH0908/MyPromise
(6) instanceOf的实现
function myInstanceOf(son,father){
let left = son.__proto__;
const right = father.prototype;
while(true){
if(left === null){
return false;
}
if(left === right){
return true;
}
left = left.__proto__;
}
}
function father(){};
var son = new father();
myInstanceOf(son,father); // true
(7) object.create()的实现
Object.prototype.myCreate = function(obj){
// 新声明一个函数
function func(){};
// 将函数的原型指向obj
func.prototype = obj;
// 返回这个函数的实例化对象
return new func();
}
// 验证代码
var source= {val: 1};
var test = Object.myCreate(test);
test.val = 2;
console.log(test.val); // 2
delete test.val;
console.log(test.val); // 1,沿着原型链找到source对象的属性val
(8) Object.assign的实现
Object.myAssign = function(target,...source){
if(typeof target === 'undefined' || target === null){
return new TypeError('target不能传入undefined或null')
}
let res = Object(target)
// 遍历传入的对象数组
source.forEach(obj=>{
if(obj){
// obj非空,遍历
for(const key in obj){
if(obj.hasOwnProperty(key)){
res[key] = obj[key];
}
}
}
})
return res;
}
var a = {name:'a'}
Object.myAssign(a,{name:'b',age:20},{age:30}) // {name: "b", age: 30}
(9) promise.all的实现
Promise.myAll = function(promiseArr){
let count = 0; // 存储当前成功的个数
let result = []; // 存储返回成功的数据
return new Promise((resolve,reject)=>{
// 遍历传入的数组
promiseArr.forEach(item=>{
Promise.resolve(item).then(res=>{
result[count] = res;
count++;
// 全部成功,返回
if(count === promiseArr.length){
resolve(result)
}
},err=>{
// 有一个失败,返回
reject(error);
})
})
})
}
Promise.myAll([
Promise.resolve(1),
Promise.resolve(2),
Promise.resolve(3),
]).then((res) => {
console.log("res:", res); // res: [1,2,3]
});
(10) Promise.race的实现
Promise.myRace = function(promiseArr){
return new Promise((resolve,reject)=>{
promiseArr.forEach(item=>{
Promise.resolve(item).then(res=>{
resolve(res);
},err=>{
reject(err);
})
})
})
}
Promise.myRace([
new Promise((resolve,reject)=>{
setTimeout(_=>{
return resolve(111)},
1000)}),
Promise.resolve(222)
]).then(res=>{
console.log('res:',res); // res:222
})
(11) Array.flat的实现
function myFlat(arr){
return arr.reduce((pre,next)=>{
return pre.concat(Array.isArray(next)?myFlat(next):next)
},[])
}
let arr = [1,2,[3,4,[5,[6]]]]
console.log(myFlat(arr)) // [1, 2, 3, 4, 5, 6]
(12) Debounce的实现
function myDebounce(func,delay=500){
let timer; // 初始化定时器
return function(...args){
clearTimeout(timer); // 每次调用函数,清除之前的定时器
timer = setTimeout(_=>{
func(...args);
},delay)
}
}
// 测试代码
function test(e,text){
console.log(e.target.innerWidth,e.target.innerHeight,text)
}
window.addEventListener('resize',myDebounce(e=>{test(e,'哈哈哈')},1000))
(13) Throttle的实现
function myThrottle(func,delay=500){
let noRun = true; // 初始化,当前函数未执行
return function(...args){
if(noRun){
noRun = false; // 执行当前函数
setTimeout(_=>{
func(...args);
noRun = true; // 函数执行完毕
},delay)
}
}
}
// 测试代码
function test(e,text){
console.log(e.target.innerWidth,e.target.innerHeight,text)
}
window.addEventListener('resize',myThrottle(e => {test(e,'哈哈')},1000))
参考文章:一文帮你搞定90%的JS手写题