`
driftcloudy
  • 浏览: 130797 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

JS中的对象创建、属性访问

阅读更多

一条面试题

公司最近在招web fronter,免不了需要进行面试,于是大家在群里讨论一些题目。其中一题如下:

var a = new Object;
var b = new Object;
var c = new Object;
c[a]=a;
c[b]=b;
alert(c[a]===a); //输出什么
 

这个题目还是很有意思的,第一反应往往会心中涌起一丝疑惑,这难道不是true么(我就是的= =!)事实上还真输出了一个false...这样也许看不出什么端倪,但是如果稍微变动一下代码:

var a = new Object;
var b = new Object;
var c = new Object;
c[a]=a;
c[b]=b;
alert(c[a]===b); //输出true
alert(c[b]===b); //输出true
 

从结果可以明显的推断出一个事实:当运行了c[b]=b这条语句之后,原先的属性c[a]被覆盖了。也就是说,其实c[a]和c[b]指向的是同一个东西。

 

创建JS对象

现在需要深究一下,JS对象的属性究竟是怎么回事...一般而言,我们会认为JS中的对象就是一个无序的属性集,这个属性集中的每个属性都由键值对构成,就好比一种散列表类似的数据结构。对象里属性的值可以用来存放JS中原型的值、对象的引用、函数的引用。这在Ecmascript-262标准中可以找到理论依据:

Ecmascript-262 3rd
An object is a member of the type Object. It is an unordered collection of properties each of which
contains a primitive value, object, or function. A function stored in a property of an object is called a method.

 

JS中有两种创建对象的方式,一种是通过new运算符,还有一种是通过字面量的方式。前文的面试题中就是利用了new Object来创建一个貌似是空的对象。下面来分别分析一下这两种创建对象的方式:

 

1.字面量

字面量创建的方式很简单,根据Ecma标准语法:

Ecma 262 10.1.5
ObjectLiteral :
     { }
     { PropertyNameAndValueList }
PropertyNameAndValueList :
     PropertyName : AssignmentExpression
     PropertyNameAndValueList , PropertyName : AssignmentExpression
PropertyName :
     Identifier
     StringLiteral
     NumericLiteral

根据描述,如果创建的不是空对象,而是一个带有Name和Value的对象,那么Name可以是JS中的标识符、字符串或者数字。具体的创建过程是可以描述成:

1)var obj = {} 就等于var obj = new Object()

The production ObjectLiteral : {} is evaluated as follows:
1. Create a new object as if by the expression new Object().
2. Return Result(1).
 

2)var obj = { PropertyNameAndValueList }

如果是这种带了键值对的对象,首先还是调用new Object()来创建一个新的对象,然后会计算PropertyName、AssignmentExpression,利用GetValue方法获取AssignmentExpression的值,最后调用被新创建对象的[[Put]] 方法(obj的put方法是内部方法,外部无法调用),具体细节如下:

The production ObjectLiteral : { PropertyNameAndValueList } is evaluated as follows:
1. Evaluate PropertyNameAndValueList.
2. Return Result(1);
The production PropertyNameAndValueList : PropertyName : AssignmentExpression is evaluated as follows:
1. Create a new object as if by the expression new Object().
2. Evaluate PropertyName.
3. Evaluate AssignmentExpression.
4. Call GetValue(Result(3)).
5. Call the [[Put]] method of Result(1) with arguments Result(2) and Result(4).
6. Return Result(1).

这里的GetValue和[[Put]]方法都可以暂且不管,因为它们对于程序员并不可见。进一步看一下Evaluate PropertyName的过程:

The production PropertyName : Identifier is evaluated as follows:
1. Form a string literal containing the same sequence of characters as the Identifier.
2. Return Result(1).
The production PropertyName : StringLiteral is evaluated as follows:
1. Return the value of the StringLiteral.
The production PropertyName : NumericLiteral is evaluated as follows:
1. Form the value of the NumericLiteral.
2. Return ToString(Result(1)).

可以发现,在利用字面量创建对象的时候:如果属性的name用JS中的标识符表示,那么name会被转成值相同的字符串;如果属性的name是number,那么会调用ToString来计算该number的字符串表示,这儿的ToString也是JS内部的方法。

 

2.利用new Object()

调用new Object()也是一种创建对象的方法,如果不传参数进去,本质上来说跟直接使用字面量{}没有区别。实际上new Object的过程还是有些复杂的:

new Object ( [ value ] )
When the Object constructor is called with no arguments or with one argument value, the following steps are taken:
1. If value is not supplied, go to step 8.
2. Ifthetypeof value isnotObject,gotostep5.
3. If the value is a native ECMAScript object, do not create a new object but simply return value.
4. If the value is a host object, then actions are taken and a result is returned in an implementation-dependent manner that may depend on the host object.
5. Ifthetypeof value is String, return ToObject(value).
6. Ifthetypeof value is Boolean, return ToObject(value).
7. Ifthetypeof value is Number, return ToObject(value).
8. (The argument value was not supplied or its type was Null or Undefined.)Create a new native ECMAScript object.
The [[Prototype]] property of the newly constructed object is set to the Object prototype object.
The [[Class]] property of the newly constructed object is set to "Object".
The newly constructed object has no [[Value]] property.
Return the newly created native object

很显然,如果是不传参数,那么会创建一个 native ECMAScript object,随后会给这个object添加一系列的内部属性 ,比如将 [[Prototype]]设置为Object prototype object(即Object.prototype),将[[Class]]设置为字符串“Object”。注意,在Object.prototype中已经包含了一些方法:

        1.toString ( )

        2.toLocaleString ( )

        3.valueOf ( )

        4.hasOwnProperty (V)

        5.isPrototypeOf (V)

        6.propertyIsEnumerable (V)

利用new Object新创建的对象不会有除了上面之外别的方法。

 

对象的属性访问、赋值

对JS中的对象进行属性访问同样也是两种形式,一种是利用“[ ]”运算符,还有一种是利用“.”运算符。即:

CallExpression. Identifier 或CallExpression[ Expression ]

注意就是利用“.”的时候,只能后接一个合法的Identifie。但是如果是利用“[ ]”却可以包含一个表达式进来,本文刚开始的题目中就是利用这种形式去访问obj的属性。其实CallExpression. Identifier也会按照CallExpression[ <Identifier-string>]去执行。

CallExpression[ Expression ] is evaluated as follows:
1. Evaluate CallExpression.
2. Call GetValue(Result(1)).
3. Evaluate Expression.
4. Call GetValue(Result(3)).
5. Call ToObject(Result(2)).
6. Call ToString(Result(4)).
7. Return a value of type Reference whose base object is Result(5) and whose property name is Result(6).

尤其要注意第6行, 所有方括号中的Expression的值要经过ToString这一步。

 

对于赋值,具体的计算过程如下:

The production AssignmentExpression : LeftHandSideExpression = AssignmentExpression is evaluated as follows:
1. Evaluate LeftHandSideExpression.
2. Evaluate AssignmentExpression.
3. Call GetValue(Result(2)).
4. Call PutValue(Result(1), Result(3)).

CallExpression就是一种 LeftHandSideExpression。

 

题目详解:

下面来拆分题目,逐行来推敲具体的执行过程,首先是三条创建对象的语句:

//创建一个native Ecmascript object
//[[Prototype]]指向Object.prototype
//[[Class]]设为"Object"
var a = new Object;
//同a
var b = new Object;
//同a
var c = new Object;

注意,一个obj里并非只有 [[Prototype]]和[[Class]]两个内部属性,具体的内部属性以及内部方法可以参考Ecma262的8.6章节。

 

在创建完对象后,又是两条属性赋值语句。

//c[a]会按照CallExpression[ Expression ] 的7个步骤来计算,
//其中的GetValue较为复杂,可以参考http://www.w3help.org/zh-cn/causes/SD9028的注释2
//注意第6步,ToString(a)会调用到ToPrimitive(a),进而调用a的[[DefaultValue]]方法,具体参考Ecma规范
//这里最终会调用到a.toString方法,根据Object.prototype.toString的描述,会返回[object Object]
//即最终相当于c["[object Object]"]=a;
c[a]=a;
//即最终相当于c["[object Object]"]=b;
c[b]=b;
alert(c[a]===a);

 

稍微变个形

var a = {};
var b = {};
var c = {};
c.a=a;
c.b=b;
alert(c[a]===a);

你可能会立马想到,c.a是怎么处理的,很显然这是利用了“.”运算符访问属性,而不是“[ ]”。根据上面的描述, CallExpression. Identifier会按照CallExpression[ <Identifier-string>]去执行,那么这里的c.a就相当于c["a"]。因此最后结果肯定是true了?

 

真的是这样么?别忘了,在alert语句中还有c[a]的存在,如前文所述,c[a]完全就相当于c["[object Object]"],因此这段代码相当于:

var a = {};
var b = {};
var c = {};
c["a"]=a;
c["b"]=b;
alert(c["[object Object]"]===a);

真是相当的恶心....

 

再来变一变

这次c的属性直接在声明里写好了。

var a = {};
var b = {};
var c = {
	a:a,
	b:b
};
alert(c.a===a);

这回是利用了字面量创建对象的方式。根据上面的描述,如果键值对的name是一个合法的JS标识符,那么name就是将该标识符变成直接字符串,简单来说,就是两边加上引号。

因此,上面这段代码相当于:

var a = {};
var b = {};
var c = {};
c["a"]=a;
c["b"]=b;
alert(c.a===a);

终于输出了true....

 

 

 

0
5
分享到:
评论

相关推荐

    javascript动态创建对象的属性详解

    我对JavaScript中属性的理解,在javascript中,可以通过在文字对象上定义变量来创建属性。 例如 var obj = { property1: '', property2: '' }; 现在可以通过使用来访问这些属性 obj.property1 = 'some value'; ...

    javascript常用对象梳理

    熟练掌握window对象的status、location、name、self、opener属性的使用 Window对象是客户端javascript最高层对象之一,只要打开浏览器窗口,不管该窗口中是否有打开的网页,当遇到BODY、FRAMESET或FRAME元素时,...

    Web前端开发技术-认识JavaScript的对象.pptx

    项目5 JavaScript对象;学习目标;任务1 认识JavaScript的对象;在JavaScript中,对象是一种数据类型,它是由属性和方法组成的一个集合。属性是指事物的特征,使用“对象.属性名”访问;方法是指事物的行为,使用“对象...

    javascript对象的创建和访问

    JavaScript,很少能让人想到它面向对象的特性,甚至有人说它不是面向对象的语言,因为它没有...JavaScript 中的对象实际上就是一个由属性组成的关联数组,属性由名称和值组成,值的类型可以是任何数据类型,或者函数和

    protomatter.js:具有私有属性和私有方法的 JavaScript 对象创建库

    Protomatter 是 JavaScript 的对象创建和继承库,具有私有实例属性和私有方法。 性能注意事项 限制 灵感 介绍 Protomatter 提供了一些经典语言的便利,例如隐私和调用“超类”的方法,同时利用了 JavaScript 原型...

    JavaScript中创建类/对象的几种方法总结

    在JS中,创建对象(Create Object)并不完全是我们时常说的创建类对象,JS中的对象强调的是一种复合类型,JS中创建对象及对对象的访问是极其灵活的。 JS对象是一种复合类型,它允许你通过变量名存储和访问,换一种...

    源文件程序天下JAVASCRIPT实例自学手册

    4.2 JavaScript对象的生成 4.2.1 HTML文档结构 4.2.2 DOM框架 4.2.3 顶级对象之间的关系 4.2.4 浏览器载入文档时对象的生成 4.3 JavaScript核心对象 4.4 文档对象的引用 4.4.1 通过对象位置访问文档对象 4.4.2 通过...

    javascript完全学习手册1 源码

    3.1 JavaScript对象概述 43 3.1.1 对象的概念 43 3.1.2 使用JavaScript对象 基础知识 44 3.2 Array对象 46 3.2.1 创建Array对象 46 3.2.2 Array对象属性 47 3.2.3 Array对象方法 48 3.3 String对象 51 3.3.1 创建...

    JavaScript教程

     常用对象的属性和方法  范例:时钟 • 五、 创建新对象  对象的定义  创建对象实例  对象方法的使用  JavaScript中的数组  范例:动态文字滚动;颜色变化 • 六、 使用内部对象系统  浏览器对象层次及其...

    javascript完全学习手册2 源码

    3.1.2 使用JavaScript对象基础知识 3.2 Array对象 3.2.1 创建Array对象 3.2.2 Array对象属性 3.2.3 Array对象方法 3.3 String对象 3.3.1 创建String对象 3.3.2 String对象属性 3.3.3 String对象方法...

    JavaScript基础和实例代码

    4.2 JavaScript对象的生成 4.2.1 HTML文档结构 4.2.2 DOM框架 4.2.3 顶级对象之间的关系 4.2.4 浏览器载入文档时对象的生成 4.3 JavaScript核心对象 4.4 文档对象的引用 4.4.1 通过对象位置访问文档对象 4.4.2 通过...

    javascript创建对象—类,继承

    你甚至可以以键值对的方式来操作javascript中的对象,就像这样:跟这种方式创建对象的效果是一样的:显然,第二种访问方式更加方便.通常只有在并不确定我们访问的对象的属性名字的时候(比如json数据),才会使用这种...

    JavaScript程序设计课件:原型与继承.pptx

    在利用构造函数创建对象时,每个对象都默认与这个原型对象连接,连接后就可以访问到原型对象中的属性和方法 6.6.1 原型 2、作用 利用原型对象可以保存一些公共的属性和方法。当访问某个对象中的一个不存在的属性或...

    JavaScript 基于原型的对象(创建、调用)

    在我们写js代码的时候,内部对象是不可避免的要引用,但是光靠这些对象是不够的,所以需要我们自己定义对象,这个时候通常用到的对象是第三种,即基于原型的对象,下面就如何创建自己的对象,定义对象的方法、属性,...

    JavaScript权威指南-第六版

     4.4 属性访问表达式63  4.5 调用表达式64  4.6 对象创建表达式64  4.7 运算符概述65  4.8 算术表达式69  4.9 关系表达式74  4.10 逻辑表达式79  4.11 赋值表达式81  4.12 表达式计算83  4.13 其他运算符...

    JavaScript创建类/对象的几种方式概述及实例

    在JS中,创建对象(Create Object)并不完全是我们时常说的创建类对象,JS中的对象强调的是一种复合类型,JS中创建对象及对对象的访问是极其灵活的。 JS对象是一种复合类型,它允许你通过变量名存储和访问,换一种...

    理解JavaScript中的对象 推荐

    在JavaScript没有类的定义,创建对象时没有固定的模板,可以动态的创建新的属性和方法,在动态创建新属性的... JavaScript对象完全不同于c#或vb对象,JavaScript对象可以看成一组健/值对的集合,用对象.属性名来访问一

    JavaScript创建对象_动力节点Java学院整理

    当我们用obj.xxx访问一个对象的属性时,JavaScript引擎先在当前对象上查找该属性,如果没有找到,就到其原型对象上找,如果还没有找到,就一直上溯到Object.prototype对象,最后,如果还没有找到,就只能返回...

    JavaScript中对DOM节点的访问、创建、修改、删除

    用DOM方法和属性,你可以访问,修改,删除页面上任意一个元素,也是可以添加一个元素。DOM是独立于语言的API,可以被任意语言所实现,当然也包括了Javascript 看看下面的一个文本。 &lt;!DOCTYPE ...

Global site tag (gtag.js) - Google Analytics