bind和call、apply最大的区别
call 和 apply 的主要作用,是改变对象的执行上下文,并且是立即执行的。
bind 也能改变对象的执行上下文,它与 call 和 apply 不同的是,返回值是一个函数,并且需要稍后再调用一下,才会执行。
call和apply的共同点
- call和apply都能够改变函数执行时的上下文,将一个对象的方法交给另一个对象来执行,并且是立即执行的。
- 调用 call 和 apply 的对象,必须是一个函数 ,Function。
- call 和apply 的第一个参数,都是一个对象, Function 的调用者,将会指向这个对象。如果不传,则默认为全局对象 window。
call和apply的区别
就在第二个参数的不同形式上。
- call 的写法,第二个参数开始,可以接收任意个参数。每个参数会映射到相应位置的 Function 的参数上。
Function.call(obj,[param1[,param2[,…[,paramN]]]])
- apply 的写法,第二个参数,必须是数组或者类数组,它们会被转换成类数组,传入 Function 中,并且会被映射到 Function 对应的参数上。
Function.apply(obj[,argArray])
call和apply的应用
- 对象继承。subClass 通过 call 方法,继承了 superClass 的 print 方法和 a 变量。
function superClass () { this.a = 1; this.print = function () { console.log(this.a); } } function subClass () { superClass.call(this); this.print(); } subClass(); // 1
- 借用方法。
function log(){ console.log.apply(console, arguments); }; log(1); //1 log(1,2); //1 2
- 便捷记忆
猫吃鱼,狗吃肉,奥特曼打小怪兽。
有天狗想吃鱼了猫.吃鱼.call(狗,鱼)
狗就吃到鱼了
猫成精了,想打怪兽
奥特曼.打小怪兽.call(猫,小怪兽)
猫也可以打小怪兽了
手写apply
Function.prototype.myAppy = function (tartget, ...args) {
if (typeof this !== 'function') {
throw new TypeError('Error')
}
const that = this; // 保持功能函数this
const tartgetArgs = [...args]; // 保存初始参数
tartget[that.name] = that;
const result = tartget[that.name](...tartgetArgs);
return result;
}
const a = {
name: 'a',
testfn: function (...agrs) {
console.log('这是', this.name, '的方法,参数是:', ...agrs);
}
}
a.testfn('aaa'); // 这是 a 的方法,参数是: aaa
let b = { name: 'b' };
a.testfn.myAppy(b, ['bbb', 'ccc']); // 这是 b 的方法,参数是: ["bbb", "ccc"]
a.testfn.myAppy(b, 'ddd'); //这是 b 的方法,参数是: ddd
bind的特点
- bind() 方法和call很像,第一个参数是this的指向,从第二个参数开始是接收的参数列表。只是bind会创建一个新的函数,并在调用新函数时,将第二个参数作为原函数的参数序列的前若干项,将新函数返回,而并不会立即调用。
- bind不兼容(IE5,6,7,8)
bind的写法
Function.bind(thisArg[, arg1[, arg2[, ...]]])
bind的应用
- 借用方法。
function log(){ return console.log.bind(console, ...arguments); }; let k = log(1); // 不会调用 k(); // 这里才会调用,输出1
手写bind
Function.prototype.myBind = function (tartget, ...args) {
if (typeof this !== 'function') {
throw new TypeError('Error')
}
const that = this; // 保持函数this
const tartgetArgs = [...args]; // 保存初始参数
tartget[that.name] = function (...args) { // 给target创建一个新函数,名字为that.name
return that.apply(tartget, args.length > 0 ? args : tartgetArgs); // 执行函数,调用apply,抽取闭包保留下来的that和tartgetArgs
};
return tartget;
}
const a = {
name: 'a',
testfn: function (...agrs) {
console.log('这是', this.name, '的方法,参数是:', ...agrs);
}
}
a.testfn('aaa'); // 这是 a 的方法,参数是: aaa
let b = { name: 'b' };
b = a.testfn.myBind(b, 'bbb', 'ccc');
b.testfn(); // 这是 b 的方法,参数是: bbb ccc
b.testfn('ddd', 'eee'); // 这是 b 的方法,参数是: ddd eee