这里有新鲜出炉的 Javascript 教程,程序狗速度看过来!
Javascript 是一种由 Netscape 的 LiveScript 发展而来的原型化继承的基于对象的动态类型的区分大小写的客户端脚本语言,主要目的是为了解决服务器端语言,比如 Perl,遗留的速度问题,为客户提供更流畅的浏览效果。
引用类型的值是应用类型的的一个实例,对象是某个特定引用类型的实例。新对象是使用 new 操作符后跟一个构造函数创建的。下面我们就从一个小例子烂研究下这个问题吧。
先看个例子:
- <script>
- var a = {
- n: 1
- };
- var b = a;
- a.x = a = {
- n: 2
- };
- console.log(a.x); // --> undefined
- console.log(b.x); // --> [object Object]
- </script>
上面的例子看似简单,但结果并不好了解,很容易把人们给想绕了——"a.x 不是指向对象 a 了么?为啥 log(a.x) 是 undefined?"、"b.x 不是应该跟 a.x 是一样的么?为啥 log 出来居然有 2 个对象 "
当然各位可以先自行理解一下,若能看出其中的原因和工作机理自然就无须继续往下看啦。
下面来分析下这段简单代码的工作步骤,从而进一步理解 js 引用类型 "赋值" 的工作方式。
首先是
var a = {n:1}; var b = a;
在这里 a 指向了一个对象 {n:1}(我们姑且称它为对象 A),b 指向了 a 所指向的对象,也就是说,在这时候 a 和 b 都是指向对象 A 的:
这一步很好理解,接着继续看下一行非常重要的代码:
a.x = a = {n:2};
我们知道 js 的赋值运算顺序永远都是从右往左的,不过由于 "." 是优先级最高的运算符,所以这行代码先 "计算" 了 a.x。
这时候发生了这个事情——a 指向的对象 {n:1} 新增了属性 x(虽然这个 x 是 undefined 的):
从图上可以看到,由于 b 跟 a 一样是指向对象 A 的,要表示 A 的 x 属性除了用 a.x,自然也可以使用 b.x 来表示了。
接着,依循 "从右往左" 的赋值运算顺序先执行 a={n:2} ,这时候,a 指向的对象发生了改变,变成了新对象 {n:2}(我们称为对象 B):
接着继续执行 a.x=a,很多人会认为这里是 "对象 B 也新增了一个属性 x,并指向对象 B 自己"
但实际上并非如此,由于一开始 js 已经先计算了 a.x,便已经解析了这个 a.x 是对象 A 的 x,所以在同一条公式的情况下再回来给 a.x 赋值,也不会说重新解析这个 a.x 为对象 B 的 x。
所以 a.x=a 应理解为对象 A 的属性 x 指向了对象 B:
那么这时候结果就显而易见了。当 console.log(a.x) 的时候,a 是指向对象 B 的,但对象 B 没有属性 x。没关系,当查找一个对象的属性时,JavaScript 会向上遍历原型链,直到找到给定名称的属性为止。但当查找到达原型链的顶部 - 也就是 Object.prototype - 仍然没有找到指定的属性 B.prototype.x,自然也就输出 undefined;
而在 console.log(b.x)的时候,由于 b.x 表示对象 A 的 x 属性,该属性是指向对象 B,自然也输出了 [object Object] 了,注意这里的 [object Object] 可不是 2 个对象的意思,对象的字符串形式,是隐式调用了 Object 对象的 toString()方法,形式是:"[object Object]"。所以 [object Object] 表示的就只是一个对象罢了
来源: http://www.phperz.com/article/17/0416/271844.html