问题
Function.prototype 中的 [call, apply, bind] 之间有什么区别
描述
首先肯定是拼写不同了 …..
让我们打死楼上那个发言者,然后继续讨论这3个方法,其实从原型就可以看出它们之间的区别:
Function.prototype.call(thisArg [ , arg1 [ , arg2, … ] ] )
=>
返回该方法在 thisArg
上下文中执行后的结果
Function.prototype.bind(thisArg [, arg1 [, arg2, …]])
=>
返回一个该方法作用于 thisArg
上下文中的版本
Function.prototype.apply(thisArg, argArray)
=>
返回该方法在 thisArg
上下文中执行后的结果
总而言之 它们具有如下共同点:
- 目的明确,都是为了替换当前函数中的
this
上下文 thisArg
无效时会选择全局作为当前上下文,这和函数的this
定义保持一致
总而言之 它们具有如下不同点:
call
和bind
接受参数列表,apply
接受数组 作为调用方法时传递的参数call
和apply
返回执行的结果,而bind
返回一个新方法
接下来演示它们的常见用法:
代码
Math.max.apply(null, [1, 2, 3, 4, 5])
// => 5 老生长谈了吧 这里的上下文并没有什么卵用 所以用null
Array.prototype.slice.apply({ 0: "ele_0", 1: "ele_1", 2: "ele_2", length: 3})
// => ["ele_0", "ele_1", "ele_2"] 这是为什么呢 换一种思路看看
[].slice.apply({ 0: "ele_0", 1: "ele_1", 2: "ele_2", length: 3}, [1])
// => ["ele_1", "ele_2"]
[].slice.apply({ 0: "ele_0", 1: "ele_1", 2: "ele_2", length: 3}, [0])
// => ["ele_0", "ele_1", "ele_2"]
[].slice.apply({ 0: "ele_0", 1: "ele_1", 2: "ele_2", length: 3}, [-1])
// => ["ele_2"]
// 由此可以看出 大概是slice内部搞的鬼
(function() { return [].slice.apply(arguments); })(1,2,3,4,5)
// => [1, 2, 3, 4, 5]
// 同时slice的运作方式依赖属性length 由此arguments也可以这么搞
// 囧 然后我们可以写自己的call了 ... 当然这个不传 thisArg 是不行的 ...
Function.prototype.mycall = function() {
return this.apply(arguments[0], [].slice.apply(arguments).slice(1));
}
// 以下是一些特殊情况
[].slice.apply({ '-1': "ele_-1", 0: "ele_0", 1: "ele_1", 2: "ele_2", length: 4})
// => ["ele_0", "ele_1", "ele_2", undefined × 1]
[].slice.apply({ 0: "ele_0", 1: "ele_1", 2: "ele_2", length: 100})
// => ["ele_0", "ele_1", "ele_2", undefined × 97]
// 最后说一下
// 其实 Array.prototype.slice, [].slice, new Array().slice 都一样的
// 很明显中间那个最短 ...
// 割 -----------------------------------
// 以百度为例,我们撸一个计数器,统计我们单击百度LOGO的次数并向控制台输出
var ClickCounter = function() {
this.cnt = 0;
document.getElementById('s_lg_img').onclick = function() {
/* this.cnt += 1; console.log(this.cnt); */
};
}
// 很明显 注释里的 this 是拿不到ClickCounter中的cnt值的
// 一般情况下 我(们?)都是这么干♂的
var ClickCounter = function() {
this.cnt = 0; var that = this;
document.getElementById('s_lg_img').onclick = function() {
that.cnt += 1; console.log(that.cnt);
};
}
new ClickCounter(); // 然后疯狂戳度娘的LOGO吧
// 很明显 如果继续嵌套下去 写一堆 that 会疯的 这时候 bind 出场了
var ClickCounter = function() {
this.cnt = 0; var that = this;
document.getElementById('s_lg_img').onclick = function() {
this.cnt += 1; console.log(this.cnt);
}.bind(this);
}
new ClickCounter(); // let's do this!
// 这很优雅!