面试手写

126 阅读3分钟

new

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

语法:new constructor[([arguments])]

参数:
constructor: 一个指定对象实例的类型的类或函数。
arguments: 一个用于被 constructor 调用的参数列表

描述:
new 关键字会进行如下的操作:
1.创建一个空的简单JavaScript对象(即{});
2.链接该对象(设置该对象的constructor)到另一个对象 ;
3.将步骤1新创建的对象作为this的上下文 ;
4.如果该函数没有返回对象,则返回this。
详情-new-MDN

// 第二版的代码(讶羽大佬)
function objectFactory() {
    var obj = new Object(), // 关联注里面obj
    Constructor = [].shift.call(arguments);
    obj.__proto__ = Constructor.prototype; 
    var ret = Constructor.apply(obj, arguments); // new实现原理
    return typeof ret === 'object' ? ret : obj;
};

JavaScript深入之new的模拟实现-讶羽

注:
1.new构造函数分为两种:①无return返回或return返回非对象②return对象即object
2.调用apply改变this指针(即obj添加属性值)

bind

定义:bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。

语法:function.bind(thisArg[, arg1[, arg2[, ...]]])

参数: thisArg; arg1,arg2...

thisArg
调用绑定函数时作为 this 参数传递给目标函数的值。 如果使用new运算符构造绑定函数,则忽略该值。当使用 bindsetTimeout 中创建一个函数(作为回调提供)时,作为 thisArg 传递的任何原始值都将转换为 object。如果 bind 函数的参数列表为空,或者thisArgnullundefined,执行作用域的 this 将被视为新函数的 thisArg
arg1, arg2, ...
当目标函数被调用时,被预置入绑定函数的参数列表中的参数。

返回值:返回一个原函数的拷贝,并拥有指定的 this 值和初始参数。 MDN链接

有两种实现bind的方法

第一种:不支持使用new调用新创建的构造函数

 Function.prototype.bind = function () {
    var slice = Array.prototype.slice;
    var thatFunc = this, // this为调用函数
        thatArg = arguments[0];
    var args = slice.call(arguments, 1); // bind函数的arguments
    if (typeof thatFunc !== 'function') {
        // closest thing possible to the ECMAScript 5
        // internal IsCallable function
        throw new TypeError('Function.prototype.bind - ' +
            'what is trying to be bound is not callable');
    }
    return function () {
        var funcArgs = args.concat(slice.call(arguments)) // 新函数arguments
        return thatFunc.apply(thatArg, funcArgs);
    };
};
// 第二版(来自讶羽大神)
Function.prototype.bind2 = function (context) {
    var self = this;
    // 获取bind2函数从第二个参数到最后一个参数
    var args = Array.prototype.slice.call(arguments, 1);
    return function () {
        // 这个时候的arguments是指bind返回的函数传入的参数
        var bindArgs = Array.prototype.slice.call(arguments);
        self.apply(context, args.concat(bindArgs));
    }
}

第二种:支持使用new调用新创建的构造函数

//  Yes, it does work with `new (funcA.bind(thisArg, args))`
Function.prototype.bind = function (otherThis) { // otherThis:this绑定参数
    var slice = Array.prototype.slice;
    if (typeof this !== 'function') {
        throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
    }
    var baseArgs = slice.call(arguments, 1), // bind函数arguments
        baseArgsLength = baseArgs.length,
        fToBind = this, // 原函数

        fNOP = function () {},

        fBound = function () {
            baseArgs.length = baseArgsLength; // reset to default base arguments
            baseArgs.push.apply(baseArgs, arguments);
            return fToBind.apply(
                fNOP.prototype.isPrototypeOf(this) ? this : otherThis, baseArgs
            );
        };
    if (this.prototype) {
        // Function.prototype doesn't have a prototype property
        fNOP.prototype = this.prototype;
    }
    fBound.prototype = new fNOP();
    return fBound;
};

// 讶羽实现
Function.prototype.bind2 = function (context) {
    if (typeof this !== "function") {
      throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
    }
    var self = this;
    var args = Array.prototype.slice.call(arguments, 1);
    var fNOP = function () {};
    var fbound = function () {
        // 如果是new this instanceof self => true
        self.apply(this instanceof self ? this : context, args.concat(Array.prototype.slice.call(arguments)));
    }
    fNOP.prototype = this.prototype;
    fbound.prototype = new fNOP();
    return fbound;
}