前端面试题之JS手写bind

前端面试题之JS手写bind

首先解释一下bind:

bind() 方法会创建一个新函数。当这个新函数被调用时,bind() 的第一个参数将作为它运行时的 this,之后的一序列参数将会在传递的实参前传入作为它的参数。(来自于 MDN )

给个例子:

var value = 'v in window';
function func() {
    console.log(this.value);
}
var obj = {
    value: 'v in obj'
};
func(); //v in window
var newFunc = func.bind(obj);
newFunc(); //v in obj

用法类似call和apply,调用返回的newFunc函数类似调用func.call(obj)或者func.apply。
根据这个原理,手写一个bind2:

var value = 'v in window';
function func() {
    console.log(this.value);
}
var obj = {
    value: 'v in obj'
};
Function.prototype.bind2 = function (obj) {
    var that = this;
    return function () {
        that.apply(obj); //call和apply都可以,这里用apply主要是为了方便后面处理带参数的情况
    }
};
func(); //v in window
var newFunc = func.bind2(obj);
newFunc(); //v in obj

bind2返回一个函数,调用这个函数时,that指向之前的func,相当于func.apply(obj),实现了bind功能
处理一下带参数的情况:

var value = 'v in window';
function func() {
    arguments = [].splice.call(arguments, 0); //这一句是把参数转成数组,因为arguments不是数组,输出的时候容易观察
    console.log(arguments);
    console.log(this.value);
}
var obj = {
    value: 'v in obj'
};
Function.prototype.bind2 = function (obj) {
    var that = this;
    var args = [].splice.call(arguments,1);
    return function () {
        that.apply(obj,args);
    }
};
func(1,2,3); 
//[1,2,3]
//v in window
var newFunc = func.bind2(obj,1,2,3);
newFunc();
//[1,2,3]
//v in window

官方bind还有一个特点:

var value = 'v in window';
function func() {
    arguments = [].splice.call(arguments, 0); //这一句是把参数转成数组,因为arguments不是数组,输出的时候容易观察
    console.log(arguments);
    console.log(this.value);
}
var obj = {
    value: 'v in obj'
};
var newFunc = func.bind(obj,1,2,3);
newFunc(4,5,6); 
//[1, 2, 3, 4, 5, 6]
//v in obj

如果给newFunc传参数,他可以把参数拼接起来,修改一下

Function.prototype.bind2 = function (obj) {
    var that = this;
    var args = [].splice.call(arguments,1);
    return function () {
        var newArgs = [].splice.call(arguments,0); //将newFunc的参数变成数组
        that.apply(obj,args.concat(newArgs)); //将上面的数组和之前的参数数组结合
    }
};

处理一下返回的函数被作为构造函数的情况:

Function.prototype.bind2 = function (obj) {
    var that = this;
    var args = [].slice.call(arguments,1);
    var func =  function () {
        that.apply(this instanceof func ? this : obj,args.concat([].splice.call(arguments,0))); //用来判断是不是作为构造函数:this instanceof func === true是则是构造函数
    };
    fNOP.prototype = this.prototype; //利用空函数fNOP实现继承原型链同时又不改变原函数的原型链
    fbound.prototype = new fNOP();
    return func;
};

最后处理一下兼容问题:

Function.prototype.bind2 = function (obj) {
    if (typeof this !== "function") { //不是函数不能调用bind方法
      throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
    }
    var that = this;
    var args = [].slice.call(arguments,1);
    var func =  function () {
        that.apply(this instanceof func ? this : obj,args.concat([].splice.call(arguments,0))); //用来判断是不是作为构造函数:this instanceof func === true是则是构造函数
    };
    fNOP.prototype = this.prototype; //利用空函数fNOP实现继承原型链同时又不改变原函数的原型链
    fbound.prototype = new fNOP();
    return func;
};

猜你喜欢

转载自blog.csdn.net/qq593249106/article/details/83120475
今日推荐