2011-03-05 129 views
50

我继承了另一位开发人员写的一些javascript代码。他不喜欢我们在整个项目中使用的网格组件,所以他决定写他自己的。他写的网格不能排序日期,因为它只能绑定到字符串/数字。他在使用它们之前将所有日期转换为字符串。我查看了他编写的日期函​​数的字符串格式,并且认为我只需将一个日期属性添加到具有原始值的字符串中,然后在排序时查看该字符串是否具有日期属性并根据该属性进行排序。但是,似乎你不能在javascript中为字符串添加属性。我不知道有一些你不能添加属性的类型。例如:为什么我无法将属性添加到JavaScript中的字符串对象?

<html> 
<script> 
var test = "test"; 
test.test = "test inner"; 
console.log(test); 
console.log(test.test); 
</script> 

test.test将是未定义的。奇怪的。我的问题是为什么这段代码不起作用?此外,如果您可以考虑在该网格上排序日期的任何解决方法(除了实际绑定到日期对象而不是字符串,这将是一个修复的痛苦),这将是非常有用的。

+0

参见:[?是字符串对象(http://stackoverflow.com/questions/5156196/are-strings-object/) – CMS 2011-03-05 02:16:34

回答

69

有6种语言类型中的JavaScript:

  • 5原始类型:字符串布尔未定义
  • 1非原始型: 对象

原始类型的值称为原始值,它们不能具有属性。
对象的值非原始类型被称为对象,它们可以具有属性。

当您尝试了一个名为'bar'属性分配给一个变量foo,像这样:

foo.bar = 'abc'; 

那么结果将取决于foo值的类型:

(一)如果foo的值是的类型未定义无效,则会抛出错误,

(b)中如果foo值是类型对象,则命名属性'bar'将对象foo(如果必要)上定义的,并且它的值将被设置为'abc'

(c)中如果foo值是类型的字符串布尔,则变量foo将不会以任何方式改变。在这种情况下,上述分配操作将是noop

因此,正如你所看到的,如果这些变量是对象,那么赋值给变量只有意义。如果情况并非如此,那么这项任务根本就什么也不做,甚至会出错。


在你的情况下,变量test包含String类型的值,所以这个:

test.test = "test inner"; 

做什么都没有。


但是,由于ES5引入了访问器属性,所以我上面说过了一个例外。访问器属性允许我们定义在检索或设置属性时调用的函数。

例如:

var str = ''; 
str.prop; 

这里str是拿着字符串值的变量。因此,访问该变量的属性应该是无操作的(str.prop仅返回undefined)。这是有一个例外:如果String.prototype包含访问器属性'prop'与一个定义的getter,那么该getter将被调用。

所以,如果这被定义:

Object.defineProperty(String.prototype, 'prop', { 
    get: function() { 
     // this function is the getter 
    } 
}); 

那么这

str.prop; 

将调用该getter函数。

现场演示:http://jsfiddle.net/fmNgu/

不过,我不认为加入存取性能的内置原型将是一个很好的做法。

+9

'你不能给属性赋值'有点令人误解:由于自动装箱(更具体地说,ECMA-262第5版第8.7.2节中描述的算法),将属性分配给基元是完全有效的;然而,这些属性将被添加到纯粹的临时包装对象而不是基元中,因此无法获取属性(包装对象不会替换基元)。因此,将一个属性赋给一个原语是一个noop,除非赋值有副作用(例如,如果该属性是通过访问函数实现的) – Christoph 2011-03-05 13:14:31

+0

@Christoph是的,你说得对。我已经更新了我的答案。你可以请实际检查一下吗? – 2011-03-05 18:10:18

+2

@Šime:您的回答准确地描述了ECMAScript3的行为:根据第11.2.1节,属性访问调用'ToObject()',它将抛出未定义和空值,为值创建包装对象并返回对象的参数;在ES5中,情况稍微复杂一些,因为您可以将一个setter函数添加到基元的原型对象,即对基元的设置属性可能会产生副作用... – Christoph 2011-03-05 21:50:31

25

如果您使用String对象,您可以添加属性:

var test = new String("test"); 
test.test = "test inner"; 
console.log(test.toString()); // prints out "test" 
console.log(test.test); // prints out "test inner" 
+5

它确实有一个缺点。以下返回false:'test ==='test''。这是[为什么它那样](http://stackoverflow.com/questions/10951906/why-does-foo-new-stringfoo-evaluate-to-false-in-javascript)。 – 2012-09-14 14:56:29

+0

你刚刚做了我的一天。我知道......曾经...... – halfbit 2016-05-29 17:05:43

相关问题