如何自己实现bind方法

由于在低版本浏览器没有js原生bind方法,所以要兼容低版本浏览器的话就要手动实现

了解bind函数

bind 强制将函数的执行环境绑定到目标作用域中去

与 call 和 apply 其实有点类似,但是不同点在于,bind 方法不会立即执行,而是返回一个改变了上下文 this 后的函数

因此我们要想自己实现一个 bind 函数,就必须要返回一个函数,而且这个函数会接收绑定的参数的上下文。

if (!Function.prototype.bind) {
    Function.prototype.bind = function () {
        if(typeof this != 'function'){// 判断调用者是不是函数
            throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
        }
        var self = this,                        // 保存原函数 (this指向调用bind者)
        context = [].shift.call(arguments), // 把参数中的第一个剪切出来,保存需要绑定的this上下文
        args = [].slice.call(arguments);    // 剩余的参数转为数组
        return function () {                    // 返回一个新函数
            self.apply(context,[].concat.call(args, [].slice.call(arguments)));
        }
    }
}
复制代码

arguments 的含义

arguments 是一个对应于传递给函数的参数的类数组对象,没有 shift 等数组独有的方法

function fun(){
  console.log(arguments)
  console.log(Array.prototype.slice.call(arguments))
}
console.log(fun('a','b'));
复制代码

arguments转换成数组 方法一

先将 arguments 转为数组,然后再对其运用了 slice 方法 Array.prototype.shift === [].shift

Array.prototype.slice.call(arguments); //通过原型的方式直接在类上调用
[].slice.call(arguments);    //通过实例化,继承过来,然后再调用

//["a", "b"]
复制代码

arguments转换成数组 方法二

es6 为数组新增了一个 from 方法

Array.from(temp).slice();   //["a", "b"]
复制代码

为什么要合并参数

作者看文章的时候看到[].concat.call(args, [].slice.call(arguments)也有点蒙圈,参数不就是args么,为什么要合并它自己?如果你也是这么认为的那就请认真往下阅读 其实args是绑定上下文的时候(也就是bind())传递的参数,而后面的arguments则是调用bind()()第二个括号传递的参数,所以这里才会需要合并 如果还是有点不明白可以看看一下的代码,懂了的可跳过啦

Function.prototype.binding = function () {
    let self = this;
    let context = [].shift.call(arguments);
    let args = [].slice.call(arguments);
    console.log(args);

    return function () {
        self.apply(context, [].concat.call(args, [].slice.call(arguments)))
    }
};

let obj = {
    a: 'a'
};

function f(b, c, d) {
    console.log(this.a, b, c, d)
}

f.binding(obj, 'b', 'c', 'd')('e');
f.binding(obj, 'b', 'c')('d', 'e');
f.binding(obj, 'b')('c', 'd', 'e');
f.binding(obj)('b', 'c', 'd', 'e');

输出:
[ 'b', 'c', 'd' ]   a b c d
[ 'b', 'c' ]   a b c d
[ 'b' ]   a b c d
[] a b c d
复制代码

补充

slice() 方法可从已有的数组中返回选定的元素  //slice(2,4)
shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值
unshift() 方法可向数组的开头添加一个或更多元素,并返回新的长度
复制代码
Array.from() 
从一个类似数组或可迭代对象中创建一个新的,浅拷贝的数组实例。

Array.from('foo'); //Array ["f", "o", "o"]
Array.from([1, 2, 3], x => x + x); //Array [2, 4, 6]
复制代码

apply的用法

function setName(){
  this.name='haha';
}
function person(){
  setName.apply(this);
}
var person=new person();
console.log(person.name);
复制代码

apply与bind的区别

const person = { name: 'ximelly' }

function sayHi(age) {
console.log(`${this.name} is ${age}`)
}

//call和apply 立即执行
sayHi.call(person, 21)

//bind 返回带有绑定上下文的函数副本,但不立即执行
sayHi.bind(person, 21)()
sayHi.bind(person)(21)
复制代码

转载于:https://juejin.im/post/5d0b1903f265da1b904be75e

猜你喜欢

转载自blog.csdn.net/weixin_34235105/article/details/93174779
今日推荐