由于在低版本浏览器没有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)
复制代码