实现 call/apply/bind/new

自己实现call apply bind new来理解这些函数的作用

这里用es6语法实现,只用es5语法实现可见 https://github.com/mqyqingfeng/Blog/issues/11

call

简介

call指定了函数的this值和参数并调用函数

fun.call(thisArg, arg1, arg2, ...);

实现

function myCall(obj, ...args) {
    obj = obj || window; // call对象为null情况下指向window
    obj._fn = this; // 将函数设置为obj的属性
    let result = obj._fn(...args); // 调用函数,此时函数的this就指向了obj
    delete obj._fn; // 调用完毕后,在obj对象中删除fn属性
    return result; // 返回函数调用结果
}

Function.prototype.call = myCall;

let obj = {
    name: 'obj'
};
function logMyName() {
    console.log(this.name);
}

logMyName.call(obj); // obj

apply

简介

与call类似,只是接受参数的方式有所不同

func.apply(thisArg, [argsArray]);

实现

function myApply(obj, args) {
    obj = obj || window; // call对象为null情况下指向window
    obj._fn = this; // 将函数设置为obj的属性
    let result = obj._fn(...args); // 调用函数,此时函数的this就指向了obj
    delete obj._fn; // 调用完毕后,在obj对象中删除fn属性
    return result; // 返回函数调用结果
}

Function.prototype.apply = myApply;

bind

简介

bind方法创建一个新的函数,当这个新函数被调用时this为其提供的值,其参数列表前几项值为创建时指定的参数序列。

实现

function myBind(obj, ...args) {
    let self = this; // 记录函数
    let fNOP = function(){}; // 空对象用于原型继承

    let fBound = function (...args2) {
        return self.apply(this instanceof fNOP ? this : obj, [...args, ...args2]); // 如果this原型链上有fNOP则说明被new调用,则借用构造函数
    };

    fNOP.prototype = this.prototype; 
    fBound.prototype = new fNOP(); // 利用空函数让fBound.prototype能访问到this.prototype
    return fBound;
}

Function.prototype.bind = myBind;

new

简介

new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象类型之一

实现

function myNew(fn, ...args) {
    let F = function () {}; // 空函数
    F.prototype = fn.prototype; // 原型链接
    let obj = new F(); // 继承

    let temp = fn.apply(obj, args);
    return typeof temp === 'object' ? temp : obj; // 如果返回值是对象则返回对象
}

function Person(name) {
    this.name = name;
    this.sex = 'man';
}

console.log(myNew(Person, 'hong')) // Person { name: 'hong', sex: 'man' }

参考

https://github.com/mqyqingfeng/Blog

最后更新于

这有帮助吗?