当我们使用let声明变量的时候 我们可以看到for循环的性能要好一些
let arr = new Array(9999999).fill(0);
console.time("FOR");
for (let i = 0; i < arr.length; i++) {}
console.timeEnd("FOR");
console.time("WHILE");
let i = 0;
while (i < arr.length) {
i++;
}
console.timeEnd("WHILE");
但是如果使用var来声明 会发现for循环与while循环差不多
let arr = new Array(9999999).fill(0);
console.time("FOR");
for (var i = 0; i < arr.length; i++) {}
console.timeEnd("FOR");
console.time("WHILE");
var i = 0;
while (i < arr.length) {
i++;
}
console.timeEnd("WHILE");
总结:for循环时自己控制循环过程
基于var声明的时候 for和while性能差不多 (不确定循环次数的情况下使用while)
基于let声明的时候 for循环性能更好 (原理:没有创造全局不释放的变量)
forEach比for的性能差一些
let arr = new Array(9999999).fill(0);
console.time("FOR");
for (var i = 0; i < arr.length; i++) {}
console.timeEnd("FOR");
console.time("WHILE");
var i = 0;
while (i < arr.length) {
i++;
}
console.timeEnd("WHILE");
console.time("FOREACH");
arr.forEach(function () {});
console.timeEnd("FOREACH");
Array.prototype.forEach = function forEach(callback,context){
//this -> arr
let self = this,
i = 0,
len = self.length;
context = context === null ? window : context
for(; i < len ; i++){
typeof callback === 'function' ? callback.call(context,self[i],i) : null
}
}
for in 的性能很差:用来迭代当前对象中所有可枚举的属性的 (私有属性大部分是可枚举的 注意length不可枚举,公有属性【出现在所属类的原型上的】也有部分是可枚举的) 查找机制上一定会搞到原型链上去
let arr = new Array(9999999).fill(0);
console.time("FOR");
for (var i = 0; i < arr.length; i++) {}
console.timeEnd("FOR");
console.time("WHILE");
var i = 0;
while (i < arr.length) {
i++;
}
console.timeEnd("WHILE");
console.time("FOREACH");
arr.forEach(function () {});
console.timeEnd("FOREACH");
console.time("FORIN");
for (let key in arr) {
}
console.timeEnd("FORIN");
//问题一:遍历顺序以数字属性优先 从小到大
//问题二:无法遍历Symbol属性
//问题三:可以遍历到共有中可枚举的属性
Object.prototype.fn = function () {};
let obj = {
name: "gh",
age: 24,
[Symbol("AA")]: 100,
0: 100,
1: 200,
};
for (let key in obj) {
console.log(key);
}
Object.prototype.fn = function () {};
let obj = {
name: "gh",
age: 24,
[Symbol("AA")]: 100,
0: 100,
1: 200,
};
for (let key in obj) {
if (!obj.hasOwnProperty(key)) {
break;
}
console.log(key);
}
Object.prototype.fn = function () {};
let obj = {
name: "gh",
age: 24,
[Symbol("AA")]: 100,
0: 100,
1: 200,
};
let keys = Object.keys(obj);
if (typeof Symbol !== "undefined") keys = keys.concat(Object.getOwnPropertySymbols(obj));
keys.forEach((key) => {
console.log("属性名: ", key);
console.log("属性值: ", obj[key]);
});
for of比forEach差一点
let arr = new Array(9999999).fill(0);
console.time("FOR");
for (var i = 0; i < arr.length; i++) {}
console.timeEnd("FOR");
console.time("WHILE");
var i = 0;
while (i < arr.length) {
i++;
}
console.timeEnd("WHILE");
console.time("FOREACH");
arr.forEach(function () {});
console.timeEnd("FOREACH");
console.time("FORIN");
for (let key in arr) {
}
console.timeEnd("FORIN");
console.time("FOROF");
for (let key of arr) {
}
console.timeEnd("FOROF");
部分数据结构实现了迭代器规范
所有拥有Symbol.iterator就实现了迭代器规范
for of循环的原理:按照迭代器规范遍历的
数组、部分类数组(argument实现了)、set、map【对象没有实现】
实现迭代
arr = [10, 20, 30];
arr[Symbol.iterator] = function () {
let self = this,
index = 0;
return {
//必须具备next方法 每执行一次next方法 拿到结构中的每一项的值
//done:false 没有完成 value:每一项的值
//如果当前的索引大于 数组最大索引就结束
next() {
if (index > self.length - 1) {
return { done: true, value: undefined };
}
return { done: false, value: self[index++] };
},
};
};
让对象具备迭代属性
//类数组对象 【默认不具备迭代器规范】
let obj = {
0: 100,
1: 200,
2: 300,
length: 3,
};
obj[Symbol.iterator] = Array.prototype[Symbol.iterator];
for (let val of obj) {
console.log(val);
}