call() 方法中的上下文如何工作
How context in the call() method works
对于重新创建 Underscore.js 的一系列练习,我试图了解 call() 方法在幕后是如何工作的。
我确实理解 call() 方法在下面的示例中是如何工作的。
let person = {
firstName:"John",
lastName: "Doe",
fullName: function() {
return this.firstName + " " + this.lastName;
}
}
let myObject = {
firstName:"Mary",
lastName: "Doe",
}
person.fullName.call(myObject); // Will return "Mary Doe"
但是,我很难理解 iteratee.call(context, collection[i], i, collection)
中上下文的概念。
这是我正在做的练习:
// _.each(collection, iteratee, [context])
// Iterates over a collection of elements (i.e. array or object),
// yielding each in turn to an iteratee function, that is called with three arguments:
// (element, index|key, collection;), and bound to the context if one is passed.
// Returns the collection for chaining.
_.each = function (collection, iteratee, context) {
if (Array.isArray(collection)) {
for (let i = 0; i < collection.length; i++) {
iteratee.call(context, collection[i], i, collection);
}
} else if (collection !== null) {
Object.entries(collection).map(([key, value]) => {
iteratee.call(context, value, key, collection);
});
}
return collection;
};
在此先感谢您的帮助。
很多年前,通常使用“上下文”一词来指代 this
在函数调用期间应该具有的值。 (这不是一个好术语,已经失宠了。)_.each
定义正在做的是接受一个可选参数 context
,并使用它来设置调用时 this
是什么传入的 iteratee
函数使得 iteratee
调用中的 this
是 context
的任何内容。 (如果未提供 context
,它将是 undefined
,并且 iteratee
中的 this
将是 undefined
[在严格模式下] 或全局对象[松散模式].)
例如,假设您有一个带有方法的对象,并且您想要使用 _.each
为数组中的每个条目调用该方法。你可以这样做:
const obj = {
id: "some ID",
method(value) {
console.log(`this.id = ${this.id}, value = ${value}`);
}
};
_.each([1, 2, 3], obj.method, obj);
实例:
"use strict";
const _ = {};
_.each = function (collection, iteratee, context) {
if (Array.isArray(collection)) {
for (let i = 0; i < collection.length; i++) {
iteratee.call(context, collection[i], i, collection);
}
} else if (collection !== null) {
Object.entries(collection).map(([key, value]) => {
iteratee.call(context, value, key, collection);
});
}
return collection;
};
const obj = {
id: "some ID",
method(value) {
console.log(`this.id = ${this.id}, value = ${value}`);
}
};
_.each([1, 2, 3], obj.method, obj);
如果您没有提供 obj
作为第三个参数,obj.method
中的 this.id
将无法正常工作,因为 this
不会是 obj
,它将是 undefined
(严格模式)或全局对象。例如(严格模式):
"use strict";
const _ = {};
_.each = function (collection, iteratee, context) {
if (Array.isArray(collection)) {
for (let i = 0; i < collection.length; i++) {
iteratee.call(context, collection[i], i, collection);
}
} else if (collection !== null) {
Object.entries(collection).map(([key, value]) => {
iteratee.call(context, value, key, collection);
});
}
return collection;
};
const obj = {
id: "some ID",
method(value) {
console.log(`this.id = ${this.id}, value = ${value}`);
}
};
_.each([1, 2, 3], obj.method); // <== Note no third argument
内置数组方法 forEach
也有此参数(称为 thisArg
),许多其他内置数组方法也是如此。
但是现在,在我看来,使用包装箭头函数更常见:
_.each([1, 2, 3], value => obj.method(value));
你可以把this
看成是所有函数的隐式参数。为了说明,以下函数将抛出错误,因为没有声明变量 banana
:
function fruit() {
console.log(banana);
}
fruit();
但下面的函数没问题,因为 this
是一个隐式声明的参数:
'use strict';
function fruit() {
console.log(this);
}
fruit();
您不能将 this
作为参数直接传递,因为那样您将不得不重新声明名称:
function broken(this) {
console.log(this.name);
}
broken({name: 'Ann'});
将 this
参数传递给函数的唯一有效方法是将其作为方法调用,或者使用 call
或 apply
:
// the following lines are equivalent
anObject.aMethod(argument1, argument2);
aMethod.call(anObject, argument1, argument2);
aMethod.apply(anObject, [argument1, argument2]);
在所有情况下,aMethod
都会将 anObject
视为其 this
参数。但是,第一种情况仅在 aMethod
是 anObject
的 属性 时有效,而其他情况始终有效。 call
和 apply
之间的唯一区别是后者在单个数组中接受 this
之后的所有参数。
现在开始让您感到困惑的那一行:
iteratee.call(context, collection[i], i, collection)
iteratee
只是任何函数,context
只是一个变量,将作为其隐式 this
参数提供。 context
变量可以有任何其他名称,例如 thisArg
或 object
.
对于重新创建 Underscore.js 的一系列练习,我试图了解 call() 方法在幕后是如何工作的。
我确实理解 call() 方法在下面的示例中是如何工作的。
let person = {
firstName:"John",
lastName: "Doe",
fullName: function() {
return this.firstName + " " + this.lastName;
}
}
let myObject = {
firstName:"Mary",
lastName: "Doe",
}
person.fullName.call(myObject); // Will return "Mary Doe"
但是,我很难理解 iteratee.call(context, collection[i], i, collection)
中上下文的概念。
这是我正在做的练习:
// _.each(collection, iteratee, [context])
// Iterates over a collection of elements (i.e. array or object),
// yielding each in turn to an iteratee function, that is called with three arguments:
// (element, index|key, collection;), and bound to the context if one is passed.
// Returns the collection for chaining.
_.each = function (collection, iteratee, context) {
if (Array.isArray(collection)) {
for (let i = 0; i < collection.length; i++) {
iteratee.call(context, collection[i], i, collection);
}
} else if (collection !== null) {
Object.entries(collection).map(([key, value]) => {
iteratee.call(context, value, key, collection);
});
}
return collection;
};
在此先感谢您的帮助。
很多年前,通常使用“上下文”一词来指代 this
在函数调用期间应该具有的值。 (这不是一个好术语,已经失宠了。)_.each
定义正在做的是接受一个可选参数 context
,并使用它来设置调用时 this
是什么传入的 iteratee
函数使得 iteratee
调用中的 this
是 context
的任何内容。 (如果未提供 context
,它将是 undefined
,并且 iteratee
中的 this
将是 undefined
[在严格模式下] 或全局对象[松散模式].)
例如,假设您有一个带有方法的对象,并且您想要使用 _.each
为数组中的每个条目调用该方法。你可以这样做:
const obj = {
id: "some ID",
method(value) {
console.log(`this.id = ${this.id}, value = ${value}`);
}
};
_.each([1, 2, 3], obj.method, obj);
实例:
"use strict";
const _ = {};
_.each = function (collection, iteratee, context) {
if (Array.isArray(collection)) {
for (let i = 0; i < collection.length; i++) {
iteratee.call(context, collection[i], i, collection);
}
} else if (collection !== null) {
Object.entries(collection).map(([key, value]) => {
iteratee.call(context, value, key, collection);
});
}
return collection;
};
const obj = {
id: "some ID",
method(value) {
console.log(`this.id = ${this.id}, value = ${value}`);
}
};
_.each([1, 2, 3], obj.method, obj);
如果您没有提供 obj
作为第三个参数,obj.method
中的 this.id
将无法正常工作,因为 this
不会是 obj
,它将是 undefined
(严格模式)或全局对象。例如(严格模式):
"use strict";
const _ = {};
_.each = function (collection, iteratee, context) {
if (Array.isArray(collection)) {
for (let i = 0; i < collection.length; i++) {
iteratee.call(context, collection[i], i, collection);
}
} else if (collection !== null) {
Object.entries(collection).map(([key, value]) => {
iteratee.call(context, value, key, collection);
});
}
return collection;
};
const obj = {
id: "some ID",
method(value) {
console.log(`this.id = ${this.id}, value = ${value}`);
}
};
_.each([1, 2, 3], obj.method); // <== Note no third argument
内置数组方法 forEach
也有此参数(称为 thisArg
),许多其他内置数组方法也是如此。
但是现在,在我看来,使用包装箭头函数更常见:
_.each([1, 2, 3], value => obj.method(value));
你可以把this
看成是所有函数的隐式参数。为了说明,以下函数将抛出错误,因为没有声明变量 banana
:
function fruit() {
console.log(banana);
}
fruit();
但下面的函数没问题,因为 this
是一个隐式声明的参数:
'use strict';
function fruit() {
console.log(this);
}
fruit();
您不能将 this
作为参数直接传递,因为那样您将不得不重新声明名称:
function broken(this) {
console.log(this.name);
}
broken({name: 'Ann'});
将 this
参数传递给函数的唯一有效方法是将其作为方法调用,或者使用 call
或 apply
:
// the following lines are equivalent
anObject.aMethod(argument1, argument2);
aMethod.call(anObject, argument1, argument2);
aMethod.apply(anObject, [argument1, argument2]);
在所有情况下,aMethod
都会将 anObject
视为其 this
参数。但是,第一种情况仅在 aMethod
是 anObject
的 属性 时有效,而其他情况始终有效。 call
和 apply
之间的唯一区别是后者在单个数组中接受 this
之后的所有参数。
现在开始让您感到困惑的那一行:
iteratee.call(context, collection[i], i, collection)
iteratee
只是任何函数,context
只是一个变量,将作为其隐式 this
参数提供。 context
变量可以有任何其他名称,例如 thisArg
或 object
.