js中的for循环
for循环经常使⽤,js常⽤有4中for循环, 普通 for(表达式1;表达式2;表达式3),for( i in obj),for (item of
obj),foreach(callback(val,index,arr),thisArg )
for
for 语句⽤于创建⼀个循环,它包含了三个可选的表达式,这三个表达式被包围在圆括号之中,使⽤分号分隔,后跟⼀个⽤于在循环中执⾏的语句(通常是⼀个块语句)。
let str ='';
for(let i =0; i <9; i++){
str = str + i;
}
console.log(str);
// expected output: "012345678"
语法
for ([initialization]; [condition]; [final-expression])
statement
initialization
⼀个表达式 (包含赋值语句) 或者变量声明。典型地被⽤于初始化⼀个计数器。该表达式可以使⽤ var 或 let 关键字声明新的变量,使⽤ var 声明的变量不是该循环的局部变量,⽽是与 for 循环处在同样的作⽤域中。⽤ let 声明的变量是语句的局部变量。该表达式的结果⽆意义。
condition
⼀个条件表达式被⽤于确定每⼀次循环是否能被执⾏。如果该表达式的结果为 true,statement 将被执⾏。这个表达式是可选的。如果被忽略,那么就被认为永远为真。如果计算结果为假,那么执⾏流程将被跳到 for 语句结构后⾯的第⼀条语句。
final-expression
每次循环的最后都要执⾏的表达式。执⾏时机是在下⼀次 condition 的计算之前。通常被⽤于更新或者递增计数器变量。
statement
只要condition的结果为true就会被执⾏的语句。要在循环体内执⾏多条语句,使⽤⼀个块语句({ … })来包含要执⾏的语句。没有任何语句要执⾏,使⽤⼀个空语句(;)。
; 不能少
for…of
for…of语句在可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等等)上创建⼀个迭代循环,调⽤⾃定义迭代钩⼦,并为每个不同属性的值执⾏语句
const array1 =['a','b','c'];
for(const element of array1){
console.log(element);
}
语法
for (variable of iterable) {
//statements
}
variable
在每次迭代中,将不同属性的值分配给变量。
iterable
被迭代枚举其属性的对象。
for…in
for…in语句以任意顺序遍历⼀个对象的除Symbol以外的可枚举属性。
var obj ={a:1, b:2, c:3};
for(var prop in obj){
console.log("obj."+ prop +" = "+ obj[prop]);
}
// Output:
// "obj.a = 1"
// "obj.b = 2"
// "obj.c = 3"
语法
for (variable in object)
statement
variable
在每次迭代时,variable会被赋值为不同的属性名。
object
⾮Symbol类型的可枚举属性被迭代的对象。
仅迭代⾃⾝的属性
如果你只要考虑对象本⾝的属性,⽽不是它的原型,那么使⽤ getOwnPropertyNames() 或执⾏ hasOwnProperty() 来确定某属性是否是对象本⾝的属性(也能使⽤propertyIsEnumerable)。或者,如果你知道不会有任何外部代码⼲扰,您可以使⽤检查⽅法扩展内置原型。
for … in是为遍历对象属性⽽构建的,不建议与数组⼀起使⽤,数组可以⽤。
它最常⽤的地⽅应该是⽤于调试,可以更⽅便的去检查对象属性(通过输出到控制台或其他⽅式)。尽管对于处理存储数据,数组更实⽤些,但是你在处理有key-value数据(⽐如属性⽤作“键”),需要检查其中的任何键是否为某值的情况时,还是推荐⽤for … in。
forEach()
forEach() ⽅法对数组的每个元素执⾏⼀次给定的函数。返回⼀个回调函数
语法
arr.forEach(callback(currentValue [, index [, array]])[, thisArg])
参数
callback
为数组中每个元素执⾏的函数,该函数接收⼀⾄三个参数:
currentValue
数组中正在处理的当前元素。
index 可选
数组中正在处理的当前元素的索引。
array 可选
forEach() ⽅法正在操作的数组。
thisArg 可选
可选参数。当执⾏回调函数 callback 时,⽤作 this 的值。
返回值
undefined。
描述
forEach() ⽅法按升序为数组中含有效值的每⼀项执⾏⼀次 callback 函数,那些已删除或者未初始化的项将被跳过(例如在稀疏数组上)。
可依次向 callback 函数传⼊三个参数:
数组当前项的值
数组当前项的索引
数组对象本⾝
如果 thisArg 参数有值,则每次 callback 函数被调⽤时,this 都会指向 thisArg 参数。如果省略了 thisArg 参数,或者其值为 null 或undefined,this 则指向全局对象。按照函数观察到 this 的常⽤规则,callback 函数最终可观察到 this 值。
forEach() 遍历的范围在第⼀次调⽤ callback 前就会确定。调⽤ forEach 后添加到数组中的项不会被 callback 访问到。如果已经存在的值被改变,则传递给 callback 的值是 forEach() 遍历到他们那⼀刻的值。已删除的项不会被遍历到。如果已访问的元素在迭代时被删除了(例如使⽤ shift()),之后的元素将被跳过——参见下⾯的⽰例。
forEach() 为每个数组元素执⾏⼀次 callback 函数;与 map() 或者 reduce() 不同的是,它总是返回 undefined 值,并且不可链式调⽤。其典型⽤例是在⼀个调⽤链的最后执⾏副作⽤(side effects,函数式编程上,指函数进⾏ 返回结果值 以外的操作)。
forEach() 被调⽤时,不会改变原数组,也就是调⽤它的数组(尽管 callback 函数在被调⽤时可能会改变原数组)。(译注:此处说法可能不够明确,具体可参考EMCA语⾔规范:‘forEach does not directly mutate the object on which it is called but the object may be mutated by the calls to callbackfn.’,即 forEach 不会直接改变调⽤它的对象,但是那个对象可能会被 callback 函数改变。)
注意: 除了抛出异常以外,没有办法中⽌或跳出 forEach() 循环。如果你需要中⽌或跳出循环,forEa
ch() ⽅法不是应当使⽤的⼯具。
若你需要提前终⽌循环,你可以使⽤:
⼀个简单的 for 循环
for…of / for…in 循环
Array.prototype.every()
Array.prototype.some()
Array.prototype.find()
Array.prototype.findIndex()
这些数组⽅法则可以对数组元素判断,以便确定是否需要继续遍历:
every()
some()
find()
findIndex()
译者注:只要条件允许,也可以使⽤ filter() 提前过滤出需要遍历的部分,再⽤ forEach() 处理。
⽰例
//不对未初始化的值进⾏任何操作(稀疏数组)
//如你所见,3 和 7 之间空缺的数组单元未被 forEach() 调⽤ callback 函数,或进⾏任何其他操作。
const arraySparse =[1,3,,7];
let numCallbackRuns =0;
arraySparse.forEach(function(element){
console.log(element);
numCallbackRuns++;
js arguments});
console.log("numCallbackRuns: ", numCallbackRuns);
// 1
// 3
// 7
// numCallbackRuns: 3
Copy to Clipboard
将for循环转换为 forEach
const items =['item1','item2','item3'];
const copy =[];
// before
for(let i=0; i<items.length; i++){
copy.push(items[i]);
}
}
// after
items.forEach(function(item){
copy.push(item);
});
Copy to Clipboard
//打印出数组的内容
//注意:为了在控制台中显⽰数组的内容,你可以使⽤ console.table() 来展⽰经过格式化的数组。下⾯的例⼦则是另⼀种使⽤ forEach() 的格式化的⽅法。
下⾯的代码会为每⼀个数组元素输出⼀⾏记录:
function logArrayElements(element, index, array){
console.log('a['+ index +'] = '+ element);
}
// 注意索引 2 被跳过了,因为在数组的这个位置没有项
[2,5,,9].forEach(logArrayElements);
// logs:
// a[0] = 2
// a[1] = 5
// a[3] = 9
//Copy to Clipboard
/
/使⽤ thisArg
//举个勉强的例⼦,按照每个数组中的元素值,更新⼀个对象的属性:
function Counter(){
this.sum =0;
}
Counter.prototype.add=function(array){
array.forEach(function(entry){
this.sum += entry;
++unt;
},this);
/
/ ^---- Note
};
const obj =new Counter();
obj.add([2,5,9]);
// 3 === (1 + 1 + 1)
obj.sum;
// 16 === (2 + 5 + 9)
//Copy to Clipboard
//因为 thisArg 参数(this)传给了 forEach(),每次调⽤时,它都被传给 callback 函数,作为它的 this 值。
/
/注意:如果使⽤箭头函数表达式来传⼊函数参数, thisArg 参数会被忽略,因为箭头函数在词法上绑定了 this 值。
//对象复制器函数
//下⾯的代码会创建⼀个给定对象的副本。创建对象的副本有不同的⽅法,以下是只是⼀种⽅法,并解释了 Array.prototype.forEach() 是如何使⽤ ECMAScript 5 Object.* 元属性(meta property)函数⼯作的。
function copy(obj){
const copy = PrototypeOf(obj));
const propNames = OwnPropertyNames(obj);
propNames.forEach(function(name){
const desc = OwnPropertyDescriptor(obj, name);
Object.defineProperty(copy, name, desc);
});
return copy;
}
const obj1 ={ a:1, b:2};
const obj2 =copy(obj1);// 现在 obj2 看起来和 obj1 ⼀模⼀样了
const obj2 =copy(obj1);// 现在 obj2 看起来和 obj1 ⼀模⼀样了
//Copy to Clipboard
//如果数组在迭代时被修改了,则其他元素会被跳过。
//下⾯的例⼦会输出 "one", "two", "four"。当到达包含值 "two" 的项时,整个数组的第⼀个项被移除了,这导致所有剩下的项上移⼀个位置。因为元素 "four" 正位于在数组更前的位置,所以 "three" 会被跳过。 forEach() 不会在迭代之前创建数组的副本。
var words =['one','two','three','four'];
words.forEach(function(word){
console.log(word);
if(word ==='two'){
words.shift();
}
});
// one
// two
// four
//Copy to Clipboard
//扁平化数组
/
/下⾯的⽰例仅⽤于学习⽬的。如果你想使⽤内置⽅法来扁平化数组,你可以考虑使⽤ Array.prototype.flat()(预计将成为 ES2019 的⼀部分,并且已在主要浏览器中实现)或参考其 polyfill。
/**
* Flattens passed array in one dimensional array
*
* @params {array} arr
* @returns {array}
*/
function flatten(arr){
const result =[];
arr.forEach((i)=>{
if(Array.isArray(i))
result.push(...flatten(i));
else
result.push(i);
})
return result;
}
// Usage
const problem =[1,2,3,[4,5,[6,7],8,9]];
flatten(problem);// [1, 2, 3, 4, 5, 6, 7, 8, 9]
//Copy to Clipboard
/
/针对 promise 或 async 函数的使⽤备注
//如果使⽤ promise 或 async 函数作为 forEach() 等类似⽅法的 callback 参数,最好对造成的执⾏顺序影响多加考虑,否则容易出现错误。
let ratings =[5,4,5];
let sum =0;
let sumFunction=async function(a, b){
return a + b;
}
ratings.forEach(async function(rating){
sum =await sumFunction(sum, rating);
})
console.log(sum);
// Expected output: 14
// Actual output: 0
//Copy to Clipboard
//Polyfill
forEach()// 是在第五版本⾥被添加到 ECMA-262 标准的;这样它可能在标准的其他实现中不存在,你可以在你调⽤ forEach() 之前插⼊下⾯的代码,在本地不⽀持的情况下使⽤ forEach()。该算法是 ECMA-262 第5版中指定的算法。它假定 Object 和 TypeError 拥有它们的初始值,且 callback.call 等价于 Function.pr ototype.call()。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。