Appearance
for循环和forEach底层原理 1.基于var声明的时候,for和while性能差不多, 2.基于let声明的时候,for循环性能更好 原理: for循环的i保存在块级上下文中,每轮循环结束i都会被释放,不会占用全局上下文空间 while循环的i只能定义在条件外,所以是全局上下文的i,循环没结束就不能释放,一直被占用
3.重写forEach
for...in循环机制 => 主要用来遍历对象key 1.优先迭代数字属性且从小到大(无法解决) 2.会遍历所有私有和公有的可枚举属性(私有属性大部分是可枚举的(length就不可以), 公有属性出现在所属类的原型上,也有部分是可枚举的) 带来问题: 1.性能最差(原型链一级一级查找) 2.公有属性一般是不需要迭代的(使用if (!o.hasOwnProperty(key)) break解决, 但是性能还是很受影响,因为要先找到一个可枚举的公有属性,找不到还是会一直找下去 ) 3.无法迭代Symbol类型的私有属性
js
const o = {
// 都是私有属性
name: 'Tom',
age: 20,
[Symbol('foo')]: 'foo',
0: 100,
1: 200
}
// 定义公有属性
Object.prototype.bar = 'bar'
Object.prototype[10] = 300
for (let key in o) {
// if (!o.hasOwnProperty(key)) break // 不拿公有属性
console.log(key)
// 0 私有数字优先
// 1 私有数字优先
// name 私有其他属性
// age 私有其他属性
// 10 公有数字属性优先
// bar 公有其他属性
}怎么获取Symbol属性?
js
Object.getOwnPropertyNames(o).concat(Object.getOwnPropertySymbols(o))
// 或
const keys = Object.keys(o).concat(Object.getOwnPropertySymbols(o))
keys.forEach(key => {
console.log(key, o[key])
})for...of循环机制 => 遍历value => Array, Map, Set, String, TypedArray, arguments... 1.原理是Iterator迭代器 2.实现对象使用for...of
js
class Iterator {
constructor (assemble) {
this.assemble = assemble
this.index = 0
}
next () {
let { index, assemble } = this
if (index < assemble.length) {
// this.index++,不是index++
return { done: false, value: assemble[this.index++]}
}
return { done: true, value: undefined}
}
}
const iterator = new Iterator([1, 2, 3, 4, 5])
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
const arr = [1, 2, 3, 4, 5]
arr[Symbol.iterator] = function () {
let _this = this
let index = 0
return {
next () {
if (index < _this.length) {
return { done: false, value: _this[index++]}
}
return { done: true, value: undefined}
}
}
}
for (let i of arr) {
console.log(i)
}
Object.prototype[Symbol.iterator] = function () {
const _this = this
const keys = Object.keys(_this).concat(Object.getOwnPropertySymbols(_this))
let index = 0
return {
next () {
if (index < keys.length) {
return {
done: false,
value: _this[keys[index++]]
}
}
return {
done: true,
value: undefined
}
}
}
}各种循环的性能对比
js
const arr = new Array(10000000).fill(0)
console.time('for')
for (var i = 0; i < arr.length; i++) {
}
console.timeEnd('for') // 26.59423828125 ms
console.time('while')
var i = 0
while(i < arr.length) {
i++
}
console.timeEnd('while') // 26.297119140625 ms
console.time('for')
for (let i = 0; i < arr.length; i++) {
}
console.timeEnd('for') // 5.042236328125 ms
console.time('while')
let i = 0
while(i < arr.length) {
i++
}
console.timeEnd('while') // 26.242919921875 ms
console.time('forEach')
arr.forEach(item => {})
console.timeEnd('forEach') // 83.221923828125 ms
console.time('for...in')
for (let key in arr) {}
console.timeEnd('for...in') // 1980.77001953125 ms
console.time('for...of')
for (let key of arr) {}
console.timeEnd('for...of') // 144.93798828125 ms
// for/while > forEach > for...of > for...in封装一个方面遍历对象所有私有属性 支持回调返回值为false时, 结束循环
js
function eachObject(target, callback) {
let keys = Object.keys(target)
// 不兼容Symbol的浏览器就不用拿Symbol属性了
if (typeof Symbol !== 'undefined') {
keys = keys.concat(Object.getOwnPropertySymbols(target))
}
let i = 0,
length = keys.length,
key,
value,
result
// 写成for是因为forEach不支持结束迭代
for (; i < length; i++) {
key = keys[i]
value = target[key]
result = callback(key, value)
// 若回调返回false,结束迭代
if (result === false) {
break
}
}
}