如何使用 JavaScript 的一些方法
作者:阿卜杜拉·努曼
介绍
本文介绍JavaScript 中的迭代方法。这是“实用 JavaScript 迭代方法”some()系列文章的第二部分。
在这篇文章中,我们将通过示例探讨JavaScript 的 some是什么,它是如何工作的(有和没有)thisArg,并了解从内部修改调用者数组的影响。
我们将深入探讨一些问题,所以让我们从基础知识开始。
我们将介绍以下步骤:
- JavaScript 的 some 方法是什么?
Array.prototype.some()工作原理- JavaScript
some()带thisArg参数 some(callback, thisArg)不支持箭头函数some(callback, thisArg)适用于非箭头函数- 修改调用者数组
JavaScript 的 some 方法是什么?
Array.prototype.some()这是一个 JavaScript 迭代方法,用于检查数组中的任意元素是否满足给定条件。该方法针对一个元素数组调用,并通过回调函数检查条件,并将任何必要的thisArg对象传递给回调函数的执行上下文:
// Method signature
some(callbackFn)
some(callbackFn, thisArg)
第一个参数callbackFn是必需的,第二个参数thisArg是可选的。
callbackFn反过来,它接受三个参数。第一个参数是要遍历到的元素element,它是必需的。第二个参数是当前索引,index第三个参数是array要迭代的数组。第二个和第三个参数都是可选的:
// Method signature
some(function(element){...});
some(function(element, index){...});
some(function(element, index, array){...});
Array.prototype.some()工作原理
JavaScript 中的一些代码会检查是否存在一个元素满足回调函数中设置的条件callbackFn。它会尝试对数组中的每个元素执行一次回调函数。如果找到一个元素的条件为真(true)callbackFn,则返回布尔值 true true。否则,它会遍历数组直到末尾,false如果所有元素的条件都为假(false),则返回 false。
const numbers = [1, 2, 3, 4, 5];
const even = element => element % 2 === 0;
const isThereEvenNumber = numbers.some(even);
console.log(isThereEvenNumber); // true
在上面的代码块中,`failure`even()是我们的回调函数,我们将其传递给 `get() some()`。显然,我们的数组中至少有一个偶数numbers。因此,`get()`some()返回 `nil` true。
JavaScriptsome()带thisArg参数
我们可以将该对象传递thisArg给 JavaScript some(),将其添加到回调函数的执行上下文中。让我们通过修改回调函数来尝试一下。
假设我们不想仅仅检查数字是否为偶数,而是想将回调函数泛化,使其能够检查某个元素是否能被给定的数字整除。我们希望回调函数类似于以下形式:
function divisible(element, divisor) {
return element % divisor === 0;
};
但是,我们不能将divisor作为第二个参数传递给divisible(),因为我们的回调函数分别接受index和array作为第二个和第三个参数。如果我们引入第四个参数,就会显得过于拥挤divisor。
我们可以通过将第二个参数divisor作为对象的属性传递给 `.` 来解决这个问题。然后在回调函数内部使用 `.` 访问该对象:thisArgevery()this
const numbers = [1, 2, 3, 4, 5];
function divisible(element) {
return element % this?.divisor === 0;
};
const isThereEvenNumber = numbers.some(divisible, { divisor: 2 });
console.log(isThereEvenNumber); // true
在这里,我们将thisArg对象设置为{ divisor: 2 },这基本上会导致检查该项是否为偶数。
我们还可以尝试其他除数选项,例如检查是否能被 3 或 7 整除。多亏了thisArg,现在这变得非常简单:
const isThereAnyDivisibleByThree = numbers.some(divisible, { divisor: 3 });
const isThereAnyDivisibleBySeven = numbers.some(divisible, { divisor: 7 });
console.log(isThereAnyDivisibleByThree); // true
console.log(isThereAnyDivisibleBySeven); // false
后端开发人员非常喜欢这个 React 框架!
隆重推出这款基于 React 的无头解决方案,助您构建简洁高效的CRUD应用。有了 refine,您可以确保代码库始终保持整洁,告别冗余代码。
尝试改进以快速构建您的下一个CRUD项目,无论是管理面板、仪表板、内部工具还是店面。
some(callback, thisArg)不支持箭头函数
回顾第一个涉及even()回调函数的例子,我们将其定义为箭头函数。而且它运行正常。
我们定义了它的扩展,divisible()即使用命名声明语法的函数。而且它也运行良好。
如果将其声明divisible()为箭头函数,则会遇到问题:
const divisible = element => element % this?.divisor === 0;
const isThereEvenNumber = numbers.some(divisible, { divisor: 2 });
const isThereAnyDivisibleByThree = numbers.some(divisible, { divisor: 3 });
const isThereAnyDivisibleBySeven = numbers.some(divisible, { divisor: 7 });
console.log(isThereEvenNumber); // false
console.log(isThereAnyDivisibleByThree); // false
console.log(isThereAnyDivisibleBySeven); // false
全部回归false,尽管我们预计其中两人将回归true,一人将回归false。
divisible()如果我们用一个修改后的、会将日志输出this到控制台的函数来调查这个问题,我们会发现它this处于undefined严格模式:
// strict mode
const numbers = [1, 2, 3, 4, 5];
const divisible = element => {
console.log(this);
return element % this?.divisor === 0;
};
const isThereEvenNumber = numbers.some(divisible, { divisor: 2 });
console.log(isThereEvenNumber);
// undefined
// undefined
// undefined
// undefined
// undefined
// false
现在,如果我们this.divisor向词法环境引入一个属性divisible(),它的值就会被记录到控制台:
const numbers = [1, 2, 3, 4, 5];
this.divisor = 'Hi';
const divisible = element => {
console.log(this);
return element % this.divisor === 0;
};
const isThereEvenNumber = numbers.some(divisible, { divisor: 2 });
console.log(isThereEvenNumber);
// { divisor: 'Hi' }
// { divisor: 'Hi' }
// { divisor: 'Hi' }
// { divisor: 'Hi' }
// { divisor: 'Hi' }
// false
显然,这里我们遇到了{ divisor: 'Hi' }来自divisible()闭包的问题。事实证明,问题在于箭头语法导致的divisible()闭包与其词法环境的绑定。在我们引入之前,情况就是这样。现在是。换句话说,} 没有被传递给闭包。thisundefinedthis.divisor = 'Hi';this{ divisor: 'Hi' }{ divisor: 2divisiblethis
因此,some()使用箭头语法定义的 ` with` 函数thisArg无法按预期工作。callbackFn
some(callback, thisArg)适用于非箭头函数
但正如我们之前看到的,它适用于使用命名函数声明定义的回调函数:
function divisible(element) {
return element % this?.divisor === 0;
};
const isThereEvenNumber = numbers.some(divisible, { divisor: 2 });
console.log(isThereEvenNumber); // true
它也适用于匿名函数表达式:
const divisible = function(element) {
return element % this?.divisor === 0;
};
const isThereEvenNumber = numbers.some(divisible, { divisor: 2 });
console.log(isThereEvenNumber); // true
修改调用者数组
JavaScript 中的某个方法会在回调函数第一次调用之前设置要处理的项目的范围。
some()回调函数本身不会修改调用者数组,但调用者会作为第三个参数传递给回调函数array。如果遍历后某个元素发生了变化,回调函数会忽略这种变化。也就是说,回调函数只考虑访问该元素时它所具有的值。
我们可以在调用者数组从内部被修改的场景中看到这一点some()。
JavaScriptsome()本身不会修改调用者数组,但调用者会作为回调函数的第三个参数传递给它array。这意味着我们可以在回调函数内部根据需要修改调用者divisible():
function divisible(element, index, array) {
array[0] = 7;
array[4] = 7;
console.log(array);
return element % this?.divisor === 0;
};
在这种情况下,如果一个未访问过的项事先发生了更改,回调函数(此处divisible())会在访问该项时找到新值并进行处理。相反,它会忽略已访问过的项的更改:
const divisible = function(element, index, array) {
array[0] = 7;
array[4] = 7;
console.log(array);
return element % this?.divisor === 0;
};
const isDivisibleBySeven = numbers.some(divisible, { divisor: 7 });
console.log(isDivisibleBySeven);
console.log(numbers);
/*
[ 7, 2, 3, 4, 7 ]
[ 7, 2, 3, 4, 7 ]
[ 7, 2, 3, 4, 7 ]
[ 7, 2, 3, 4, 7 ]
[ 7, 2, 3, 4, 7 ]
true
[ 7, 2, 3, 4, 7 ]
*/
在上面的控制台日志语句中,由于我们放置在其中的语句,numbers数组被记录了五次。console.log(array);divisible()
正如我们所见,numbers在第一次调用时,被修改了两次divisible()。第一次修改发生在访问之后numbers[0],即在被访问之后,它将自身的值更改为7。因此,即使它可以被除数整除7,some()也没有立即返回true。相反,它true在下一次访问时返回了未被访问且已被修改的在7处的值numbers[4]。
这表明回调函数在遍历过程中处理找到的项的值,并忽略在该索引处及之后对其所做的更改。
结论
本文重点介绍了一种 JavaScript方法,该方法可以帮助我们测试数组中是否至少包含一个符合我们测试条件的元素,我们使用回调函数来实现这一测试。我们看到,回调函数只能接受三个参数,而额外的参数可以通过传递给回调函数的this参数值绑定到其执行上下文中。thisArgsome()
我们还发现,如果使用箭头语法声明回调函数,其词法上下文绑定会干扰thisArg其this对象的绑定。因此,我们应该使用非箭头函数来声明使用回调函数的回调函数this。
