JavaScript对象length

前几日有在Javascript数组操作一文中稍提及了数组的length属性;深入一点探究,就发现JS这length确有许多难为所知的特性。这就边学边探究下这朵奇葩属性;这里边深入边记载。

可变的数组length属性

和其他大多数语言不同的是,JavaScript数组的length属性是可变的,这一点需要特别注意。当length属性被设置得更大时,整个数组的状态事实上不会发生变化,仅仅是length属性变大;当length属性被设置得比原来小时,则原先数组中索引大于或等于length的元素的值全部被丢失。下面是演示改变length属性的例子:

var arr=[12,23,5,3,25,98,76,54,56,76];
console.log(arr.length);  // 10

arr.length=5; //将数组的长度减少到5,索引等于或超过5的元素被丢弃
alert(arr[8]); //显示第9个元素已经变为"undefined"

arr.length=10; //将数组长度恢复为10
alert(arr[8]); //虽然长度被恢复为10,但第9个元素却无法收回,显示"undefined"

arr[15] = 34;
console.log(arr.length);  //16

console.log(arr[10]);     //undefine
console.log(arr.toString())
//12,23,5,3,25,98,76,54,56,76,,,,,,34

length对象不仅可以显式的设置,它也有可能被隐式修改。JavaScript中可以使用一个未声明过的变量,同样,也可以使用一个未定义的数组元素(指索引超过或等于length的元素),这时,length属性的值将被设置为所使用元素索引的值加1。例如下面的代码:

var arr=[12,23,5,3,25,98,76,54,56,76];
console.log(arr.length);  // 10

arr[15] = 34;
console.log(arr.length);  //16

console.log(arr[10]);     //undefine
console.log(arr.toString())
//12,23,5,3,25,98,76,54,56,76,,,,,,34

JS对象的length

在JS中来判断一个对象是否为数组,是需要费点周折的。但以是否具有length属性来衡量之,显然是不合理的。length数组不是独有的,JS对象也是可以用的(当然,数组也是对象的一种~数组对象)。譬如:

var obj = {'1':'gg', '2':'love', '4':'meimei', length:5};
console.log(obj.length); // 5

JavaScript中有一些看起来像却又不是数组的对象,唤作: 类数组。一个类数组对象:

  • 具有:指向对象元素的数字索引下标以及length属性告诉我们对象的元素个数
  • 不具有:诸如 push forEach 以及 indexOf 等数组对象具有的方法

两个典型的类数组的例子是:DOM方法 document.getElementsByClassName()的返回结果(实际上许多DOM方法的返回值都是类数组)以及特殊变量 arguments [1]。例如你可以通过以下方法确定函数参数的个数:arguments.length 你也可以获取单个参数值,例如 arguments[0]。 如果这些对象想使用数组的方法,就必须要用某种方式“借用”。这里的“借用”可以借助JS的call,apply方法来实现。有时候处理类数组对象的最好方法是将其转化为数组。 这项工作也可以使用通用方法来完成:

var obj = {'1':'gg','2':'love','4':'meimei',length:5};
Array.prototype.join.call(obj , '+'); //'+gg+love++meimei'

类数组判断

聊起JS对象的length就有必要说下这个类数组判断。之前有在IOS 8 Safari JIT bug影响jQuery和underscore记录使用Underscore在IOS机器引起的问题。而对于此问题,jQuery,Underscore方面修复的办法就是改变了类数组判断的判断方式:

//underscore 1.7.0 _.each部分代码
var i, length = obj.length;
if (length === +length) {
    ......
}

对比与underscore1.8.3 _.each部分代码(是采用isArrayLike来判断的):

var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
var getLength = property('length');
var isArrayLike = function(collection) {
  var length = getLength(collection);
  return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
};

var property = function(key){
  return function(obj){
    return obj == null ? void 0 : obj[key];
  }
}

对于数组是有下标的,其下标的范围是”大于等于0并小于2^32-1的整数”,如果数字太大的话你想难为JavaScript是做不到的。因为其会自动将其转化为”字符串”。而underscore1.8.3用的MaxLength是Math.pow(2, 53) - 1(其值:9007199254740992),不解?,待探究下~

而《javascript权威指南》上给出的代码用来判断一个对象是否属于“类数组”。其code如下:

function isArrayLike(o) {
    if (o &&                                // o is not null, undefined, etc.
        typeof o === 'object' &&            // o is an object
        isFinite(o.length) &&               // o.length is a finite number
        o.length >= 0 &&                    // o.length is non-negative
        o.length===Math.floor(o.length) &&  // o.length is an integer
        o.length < 4294967296)              // o.length < 2^32
        return true;                        // Then o is array-like
    else
        return false;                       // Otherwise it is not
}

##数组的存储 在JavaScript中数组元素存储是稀疏的,这也就意味着数组的下标不会落在一个连续的数字范围由,只有那些真正存储在数组中的元素才能够分配到内存,其余均不会浪费你宝贵的内存空间。比如如下代码:

var arr = new Array();   //声明一个空数组
arr[0] = 'jeff';
arr[1000] = 'jade';
console.log(arr.length); //1001 嗯。从0到1000
console.log(arr[999]);   //undefined 没有定义

在JavaScript中数组元素本身,可以是各种类型Null,function,string,object对象等都可以。这一点毋庸置疑;但前两日在学习数组reduce方法的时候,竟然被涨了姿势了,代码走起:

var arr = ["apple","orange",'pear','jade'];
var arrJade;
function passValue(){
    return arr.reduce(function(prev,next){
        console.log("prev---:",prev);
        console.log("next---:",next);

        prev[next] = 1;
        //console.info('prev type:'+ typeof(prev)); // [object Array]
        console.log(Object.prototype.toString.call(prev));
        arrJade = prev;
        return prev;
    }, []);    
}
console.log("reduce With [] as an additional parameter:",passValue());
//reduce With [] as an additional parameter: [ apple: 1, orange: 1, pear: 1, jade: 1 ]
console.log(arrJade.length); // 0
arrJade.push('jade');    
console.log(arrJade);        // [ 'jade', apple: 1, orange: 1, pear: 1, jade: 1 ]
console.log(arrJade.apple);  // 1

这里可以看出,可以得到一个类Object对象的数组:只是被包裹的是[],而非{};且此时该“数组”是有length属性的,只不过length是0而已。这个“数组”,以console.log(Object.prototype.toString.call(arrJade));来判别是数组无疑。但是倘若类同如此这样直接定义一个“数组”,却是断然不可以的,请看如下代码:。

var arr = [apple: 1, orange: 1]; //这么搞,编译都过不了,语法错误❌
//Uncaught SyntaxError: Unexpected token : ...

//but,可以像使用reduce方法一样,可以构造出这样的数组!
var arrTest = [];
arrTest["apple"] = 1;
arrTest["orange"] = 1;
console.log(arrTest);       //[apple: 1, orange: 1]
console.log(arrTest.length) // 0
arrTest.push('pear');
console.log(arrTest);       // ["pear", apple: 1, orange: 1]
console.log(arrTest.length) // 1

console.log(arrTest.apple); //1   arrTest['apple']当然也可以访问。

arrTest["pear"] = 1;
console.log(arrTest);       //["pear", apple: 1, orange: 1, pear: 1]

既然这是一个数组,但为何不能直接如此构造,这一点现在还没搞搞明白,呜呜~。而这样:arrTest[“apple”] = 1; 操纵一个数组,无形的将该项元素对象化了,又没用{}将其包裹,致使其“游离”于此数组一级对象一列,数组能够直接访问。但是,又不在length计数范围。length的数组下表是有对应关系的,当然这里也不能使用数组带下标来访问了。

JS数组,对于诸如Number,String之类的类型数据会被直接压入栈中,而引用类型只会压入对该值的一个索引(即C中所说的保存了数据的指针)。这些数据时储存在堆中的某块区间中,堆栈并不是独立的,栈中也可以在堆中存放。那么那些直接游离在数组中的Object元素项,存储地是在哪儿呢?额额,还是没搞搞明白,!?(・_・;?。

对于JS,尚有诸多未知,待学待探究,即便是这随便一个属性:length!!!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏从流域到海域

Python基本数据类型

其实之前有一篇博客:C\C#\Java\Python 基本数据类型比较 https://cloud.tencent.com/developer/article...

2536
来自专栏伪君子的梦呓

题解~按照特定的格式输出~C++做法

一共三行,第一行:位数 第二行: 用空格分开的每个数字,注意最后一个数字后没有空格 第三行: 按逆序输出这个数

554
来自专栏前端架构与工程

【译】《Understanding ECMAScript6》- 第一章-基础知识(一)

目录: 更好的Unicode编码支持 codePointAt()函数 String.fromCodePoint() 用转义序列对Non-BMP字符编码 nor...

2745
来自专栏软件开发

JavaSE学习总结(八)—— 异常处理(Exception)

一、理解异常及异常处理的概念 异常就是在程序的运行过程中所发生的不正常的事件,它会中断正在运行的程序。 异常不是错误 程序中关键的位置有异常处理,提高程序的稳定...

2339
来自专栏web前端教室

不学不知道,sort()方法中的坑

今天的前端零基础课,在讲到js中的sort()排序方法的时候,说sort()这个方法在给数字排序的时候,根本不是按数字大小来排序的。 它是把数字都当成字符串来看...

19510
来自专栏aCloudDeveloper

LeetCode:1_Two_Sum | 两个元素相加等于目标元素 | Medium

题目: Given an array of integers, find two numbers such that they add up to a spec...

20810
来自专栏xx_Cc的学习总结专栏

iOS-正则表达式的简单使用

4437
来自专栏用户2442861的专栏

C++ string中的几个小陷阱,你掉进过吗?

http://blog.csdn.net/lanxuezaipiao/article/details/24885811

1292
来自专栏趣谈编程

Unicode与UTF-8的区别

要弄清Unicode与UTF-8的关系,我们还得从他们的来源说起,下来我们从刚开始的编码说起,直到Unicode的出现,我们就会感觉到他们之间的关系

1332
来自专栏chenjx85的技术专栏

leetcode-179-Largest Number(理解规则,自定义cmp函数进行排序)

1、这道题给定一个vector,里面存放着int类型的非负整数,要求把这些非负整数拼起来,尽可能拼成一个最大的整数。

1933

扫码关注云+社区

领取腾讯云代金券