今天在用for in
循环遍历的时候,出现了部分不符合我以为的预期的行为,于是了解了一下for in
的行为。后来突发奇想,js 里还有in
运算符可以来判断一个对象是否有某个属性,比较好奇,for in
里的in
和运算符in
表现是否一致?
for…in
for...in
语句以任意顺序遍历一个对象的除Symbol以外的可枚举属性。(包括它的原型链上的可枚举属性)。属性定义
for (variable in object) statement
来个例子:
var obj=Object.create({a:1}) //prototype ,打印 obj.b=2 // 打印 obj.c=undefined // 打印 obj.d=3 delete obj.d // 不打印 obj[Symbol('e')]=4 //不打印 Object.defineProperty(obj, 'f', {enumerable:false}) //不打印,不可枚举 for (var prop in obj) { console.log("obj." + prop + " = " + obj[prop]); } // Output: // obj.b = 2 // obj.c = undefined // obj.a = 1
我们可以看到,打印出了b、c、a ,并不是按照我们定义的顺序打印的。
总结一下:
- 遍历顺序不确定
- 包括原型链上的属性
- 忽略key为symbol 的属性
- 忽略key不可枚举 的属性
- 不忽略属性值为undefined 的key
- 已经delete 的属性不会再有
in运算符
如果指定的属性在指定的对象或其原型链中,则in
运算符返回true
。
来个例子:
var obj=Object.create({a:1}) //prototype ,打印 obj.b=2 // 打印 obj.c=undefined // 打印 obj.d=3 delete obj.d // 不打印 var e=Symbol('e') obj[e]=4 //不打印 Object.defineProperty(obj, 'f', {enumerable:false}) //不打印,不可枚举 'a' in obj // true 'b' in obj // true 'c' in obj // true 'd' in obj // false e in obj // true 'f' in obj // true
总结一下:
- 可以判断原型链上的属性
- 可以判断值为undefined 的属性
- 可以判断自身的属性
- 可以判断key 为symbol 的属性
- 可以判读不可枚举的属性
- 被删除的属性视为不存在(理应如此)
可以看到,in
运算符还是非常的具有实用价值,再也不用Object.keys(obj).includes(k)
来判断了。但要注意`!` 运算符的优先级比`in`高。
if(!('a' in obj)){ //括号不能漏 }
总结
for in
语句中的in
和运算符in
关系不大,并且表现不完全一致。in
运算符基本上可以检测一个对象上是否拥有某个属性,而for in
在遍历的时候,会忽略symbol
类型的key 和不可枚举的key。
值得一提的是,for in
遍历会把原型链上的属性也遍历出来,而与之对应的,我们经常用来获取对象的所有key 的Object.keys()
函数,只会取出属于对象本身的属性值,不知道这个区别你有注意到吗?