【JavaScript】call, apply, bind

问题

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上下文中执行后的结果

总而言之 它们具有如下共同点:

  1. 目的明确,都是为了替换当前函数中的 this 上下文
  2. thisArg 无效时会选择全局作为当前上下文,这和函数的 this 定义保持一致

总而言之 它们具有如下不同点:

  1. callbind 接受参数列表,apply 接受数组 作为调用方法时传递的参数
  2. callapply 返回执行的结果,而 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!

// 这很优雅!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值