案例分析
var obj = {
count: 1
}
var myArray = ['red', 'white', 'black'];
console.log(myArray.length);
myArray.obj = obj;
console.log(myArray.length);
两次打印myArray的length是多少?为什么?
理想与现实的冲突
我认为结果应该是 3 4
但结果是 4 4
打印的数组如我所想 [ 'red', 'white', 'black', obj: { count: 1 } ]
然length 仍然为3
老实说,一上来就被整懵逼了。
从现实出发
可仔细一看,案例本来就没有给数组多增加元素个数。
myArray.obj = obj;
这一点非常关键 案例用的时 点语法 赋值操作,那么意思就是给myarray数组增加了一个obj属性。属性值是定义的obj对象。
而真正的向数组添加元素 用的是数组的 push方法。push才是真正的向数组中添加一个元素。
如果代码改成这样,数组长度就是理想的长度了。
myArray.push(obj);
console.log(myArray);
console.log(myArray.length);
而.obj只是为当前的这个数组增加属性,
myArray.name = 'xiaoming';
console.log(myArray);
console.log(myArray.length);
实验表明,使用.属性只能增加数组的属性,
而这些属性和值通常通过键值对的形式放在数组元素的后面,而不会增加数组的个数。
[ 'red', 'white', 'black', obj: { count: 1 } ]
对数组长度的理解
数组长度:
The length property of an object which is an instance of type Array sets or returns the number of elements in that array. The value is an unsigned, 32-bit integer that is always numerically reater than the highest index in the array.
- length 属性 是数组设置或返回数组中的元素个数。它的值是无符号32位整数,始终数值上大于数组中的最高索引。
var fruits = [];
fruits.push('banana', 'apple', 'peach');
console.log(fruits.length); // 3
// 当给数组设置一个属性,当这个属性是合法的数组索引,并且数组索引超出了当前数组的边界,引擎就会相应的更新数组的length属性
fruits[5] = 'mango';
console.log(fruits[5]); // 'mango'
console.log(Object.keys(fruits)); // ['0', '1', '2', '5']
console.log(fruits.length); // 6
- 由于length可以取值也可以赋值,所以length属性并不能确切的表示数组中元素的个数,解释如下:
You can set the length property to truncate an array at any time. When you extend an array by changing its length property, the number of actual elements does not increase; for example, if you set length to 3 when it is currently 2, the array still contains only 2 elements. Thus, the length property does not necessarily indicate the number of defined values in the array. See also Relationship between length and numerical properties.
你可以随时设置length属性来缩短一个数组,它真的就缩小的,只会保留length个元素。
当你通过改变length属性扩大数组时,实际的元素个数并没有增加,例如,当前数组有2个元素,把length设置为3,数组依然只包含2个元素。因此 length属性不能确切的反映数组中的元素个数。
length和数字属性的关系
我们知道数组是通过索引访问的 或者说 通过下标来访问的。那么下标其实就是数字属性,而数组的length属性是和数字属性连在一起的。
其中数组几个内置的函数(比如, join, slice, indexOf, 等) 被调用时会计算数组的length属性,
其他的方法(比如, push, splice, 等)也会更新数组的length属性既然属性可以用点语法访问,为什么数字属性不行
属性一般可以通过点语法访问,这要求点语法点到的必须是一个合法命名的变量。而合法的命名是不允许以数字开头的。
所以这个属性只能通过括号表示法方法 即myArray[0]
- 关于数组中有多少个元素的思考
通过上述分析,我们知道length属性并不能正确表示数组中有多少个元素。
比如说修改数组的最高索引,或者更直接点直接修改length属性的值,这样都无法反应数组到底有几个元素。
这就有个问题,如何知道数组中到底有多少个元素?
上面打印结果的 obj:{count:1}是不是数组的元素呢?应不应该算上?
数组的属性是数字,通过索引访问。数组的索引就是数组特殊的属性名,而obj不是数字属性 以这种形式展示在数组中 obj:{count:1} 那么数组本质上或许也是这么写的[0:'red',1:'white']
那么我个人觉得要算上,数组中键的个数就代表了数组中有多少个元素
console.log(Object.keys(myArray).length);
然而这么算就会有一个困惑。还好这个属性是添加在具体的数组中的,所以才有显示出来,如果是在Array.prototype中定义的,那么就不会打印出来。所以我觉得非数字类索引是不需要的算入有多少个元素的。
如果要算有多少个元素,就要排除到这些非数字属性。
总结与应用
如果看到键值对的形式(外面没有括号包裹,即非独立对象)出现在数组中,
那它就不是作为数组元素存在的,而是作为数组的属性或方法存在的。
这就意味着 可以给数组增加 属性和方法 方便我们使用了。
比如返回每个数组的平方
var myArray = [1,2,3,4,5];
myArray.square = function () {
for (var i = this.length - 1; i >= 0; i--) {
this[i] *= this[i];
}
return this;
};
console.log(myArray.square());
加深理解
我查了查,这个东西其实叫做原型prototype其作用就是给对象添加属性和方法的。上述链接是W3C的参考例子。是从具体的对象层面增加的属性和方法。案例也是这个意思。
还可以给每一个对象增加属性和方法,这是MDN对Array.prototype的解释,比如给Array增加一个first方法,那么所有的数组实例都拥有这个方法,而且打印数组时,此方法在数组中不会看到。
console.log(myArray.square());
if (!Array.prototype.first) {
Array.prototype.first = function() {
return this[0];
}
}
console.log(myArray.first());