资讯专栏INFORMATION COLUMN

关于JS函数的bind

CloudwiseAPM / 2019人阅读

摘要:昨天被人问到的的作用是什么这个倒还能回答出来,之后返回一个新的函数,这个函数可以保持传递的上下文。没有完全实现规定的。比如规定了的和行为。

https://friskfly.github.io/2016/03/24/about-function-bind-in-js/

昨天被人问到js的bind的作用是什么?

这个倒还能回答出来,bind 之后返回一个新的函数,这个函数可以保持传递的this上下文。

接着又问了,那么bind两次不同的上下文会怎样?

这个一下子就蒙了,因为平时也没这么用过,于是开始查一下资料。

首先在浏览器中测试一下。

function test(){
  console.log(this.a)
}
var bind1 = test.bind({a:1}) //第一次 bind
var bind2 = bind1.bind({a:2}) // 第二次 bind
bind1()
bind2()

结果如下

1
1

可以看到第二次bind并没有能再改变this的值。

查一下MDN,Function.prototype.bind() , 并没有解释bind两次会怎样。 但是他提供了一个Polyfill,可以了解下bind的实现。

if (!Function.prototype.bind) {
  Function.prototype.bind = function(oThis) {
    if (typeof this !== "function") {
      // closest thing possible to the ECMAScript 5
      // internal IsCallable function
      throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
    }

    var aArgs   = Array.prototype.slice.call(arguments, 1),
        fToBind = this,
        fNOP    = function() {},
        fBound  = function() {
          return fToBind.apply(this instanceof fNOP
                 ? this
                 : oThis,
                 aArgs.concat(Array.prototype.slice.call(arguments)));
        };

    if (this.prototype) {
      // Function.prototype doesn"t have a prototype property
      fNOP.prototype = this.prototype;
    }
    fBound.prototype = new fNOP();

    return fBound;
  };
}

可以看到MDN提供的polyfill的实现是oThis做为参数传进来,返回一个新的函数,这个时候函数是个闭包,仍然可以访问oThis变量,然后调用call/apply来实现指定的上下文。 这种情况下,如果bind两次,相当于闭包套闭包,不管套几层,值都是第一次保存的this值。 即上面polyfill的 oThis 变量。

光看polyfill是不够了,因为并不知道polyfill实现是不是标准。所以还是要看下规范。这里我们参考下 ES2015文档

可以直接看到 19.2.3.2 节 NOTE 2,If Target is an arrow function or a bound function then the thisArg passed to this method will not be used by subsequent calls to F. 如果调用bind的是一个箭头函数或者是已经bind过的函数(bound function),那么再次bind是不会起作用的。 可以看到规范已经定义了这样的行为产生的结果,我们可以直接记住这个结论。

但是这里值得注意的是,我们看到规范定义的bind操作 和 MDN 上提供的polyfill并不一致。polyfill没有完全实现ES2015规定的bind。

比如ES2015 规定了 bound function 的length 和 name 行为。

Let targetHasLength be HasOwnProperty(Target, "length").
ReturnIfAbrupt(targetHasLength).
If targetHasLength is true, then
  Let targetLen be Get(Target, "length").
  ReturnIfAbrupt(targetLen).
  If Type(targetLen) is not Number, let L be 0.
  Else,
    Let targetLen be ToInteger(targetLen).
      Let L be the larger of 0 and the result of targetLen minus the number of elements of args.
Else let L be 0.

这里会规定bound function 的 length 属性,应该和bind之前的length一致。

再看name 的行为

Let targetName be Get(Target, "name").
ReturnIfAbrupt(targetName).
If Type(targetName) is not String, let targetName be the empty string.
Perform SetFunctionName(F, targetName, "bound").

这里规定bound function 的name 应该走 SetFunctionName 方法,而这里SetFunctionName之后的返回值应该是 bound字符串 + 空格 + 原先函数的name

......忽略了一些描述
prefix即bound 字符串
If prefix was passed, then
  Let name be the concatenation of prefix, code unit 0x0020 (SPACE), and name.

function a(){}
var b = a.bind()
console.log(b.name)

结果应该是

bound a

而 MDN 的 polyfill 是没有实现这些细节的,所以用bind的时候如果依赖于这些,是要注意的。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/79032.html

相关文章

  • JS 关于 bind ,call,apply 和arguments p8

    摘要:同样会绑定,也会穿参数,但是不会立即执行我是内部的我是内部的类似数组,但不是真的数组,好吧,就把它当成数组吧,它同样拥有而且也可以通过下标访问关于下面的官方语言警告在严格模式下,第版禁止使用。关于这3个货,网上有很多文章介绍,我这边还是记录下并加上自己的理解,还有arguments函数内置对象顺便也记录下: 简单的说apply和call 会绑定第一个参数的作用域给调用函数对象实例,并会执行...

    番茄西红柿 评论0 收藏0
  • Javascript:call(),apply()和bind()

    摘要:在面向对象的中,我们了解到在中,一切都是对象。到目前为止,我们已将函数视为由名称可选,也可以是匿名函数组成的对象及其在调用时执行的代码。这意味着,我们可以调用任何函数,并在调用函数中明确指定。和用于完全相同的目的。 What s this 在面向对象的JS中,我们了解到在JS中,一切都是对象。因为一切都是对象,我们开始明白我们可以为函数设置和访问其他属性。而this提供了一种更优雅的方...

    WrBug 评论0 收藏0
  • Javascript:call(),apply()和bind()

    摘要:在面向对象的中,我们了解到在中,一切都是对象。到目前为止,我们已将函数视为由名称可选,也可以是匿名函数组成的对象及其在调用时执行的代码。这意味着,我们可以调用任何函数,并在调用函数中明确指定。和用于完全相同的目的。 What s this 在面向对象的JS中,我们了解到在JS中,一切都是对象。因为一切都是对象,我们开始明白我们可以为函数设置和访问其他属性。而this提供了一种更优雅的方...

    Sike 评论0 收藏0
  • Javascript:call(),apply()和bind()

    摘要:在面向对象的中,我们了解到在中,一切都是对象。到目前为止,我们已将函数视为由名称可选,也可以是匿名函数组成的对象及其在调用时执行的代码。这意味着,我们可以调用任何函数,并在调用函数中明确指定。和用于完全相同的目的。 What s this 在面向对象的JS中,我们了解到在JS中,一切都是对象。因为一切都是对象,我们开始明白我们可以为函数设置和访问其他属性。而this提供了一种更优雅的方...

    sarva 评论0 收藏0
  • 你不知道js技巧

    摘要:所谓的高级,其实就是讲了一些我们平常用不到或许用了不知道,但是非常实在的东西。比如如果你想检测里面的属性值的话,基本上是不可能的。要知道,我们是有情怀的淫。 JS进阶 说起这个应该算是老生常谈了吧。所谓的高级,其实就是讲了一些我们平常用不到(或许用了不知道),但是非常实在的东西。算是熟练掌握js的一个必经road吧。 检测函数类型 其实检测函数的类型应该算是js的一个痛点,因为js是一...

    edagarli 评论0 收藏0

发表评论

0条评论

CloudwiseAPM

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<