JS从其他语言中借鉴了很多流控制语句,最典型的就是for,作为前测试循环语句,不得不提一下其中的for-in与for-of语句。
首先来看一下for-in,权威解释(W3school、菜鸟教程、JavaScript高级程序设计)为用于遍历数组或者对象的属性
来看一下实例:
var arr = [1, '2', 3, null, '4', undefined];
for(var i in arr){
console.log(i);
}
// 0
// 1
// 2
// 3
// 4
// 5
可以看到对于该数组输出的是它的序号,那么再看一个对象的实例
var dog = {
name : '大黄',
age : 5,
gender : '雄性'
}
for(var i in dog){
console.log(i);
}
// name
// age
// gender
可以看到输出了该对象的属性,每一次执行循环时,都会将dog对象中存在的一个属性名赋值给变量i,这个过程会一直持续到对象中所有的属性都被枚举一遍为止,但是输出属性名的顺序是不可预测的,因浏览器而异。对于之前数组的例子,可以将其看作为这样:
var arr = {
0: 1,
1:'2',
2: 3,
3: null,
4: '4',
5: undefined
}
输出的序号也就是该数组的属性。
继续看这样一个例子,如果该对象是空,则会如何输出:
var arr = {
}
for(var i in arr){
console.log(i);
}
无输出,这很正常,但是如果要迭代对象的变量值是null
或者undefined
呢?
var arr = null
for(var i in arr){
console.log(i);
}
var arr = undefined
for(var i in arr){
console.log(i);
}
均无输出,需要主要的是,这里的控制台输出,并不代表着该循环体被执行,JavaScript高级程序设计(第3版)Page57指出:如果表示要迭代的对象的变量值为null或undefined,for-in语句就会抛出错误。ECMAScript5更正了这一行为;对这种情况不再抛出错误,而只是不执行循环体。
扩展一下,既然for-in遍历的为对象的key,那么如何利用for-in输出对象的value呢?来看下面的代码:
var dog = {
name : '大黄',
age : 5,
gender : '雄性'
}
for(var i in dog){
console.log(dog[i]);
}
// 大黄
// 5
// 雄性
继续深挖,如果在遍历对象前,对象的属性改变了,无论是数量还是属性值,那么for-in会怎么样输出?
var dog = {
name : '大黄',
age : 5,
gender : '雄性'
}
dog.color = 'black';
dog.age = 6;
for(var i in dog){
console.log(i, `:`,dog[i]);
}
// name : 大黄
// age : 6
// gender : 雄性
// color : black
从结果可以得出结论,for-in遍历的是更新后的对象。
经过上面的检验,可以得出:for-in循环会遍历一个object所有的可枚举属性
因此,对于对象的内置函数toString,valueOf等则无法遍历,那么推测一下,for-in是否可以遍历其原型上的属性呢?
var dog = {
name : '大黄',
age : 5,
gender : '雄性',
}
dog.color = 'black';
dog.age = 6;
Object.prototype.objCustom = function () {
return 'aaa';
}
for(var i in dog){
console.log(i, `:`,dog[i]);
}
// name : 大黄
// age : 6
// gender : 雄性
// color : black
// objCustom : function () {
// return 'aaa';
// }
答案是肯定的,但是这种将原型上的属性输出也会带来一些不必要的麻烦,将上面这个例子:
Array.prototype.myfunction = function () {
return 'aaa';
}
var dog = [
{name:'小黄', age : 3},
{name:'小黑', age : 4},
{name:'小白', age : 5}
]
for(var i in dog){
console.log(dog[i].name)
}
console.log('这是一行空值测试~')
看一下输出结果:
可以看到多于输出了一个空值,这在一些大型的项目中,可能就会导致一些bug,解决方法有这些:
- 使用
hasOwnProperty
属性判断
for(var i in dog){
if(!dog.hasOwnProperty(i)){
continue;
}
console.log(dog[i].name)
}
2. 使用length
属性来进行条件循环
3. 使用for-of语句
接着上文的引入,来看一下for-of,for-of是ES6中引入的新特性,用来弥补ES-5引入for-in的缺陷,与for-of的本质区别在于,for-of遍历的是数组或对象的属性值(value),来看一个简单的数组例子:
var arr = [1, '2', null, 3, undefined, '4'];
for(var i of arr){
console.log(i);
}
// 1
// 2
// null
// 3
// undefined
// 4
可以看到输出了数组中的元素各项元素,再来看一个对象实例:
var obj = {
name : '小黄',
age : 4,
gender : 'black'
};
for(var j of obj){
console.log(j);
}
结果报错了,明显for-of语句无法遍历普通对象,那么如何解决这问题呢?
使用Object.keys()方法,将对象中的key收纳为一个数组,然后输出,就像以下代码所示:
var obj = {
name : '小黄',
age : 4,
gender : 'black'
};
for(var j of Object.keys(obj)){
console.log(j);
}
// name
// age
// gender
该方法的遍历是遵循怎样的原则呢?
var array = ['a', 123, {a:'1', b:'2'}];
array.name = '小黄';
for(var i of array){
console.log(i);
}
// a
// 123
// { a: '1', b: '2' }
以上代码中,对array数组增加了属性值,但是结果并没有输出增加该属性,因此可以得出结论,for-of不同for-in,for-of只会遍历出初始数组或对象的key,即使在原型上进行增加也是如此。
参考博客:https://www.jb51.net/article/44028.htm
https://blog.csdn.net/wangpenglonton/article/details/79095011
https://segmentfault.com/q/1010000006658882