Object.keys()会返回一个数组,包含所有可枚举属性;Object.getOwnPropertyNames()会返回一个数组,包含所有的属性,无论他们是否可枚举;对于Object.keys()和Object.getOwnPropertyNames()来说,他们都不会涉及到[[Prototype]]原型链上的属性。in和hasOwnProperty()的区别在于是否查找[[Prototype]]链,in操作符会检查属性是否在对象以及[[Prototype]]原型链上;hasOwnProperty()只会检查属性是否在对象中,并不会检查[[Prototype]]链。所有的对象都可以通过Object.prototype委托来访问hasOwnProperty(),但是有的对象可能没有连接到Object.prototype(比如说通过Object.create()创建的对象),在这种情况下,调用hasOwnProperty()就会失败。这时通过call等方法就可以解决这个问题。
如果某种数据类型的对象能够使用for...of...遍历的话,那是因为这种数据类型实现了迭代器。当然,对于普通的对象来说,它没有内置的迭代器,所以我们不能使用for...of...来进行遍历工作。不过,我们可以为其自定义一个迭代器。
var obj = {
"key1": 1,
"key2": 2
}
Object.defineProperty(obj, Symbol.iterator, {
"writable": false,
"enumerable": false,
"configurable": true,
"value": function(){
var index = 0
var target = this
var targetKeys = Object.keys(target)
return {
"next": function(){
return {
"value": target[targetKeys[index++]],
"done": (index > targetKeys.length)
}
}
}
}
})
for(var value of obj){
console.log(value)//1 2
}
1.写一个无限迭代器
无限迭代器的思想就是done属性的值总是为假。
var obj = {
[Symbol.iterator]: function(){
var times = 0
return {
"next": function(){
return {
"value": times++,
"done": false
}
}
}
}
}
for(var time of obj){
console.log(time)
}
2.需要注意的地方
先看一个例子:
var arr = [1, 2, 3, 4, 5]
Array.prototype[Symbol.iterator] = function(){
const target = this
var index = 0
return {
"next": function(){
return index < target.length ? {"value": target[index++]+1, "done": false} : {"value": undefined, "done": true}
}
}
}
arr.forEach((value, index) => {console.log(value)})//1 2 3 4 5
for(var num of arr){console.log(num)}//2 3 4 5 6
从上面那个例子,我们可以看出forEach遍历循环并不会使用iterator迭代器,它使用的遍历只是采用的常规的方法。
上面那个例子还有一个隐患,那就是我们为了改造arr的迭代器进而把数组的内置迭代器给修改了,这是会对工程中的后续代码造成隐患的——后续的数组类型对象的迭代器都被相应的改变。这同时也揭露了这么一个特性:对于数组对象来说,他的迭代器方法并不是存在数组对象自身里面的,而是存在于数组对象的[[Prototype]]上的这个对象——即Array.prototype中。同时也要注意这一点的其他应用:在对象上直接定义一个迭代器会把对象构造函数的prototype对象上的构造器给覆盖掉。下面可以看一个例子:
var arr = [1, 2, 3, 4, 5]
Array.prototype[Symbol.iterator] = function(){
const target = this
var index = 0
return {
"next": function(){
return index < target.length ? {"value": target[index++]+1, "done": false} : {"value": undefined, "done": true}
}
}
}
for(var num of arr){console.log(num)}//2 3 4 5 6
console.log(arr.hasOwnProperty(Symbol.iterator))//false
var arrPrototype = Object.getPrototypeOf(arr)
console.log(arrPrototype.hasOwnProperty(Symbol.iterator))//true
END