向Array以外的原始数据类型添加属性

时间:2013-11-15 23:44:48

标签: javascript

我不应该像这样向数组中添加元素:

var b   = [];
b.val_1 = "a";
b.val_2 = "b";
b.val_3 = "c";

我不能使用本机数组方法,为什么不只是一个对象。我只是在数组中添加属性,而不是元素。我想这使它们与length属性并行。虽然尝试重置长度(b.length = "a string")会获得Uncaught RangeError: Invalid array length

无论如何,我仍然可以看到我设置的属性:

console.log(b); //[val_1: "a", val_2: "b", val_3: "c"]

我可以使用点语法访问它:

console.log(b.val_1); //a

如果一个数组只是一个对象,字符串或数字就是一个对象,为什么不能(不是我想要的)我用这种语法为它们附加属性:

var num    = 1;
num.prop_1 = "a string";

console.log(num); //1

我无法使用点语法

访问其属性
console.log(num.prp); //undefined

为什么可以使用数组而不是其他数据类型。对于所有情况,我应该使用{}并且只需要使用{},那么为什么数组有这种能力呢?

JSBIN

2 个答案:

答案 0 :(得分:7)

由于数组被语言视为对象,因此您可以通过键入以下代码行来查看:

console.log(typeof []) // object

但是其他类型,如数字文字,字符串文字NaN ...等都是原始类型,并且只包含在由语言定义的某些上下文中的对象代理中。

如果要向这样的数字添加属性或方法,那么可以像这样使用Number构造函数:

var num = new Number(1);
num.prop_1 = "fdadsf";
console.log(num.prop_1);

使用Number构造函数返回一个数字对象,您可以通过键入以下行来查看该对象:

console.log(typeof num); // object

在第一种情况下:

var num = 1;
console.log(typeof num) // number

编辑2:例如,当您在数字文字或字符串文字上调用方法时,该原语会被方法调用的语言自动包装到其对象表示中,例如:

var num = 3;
console.log(num.toFixed(3)); // 3.000

这里num是一个原始变量,但是当你在它上面调用toFixed() metohd时,它会被包装到Number对象,因此可以进行方法调用。

编辑:在第一种情况下,您首先创建了一个类似于此字符串var str = new String()的字符串,然后将其更改为str = "asdf",然后分配了属性{{1} }。

当然,这不起作用,因为当您分配str.var_1 = "1234"时,str = "asdf"成为基本类型,而最初创建的Object实例现在已经消失,您无法添加属性原始人。

在第二个中,它没有像你说的那样输出str,我在undefined测试了它,一切正常。

编辑3:

  

字符串文字(用双引号或单引号表示)和非构造函数上下文中String调用返回的字符串(即不使用new关键字)是原始字符串。

这取自MDN Documentation,当您使用类似Firebug的字符串时,它变为转换函数而不是构造函数,并且它返回原始字符串,如上面的引用所示。

关于您的第二条评论,我不明白我的评论是如何被藐视的,因为如果您尝试var p = String(3),您将获得console.log(p.pr),证明undefined是原始类型而不是一个对象。

答案 1 :(得分:2)

  

如果一个数组只是一个对象,那么字符串或数字就是一个对象,

数组不同于字符串,数字,布尔值,null和undefined。数组是一个对象,而列表中的其他数组是原始值。您可以像对待任何其他对象一样向数组添加属性,任何不同的东西都是使数组特殊的原因(例如,您提到的长度属性)。您无法在原始值上添加属性或调用方法。

this之前的回答中,我谈到了对原始值使用Object包装器。随意阅读它以查看有关Object包装器的更多信息。以下是一个非常简短的例子:

console.log('TEST'.toLowerCase()) // 'test'

虽然看起来在字符串'TEST'上调用toLowerCase方法,但实际上字符串会自动转换为String对象,并且在String对象上调用toLowerCase方法。

每次调用字符串,数字或布尔值的属性时,都会创建一个适当类型的新Object包装器来获取或设置该值(设置属性可能完全被浏览器优化掉,我不确定这一点)。

根据你的例子:

var num    = 1; // primitive value
num.prop_1 = "a string"; // num is converted to a Number, the prop_1 property is set on the Object which is discarded immediately afterwards
console.log(num); //1 // primitive value
console.log(num.prp);  // num is converted to a Number, which doesn't have the prp property

我的例子:

Number.prototype.myProp = "works!";
String.prototype.myFunc = function() { return 'Test ' + this.valueOf() };
Boolean.prototype.myTest = "Done";


console.log(true.myTest); // 'Done'
console.log('really works!'.myFunc()); // 'Test really works!'

var x = 3;
console.log(x.myProp.myFunc()); // 'Test works!'

console.log(3['myProp']); // 'works!'

另一方面:

console.log(3.myProp); // SyntaxError: Unexpected token ILLEGAL

这个数字不一定区别对待,语法只会混淆解析器。以下示例应该有效:

console.log(3.0.myProp); // 'works!'