在.bind和.apply中覆盖`this`

时间:2019-05-24 16:33:14

标签: javascript

我正在读this page只是为了精通.apply语法,但我意识到我在JS知识方面存在空白:

您可以使用this.bind来更改函数中.apply的值(我假设.call遵循与.apply相同的规则,所以我不会单独讨论)。所以我想知道,如果我先使用.bind然后再使用.apply进行调用,那会优先吗?

所以我只是从w3schools看了这个示例并对其进行了修改:

var person = {
  fullName: function(city, country) {
    return this.firstName + " " + this.lastName + "," + city + "," + country;
  }
}
var person1 = {
  firstName: "John",
  lastName: "Doe"
}

var person2 = {
  firstName: "Mary",
  lastName: "Anne"
}

fn = person.fullName.bind(person2);

console.log(fn.apply(person1, ["Oslo", "Norway"]));

因此,如果打印出玛丽·安妮(Mary Anne),则this给出的.bind的值优先于.apply给出的值。

做到了!与安妮结婚。因此,我想知道是否还有我不太了解的关于this的其他规则。例如,您可以在呼叫.bind之后重新绑定吗?

4 个答案:

答案 0 :(得分:3)

除了实现Function.prototype.bind的方式外,没有什么可以阻止重新绑定的。没错,调用绑定后,this的值是固定的,Function.prototype.apply无法覆盖它。

代替使用Function.prototype.bind,您可以使用它来绑定参数:

Function.prototype.create = function(){
  const args = arguments;
  const original = this;
  return function() {
    return original.call(this, ...args, ...arguments);
  }
};

但是,修改原型可能会出现问题,因此我会避免创建一个辅助函数。我确信像lodash这样的实用程序库或ramda都可以做到这一点。

您可以像这样使用它:

const fn = function (one, two, three) {
    return this + one + two + three;
};


const boundfn = fn.create(1, 2);
const val = boundfn.call(-6, 3);

console.log({val});

是的,我们传递了-6作为this的值。 :)

-6 + 6 = 0

注意:避免这样做!玩弄上下文是错误的方法,而且绝对不能起作用。我会避免传递this,因为它是一个不可见的参数,而且“很难推理”。

答案 1 :(得分:2)

.bind返回绑定函数绑定函数箭头函数将永远不会再更改其上下文,因此您无法重新.bind它们或.apply其他上下文。

如果我们假设.bind是用JavaScript本身编写的,那么它可能会变得更加清楚……然后它将写为:

  function bind(context, ...args) {
    const fn = this;
    return function(...args2) {
      // Note: "this" does not get accessed inside this function, so .bind ing it or .apply ing another context doesnt change anything
      return fn.call(context, ...args, ...args2);
    }
 }

答案 2 :(得分:2)

根据规范:

  

注2:如果func是箭头功能或绑定功能,则在步骤X中,此[Arg]将被功能[[Call]]忽略。

这适用于所有三个绑定功能。

bind创建一个绑定函数,该函数不是普通函数(它是exotic object),并且不包含原型。

https://www.ecma-international.org/ecma-262/6.0/#sec-function.prototype.apply

答案 3 :(得分:0)

.bind创建一个具有添加的this上下文以及您要 curry 的参数的新函数,并且无法用{{1 }},this(除非您的apply方法不是本地的),对于已经提到https://stackoverflow.com/a/31656748/906265

的已有ES2015 spec for bind的答案

来自MDN

  

bind()方法创建一个新函数,该函数在被调用时将其this关键字设置为提供的值,并在调用新函数时提供给定的参数序列。

callbind允许您在调用函数时覆盖函数的.apply值,但不适用于用ES2015 spec note 2编写的箭头或绑定函数

  

如果func是箭头函数或绑定函数,则thisArg将被函数忽略