Javascript call() & apply() vs bind()?

IT技术 javascript arrays function
2021-01-10 15:14:25

我已经知道了,apply并且call是类似的函数,它们设置this(函数的上下文)。

不同之处在于我们发送参数的方式(手动 vs 数组)

问题:

但是我应该什么时候使用该 bind()方法?

var obj = {
  x: 81,
  getX: function() {
    return this.x;
  }
};

alert(obj.getX.bind(obj)());
alert(obj.getX.call(obj));
alert(obj.getX.apply(obj));

jsbin

6个回答

.bind()当您希望稍后使用特定上下文调用该函数时使用,这在事件中很有用。当您想立即调用该函数并修改上下文时使用.call().apply()

Call/apply 立即调用该函数,而bind返回一个函数,该函数在稍后执行时将具有用于调用原始函数的正确上下文集。通过这种方式,您可以在异步回调和事件中维护上下文。

我经常这样做:

function MyObject(element) {
    this.elm = element;

    element.addEventListener('click', this.onClick.bind(this), false);
};

MyObject.prototype.onClick = function(e) {
     var t=this;  //do something with [t]...
    //without bind the context of this function wouldn't be a MyObject
    //instance as you would normally expect.
};

我在 Node.js 中广泛地将它用于异步回调,我想为其传递成员方法,但仍然希望上下文是启动异步操作的实例。

一个简单的 bind 实现如下:

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

它还有更多内容(如传递其他参数),但您可以阅读更多关于它的内容,并在 MDN 上查看真正的实现

您还可以对部分使用 bind,在调用函数之前传入参数。
2021-03-10 15:14:25
您只是重新实现绑定,实际上并没有什么区别。无论哪种方式,您都只是将它包装在一个可以访问保存上下文的范围变量的闭包中。您的代码基本上是我发布的 polyfill。
2021-03-21 15:14:25
@RoyiNamir 编辑了我的答案
2021-03-23 15:14:25
这正是bind返回的内容。
2021-03-31 15:14:25
@RoyiNamir 是正确的,您可以稍后使用返回的“绑定”函数,并且上下文将被维护。
2021-04-06 15:14:25

它们都将this附加到函数(或对象)中,区别在于函数调用(见下文)。

call将此附加到函数中并立即执行该函数:

var person = {  
  name: "James Smith",
  hello: function(thing) {
    console.log(this.name + " says hello " + thing);
  }
}

person.hello("world");  // output: "James Smith says hello world"
person.hello.call({ name: "Jim Smith" }, "world"); // output: "Jim Smith says hello world"

bindthis附加到函数中,它需要像这样单独调用:

var person = {  
  name: "James Smith",
  hello: function(thing) {
    console.log(this.name + " says hello " + thing);
  }
}

person.hello("world");  // output: "James Smith says hello world"
var helloFunc = person.hello.bind({ name: "Jim Smith" });
helloFunc("world");  // output: Jim Smith says hello world"

或者像这样:

...    
var helloFunc = person.hello.bind({ name: "Jim Smith" }, "world");
helloFunc();  // output: Jim Smith says hello world"

applycall类似,不同之处在于它采用一个类似数组的对象,而不是一次列出一个参数:

function personContainer() {
  var person = {  
     name: "James Smith",
     hello: function() {
       console.log(this.name + " says hello " + arguments[1]);
     }
  }
  person.hello.apply(person, arguments);
}
personContainer("world", "mars"); // output: "James Smith says hello mars", note: arguments[0] = "world" , arguments[1] = "mars"                                     
这是否意味着区别在于 Bind 是一个闭包?
2021-03-10 15:14:25
感谢您的改进建议。我稍微编辑了我的答案。@iono 您的建议有一些不准确之处,因此无法批准,但在答案中进行了我自己的编辑。希望它现在更全面。
2021-03-23 15:14:25
@Max 同意;我已经提交了一个编辑,其中“这个”是错误的或在我们使用绑定/调用/应用之前没有意义
2021-03-30 15:14:25
您刚刚通过代码片段教会了我在函数内部使用的参数功能。建议提及"use strict"避免覆盖此类保留关键字。+1。
2021-04-05 15:14:25

以最简单的形式回答

  • Call调用该函数并允许您一一传递参数。
  • Apply调用该函数并允许您将参数作为数组传递。
  • Bind返回一个新函数,允许你传入一个 this 数组和任意数量的参数。

应用与调用与绑定示例

称呼

var person1 = {firstName: 'Jon', lastName: 'Kuperman'};
var person2 = {firstName: 'Kelly', lastName: 'King'};

function say(greeting) {
    console.log(greeting + ' ' + this.firstName + ' ' + this.lastName);
}

say.call(person1, 'Hello'); // Hello Jon Kuperman
say.call(person2, 'Hello'); // Hello Kelly King

申请

var person1 = {firstName: 'Jon', lastName: 'Kuperman'};
var person2 = {firstName: 'Kelly', lastName: 'King'};

function say(greeting) {
    console.log(greeting + ' ' + this.firstName + ' ' + this.lastName);
}

say.apply(person1, ['Hello']); // Hello Jon Kuperman
say.apply(person2, ['Hello']); // Hello Kelly King

绑定

var person1 = {firstName: 'Jon', lastName: 'Kuperman'};
var person2 = {firstName: 'Kelly', lastName: 'King'};

function say() {
    console.log('Hello ' + this.firstName + ' ' + this.lastName);
}

var sayHelloJon = say.bind(person1);
var sayHelloKelly = say.bind(person2);

sayHelloJon(); // Hello Jon Kuperman
sayHelloKelly(); // Hello Kelly King

何时使用

Call 和 apply 可以互换。只需决定是否更容易发送数组或逗号分隔的参数列表。

通过记住 Call 用于逗号(分隔列表)和 Apply 用于数组,我总是记得哪个是哪个。

绑定有点不同。它返回一个新函数。Call 和 Apply 立即执行当前函数。

Bind 对很多事情都很有用。我们可以用它来柯里化上面例子中的函数。我们可以将一个简单的 hello 函数转换为 helloJon 或 helloKelly。我们还可以将它用于 onClick 之类的事件,我们不知道它们何时会被触发,但我们知道我们希望它们具有什么上下文。

参考:codeplanet.io

calland 中apply,如果您this在方法内部没有 a ,那么您是否会将第一个参数分配为 a null
2021-03-13 15:14:25
调用 == 逗号,应用 == 数组是一个不错的小记忆技巧
2021-03-26 15:14:25
var person1 = {firstName: 'Jon', lastName: 'Kuperman'}; function say(greeting) { console.log(greeting + ' ' + this.firstName + ' ' + this.lastName); } say.apply(person1, ['Hello']); // Hello Jon Kuperman 工作正常并输出 VM128:4 Hello Jon Kuperman
2021-03-27 15:14:25
@DaryllSantos,根据 MDN:thisArg 可选。为调用函数提供的 this 值。请注意,这可能不是方法看到的实际值:如果方法是非严格模式下的函数,则 null 和 undefined 将替换为全局对象,原始值将转换为对象。所以如果你不在函数中使用它也没关系。
2021-04-03 15:14:25

我创建函数对象,函数调用之间的比较call/applybind前一段时间:

在此处输入图片说明

.bind允许您现在设置this值,同时允许您将来执行该函数,因为它返回一个新的函数对象。

特尔;博士:

简单来说,bind 创建函数,调用和应用执行函数,而应用需要数组中的参数

完整说明

假设我们有multiplication函数

function multiplication(a,b){
console.log(a*b);
}

让我们创建一些标准函数使用 bind

var multiby2 = multiplication.bind(this,2);

现在 multiby2(b) 等于 multiplication(2,b);

multiby2(3); //6
multiby2(4); //8

如果我在绑定中传递两个参数怎么办

var getSixAlways = multiplication.bind(this,3,2);

现在 getSixAlways() 等于 multiplication(3,2);

getSixAlways();//6

即使传递参数返回6; getSixAlways(12); //6

var magicMultiplication = multiplication.bind(this);

这将创建一个新的乘法函数并将其分配给 magicMultiplication。

哦不,我们将乘法功能隐藏在 magicMultiplication 中。

调用 magicMultiplication返回空白function b()

在执行时它工作正常 magicMultiplication(6,5); //30

打电话申请怎么样?

magicMultiplication.call(this,3,2); //6

magicMultiplication.apply(this,[5,2]); //10

很好的解释了!
2021-03-19 15:14:25
什么是函数 b,为什么它是空白的?
2021-03-21 15:14:25
+1 表示“简而言之,bind创建函数callapply执行函数,而apply期望数组中的参数”
2021-03-23 15:14:25
@DavidSpector,它不是功能 b。这是一个函数,它接受一个名为 'b' 的参数,因为函数“乘法”是如何使用 'a' 和 'b' 作为参数定义的。希望有帮助!
2021-03-31 15:14:25