for循环及forEach底层原理
FOR循环是自己控制循环过程
-
基于var声明的时候,FOR和WHILE性能差不多「不确定循环次数的情况下使用WHILE」
-
基于let声明的时候,FOR循环性能更好「原理:没有创造全局不释放的变量」
-
for和while循环叫做命令式编程,数组的foreach/fiflter/some/every/等叫做函数式编程,是被别人封装好了的。
-
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 声明了全局变量,占用内存空间 while (i < arr.length) { i++; } console.timeEnd('WHILE~~');
-
Array.prototype.forEach()MDN上Array.prototype.forEach()的详解
forEach()
方法对数组的每个元素执行一次给定的函数。
console.time('FOREACH~~');
arr.forEach(function (item) {});
//arr.forEach((item)=>{console.log(item);})
console.timeEnd('FOREACH~~');
- 手写forEach(callback,thisArg)
Array.prototype.forEach = function forEach(callback, context) {
// this -> arr
let self = this,
i = 0,
len = self.length;
// 不传context this就是window。
// 利用call(),指定callback的this、给callback传参。
context = context == null ? window : context;
for (; i < len; i++) {
typeof callback === "function" ? callback.call(context, self[i], i) : null;
}
};
- forEach看它的底层机制,可以知道它比for循环和while循环的性能要差
for in循环的BUG及解决方案
-
for in性能很差:迭代当前对象中所有可枚举的属性
-
迭代所有可枚举属性「私有&公有」,按照原型链一级级查找很耗性能
-
问题很多:1、不能迭代Symbol属性;2、迭代顺序会以数字属性优先;3、公有可枚举的{一般是自定义属性}属性也会进行迭代。
-
利用hasOwnProperty()的用法:继承的属性(公有属性)不显示。
-
利用 getOwnPropertySymbols()方法获取数组的Symbol值,用concat()方法合并数组。
ES5 引入了Object.keys方法,成员是参数对象自身的(不含继承的)所有可遍历属性的键名。 -
let obj = { name: 'zhufeng', age: 12, [Symbol('AA')]: 100, 0: 200, 1: 300 }; for (let key in obj) { if (!obj.hasOwnProperty(key)) break; console.log(key); } 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循环的底层机制
- for of循环的原理是按照迭代器规范 (Symbol.iterator) 遍历的 迭代器协议
- 迭代器iterator规范「具备next方法,每次执行返回一个对象,具备 value/done 属性」
- 让对象(Object)具备可迭代性并且使用for of循环
-
// 类数组对象「默认不具备迭代器规范」 let obj = { 0: 200, 1: 300, 2: 400, length: 3 }; //给对象加一个Symbol.iterator,因为对象默认是不可迭代的 obj[Symbol.iterator] = Array.prototype[Symbol.iterator]; for (let val of obj) { console.log(val); }
- 手写for ..of..循环的底层
-
let 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++] }; } }; };