繁体   English   中英

在 Javascript 中绑定已绑定函数的更多参数

[英]Bind more arguments of an already bound function in Javascript

我尝试整理我对 javascript 的 bind() 工作原理的想法。

我明白如果我这样做

var f = function (a) { ... }
var g = f.bind(obj);
g(1)

然后 f 以obj作为this1作为a被调用。

我认为 g 是 f 的包装函数。

但是当我这样做

var f = function (a) { ... }
var g = f.bind(obj);
g.call(1)

则f被调用, 1作为thisa不确定的。

所以看起来 g 不仅仅是一个简单的包装器,而是call以某种方式区分普通函数和绑定函数。

还有一件事是我不能多次部分应用一个函数。

var f = function (a) { ... }
var g = f.bind(obj);
var h = g.bind(1);
h();

然后用obj作为thisa undefined 调用 f。

这种行为的原因是什么?

编辑

这个问题中的构造实际上是错误的,请参阅关于它们应该是什么样子的公认答案(通常我没有注意到callbind确实总是需要上下文参数作为第一个参数)。

将对象绑定到具有bind的函数后,就无法覆盖它。 正如你在MDN文档中看到的那样,它清楚地写在规范中:

“bind()函数创建一个新函数(一个绑定函数),它具有相同的函数体(ECMAScript 5术语中的内部调用属性)作为调用它的函数(绑定函数的目标函数),并将此值绑定到bind()的第一个参数, 它不能被覆盖。

这意味着,如果你这样做:

g.call(1);

你会得到objthis ,而不是1 -上的以下规格的浏览器。

你当然可以绑定多个参数,所以:

var sum = function(a, b, c) { return a + b + c };
var sumAB = sum.bind(null, 1, 5);
var sumC = sumAB.bind(null, 2);

console.log(sumC());

但是上下文对象将始终是第一个bind指定的对象,因为它不能被覆盖。

为了避免混淆, 调用的第一个参数是上下文对象( this ),然后你将得到其余的参数。

它的意思是:

var obj = { foo: function(bar) { console.log(bar) } };

obj.foo('hello');

// equivalent to:
var foo = obj.foo;

foo.call(obj, 'hello');

希望能帮助到你。

你从未传递任何论据 - 你只设置了上下文。 call的第一个参数作为context( this )被接收,而参数2以后作为被调用函数的参数1和之后被接收。 同时, bind使用新的上下文创建一个新函数 - 在调用时传递参数。

以下是从第一个代码块传递1作为函数f的参数a

f( 1 );
g( 1 );
g.call( this, 1 );
g.apply( this, [ 1 ] );

函数.prototype.call()

使用 call() 方法,您可以编写可用于不同对象的方法。 换句话说,通过 call(),一个对象可以使用属于另一个对象的方法。 更多信息

 const person = { fullName: function() { return this.firstName + " " + this.lastName; } } const person1 = { firstName:"John", lastName: "Doe" } const person2 = { firstName:"Mary", lastName: "Doe" } // This will return "John Doe": console.log(person.fullName.call(person1));

call() 允许为一个不同的对象分配和调用属于一个对象的函数/方法。

call() 为函数/方法提供了一个新的 this 值。 使用 call(),您可以编写一次方法,然后在另一个对象中继承它,而不必为新对象重写该方法。

> 使用链式构造函数调用对象

您可以使用调用来链接对象的构造函数(类似于 Java)。

在以下示例中,Product 对象的构造函数使用两个参数定义:名称和价格。

另外两个函数 Food 和 Toy 调用 Product,传递 this、name 和 price。 Product 初始化属性 name 和 price,这两个专门的函数定义了类别。

 function Product(name, price) { this.name = name; this.price = price; } function Food(name, price) { Product.call(this, name, price); this.category = 'food'; } function Toy(name, price) { Product.call(this, name, price); this.category = 'toy'; } const cheese = new Food('feta', 5); const fun = new Toy('robot', 40); console.log(cheese); console.log(fun);

> 使用 call 调用匿名函数

在这个例子中,我们创建了一个匿名函数并使用 call 在数组中的每个对象上调用它。

这里匿名函数的主要目的是为每个对象添加一个打印函数,能够打印出数组中对象的正确索引。

 const animals = [ { species: 'Lion', name: 'King' }, { species: 'Whale', name: 'Fail' } ]; for (let i = 0; i < animals.length; i++) { (function(i) { this.print = function() { console.log('#' + i + ' ' + this.species + ': ' + this.name); } this.print(); }).call(animals[i], i); }

> 使用 call 调用函数并指定“this”的上下文

在下面的例子中,当我们调用 greet 时,this 的值将绑定到对象 obj。

 function greet() { const reply = [this.animal, 'typically sleep between', this.sleepDuration].join(' '); console.log(reply); } const obj = { animal: 'cats', sleepDuration: '12 and 16 hours' }; greet.call(obj); // cats typically sleep between 12 and 16 hours

> 使用 call 来调用函数而不指定第一个参数

在下面的示例中,我们调用 display 函数而不传递第一个参数。 如果未传递第一个参数,则 this 的值绑定到全局对象。

 var sData = 'Wisen'; function display() { console.log('sData value is %s ', this.sData); } display.call(); // sData value is Wisen

注意:在严格模式下, this 的值将是未定义的。 见下文。

 'use strict'; var sData = 'Wisen'; function display() { console.log('sData value is %s ', this.sData); } display.call(); // Cannot read the property of 'sData' of undefined

如需更多阅读,您可以访问参考

函数.prototype.bind()

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

 const module = { x: 42, getX: function() { return this.x; } }; const unboundGetX = module.getX; console.log(unboundGetX()); // The function gets invoked at the global scope // expected output: undefined const boundGetX = unboundGetX.bind(module); console.log(boundGetX()); // expected output: 42

> 创建绑定函数

bind() 的最简单用途是创建一个函数,无论它如何调用,都会使用特定的 this 值调用。

JavaScript 新手的一个常见错误是从对象中提取方法,然后稍后调用该函数并期望它使用原始对象作为其 this(例如,通过在基于回调的代码中使用该方法)。

然而,如果没有特别注意,原始对象通常会丢失。 从函数创建绑定函数,使用原始对象,巧妙地解决了这个问题:

 this.x = 9; // 'this' refers to global 'window' object here in a browser const module = { x: 81, getX: function() { return this.x; } }; module.getX(); // returns 81 const retrieveX = module.getX; retrieveX(); // returns 9; the function gets invoked at the global scope // Create a new function with 'this' bound to module // New programmers might confuse the // global variable 'x' with module's property 'x' const boundGetX = retrieveX.bind(module); console.log(boundGetX()); // returns 81

> 部分应用功能

bind() 的下一个最简单的用法是使用预先指定的初始参数创建一个函数。

这些参数(如果有)跟在提供的 this 值之后,然后插入到传递给目标函数的参数的开头,然后是在调用时传递给绑定函数的任何参数。

 function list() { return Array.prototype.slice.call(arguments); } function addArguments(arg1, arg2) { return arg1 + arg2; } const list1 = list(1, 2, 3); // [1, 2, 3] const result1 = addArguments(1, 2); // 3 // Create a function with a preset leading argument const leadingThirtysevenList = list.bind(null, 37); // Create a function with a preset first argument. const addThirtySeven = addArguments.bind(null, 37); const list2 = leadingThirtysevenList(); // [37] const list3 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3] const result2 = addThirtySeven(5); // 37 + 5 = 42 const result3 = addThirtySeven(5, 10); // 37 + 5 = 42 // (the second argument is ignored)

> 使用 setTimeout()

默认情况下,在 setTimeout() 中, this 关键字将设置为窗口(或全局)对象。 当使用需要 this 来引用类实例的类方法时,您可以将 this 显式绑定到回调函数,以维护实例。

 function LateBloomer() { this.petalCount = Math.floor(Math.random() * 12) + 1; } // Declare bloom after a delay of 1 second LateBloomer.prototype.bloom = function() { window.setTimeout(this.declare.bind(this), 1000); }; LateBloomer.prototype.declare = function() { console.log(`I am a beautiful flower with ${this.petalCount} petals!`); }; const flower = new LateBloomer(); flower.bloom(); // after 1 second, calls 'flower.declare()'

如果您想了解有关绑定方法的更多信息,请阅读此资源

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM