在后台发生什么,以防止调用更改此对象的绑定方法

What happens under the hood to prevent calling a bound method changing the this object?

本文关键字:对象 方法 绑定 调用 后台 什么      更新时间:2023-09-26

请考虑以下代码:

var o1 = { name: 'o1' };
var o2 = {
  name: 'o2',
  foo: function() { console.log(this.name); }.bind(o1)
}
o2.foo(); // o1 because of the 'bind'
o2.foo.call(o2); // o1 - why?

这是绑定方法的特定功能,其上下文中的 this 对象永远不能被调用或应用覆盖吗?

来自 MDN

bind()函数创建一个新函数(绑定函数),其中 相同的函数体(ECMAScript 5 术语中的内部调用属性)为 正在调用它的函数(绑定函数的目标 函数),将 this 值绑定到 bind() 的第一个参数, 无法覆盖


ECMA 规范 v5.1 的技术版本 - 在第 15.3.4.5 + 15.3.4.5.1 节中定义:

15.3.4.5 Function.prototype.bind (thisArg [, arg1 [, arg2, ...]])

bind 方法采用一个或多个参数,thisArg和(可选) arg1, arg2, etc ,并通过执行 以下步骤:

  1. 让"目标"为this值。
  2. 如果IsCallable(Target)为 false,则引发TypeError异常。
  3. 让 A 成为所有参数的新(可能是空的)内部列表 在 thisArgarg1, arg2 etc ) 之后按顺序提供的值。
  4. 让我们F成为一个新的原生 ECMAScript 对象。
  5. 按照指定设置F的所有内部方法(除 [[Get]] 之外) 在 8.12 中。
  6. 按照 15.3.5.4 中的规定设置 F[[Get]]内部属性。
  7. F[[TargetFunction]]内部属性设置为"目标"。
  8. F[[BoundThis]]内部属性设置为值 thisArg .
    ...

15.3.4.5.1 [[调用]]

当函数对象的[[Call]]内部方法F时,它是 使用 bind 函数创建的函数使用 this 值和列表进行调用 的参数 ExtraArgs,采取以下步骤:

设 boundArgs 是 F [[BoundArgs]]内部属性的值。让 bound这是 F [[BoundThis]]内部属性的值。让 目标是 F [[TargetFunction]]内部属性的值。让 args 是一个新列表,其中包含与列表 boundArgs 相同的值 与列表中的 ExtraArgs 相同的顺序后跟相同的值 相同的顺序。返回调用内部[[Call]]的结果 目标提供绑定的方法此作为此值并提供 参数作为参数

它受闭包保护,你可以像这样实现同样的事情

Function.prototype.bind = function( obj ) {
  var orig_function = this;
  return function() {
    return orig_function.apply(obj, arguments);
  }
}

解释

了解Function.prototype.apply

使用 applycall 可以调用具有特定上下文的函数,请参阅以下示例:

name = 'window';
obj = {name: 'obj'}
fn = function() {
    return this.name;
}
fn() // => 'window'
fn.apply(obj) // => 'obj'
fn.call(obj) // => 'obj'

开头的代码返回一个新函数,该函数使用 apply 将上下文绑定到传递的对象。 希望这有帮助