JavaScript:屬性賦值和原型鏈
本文要研究一下:一個(gè)對象的原型鏈?zhǔn)侨绾斡绊懺搶ο笞陨淼膶傩再x值操作的.本文更詳細(xì)的闡述了一下上篇文章“[譯]JavaScript中的屬性:定義和賦值的區(qū)別”中提到的一個(gè)知識(shí)點(diǎn).
原型鏈
每個(gè)對象都有一個(gè)包含了一個(gè)或者多個(gè)對象的原型鏈,該對象正是這個(gè)原型鏈的起始對象.原型鏈上的所有對象的所有屬性都可以被該對象訪問到.例如:
- > var proto = { foo: 1 };
 - > var obj = { __proto__: proto, bar: 2 };
 - > obj.foo
 - 1
 - > obj.bar
 - 2
 
我們用到了特殊屬性 __proto__ 來創(chuàng)建原型鏈(該屬性還沒有被所有瀏覽器廣泛支持).對象obj的原型鏈包含了三個(gè)對象:起始處是obj,緊跟著proto,***是Object.prototype. Object.prototype是Object構(gòu)造函數(shù)的原型對象,絕大部分原型鏈中都包含了它(大部分,但不是全部):
- > Object.prototype.isPrototypeOf({})
 - true
 - > Object.prototype.isPrototypeOf([])
 - true
 - > Object.prototype.isPrototypeOf(new Date())
 - true
 
而且它是原型鏈的截止對象:
- > Object.getPrototypeOf(Object.prototype)
 - null
 
普通對象的很多標(biāo)準(zhǔn)方法都是從Object.prototype上繼承下來的,比如toString()和hasOwnProperty().
為屬性賦值
如果你給一個(gè)屬性賦值,你通常只能修改原型鏈上的起始對象(也就是對象自身):如果自身屬性已經(jīng)存在了,則改變這個(gè)屬性的值,否則,創(chuàng)建這個(gè)新的自身屬性:
- > obj.foo = 3;
 - > obj.foo
 - 3
 - > obj.hasOwnProperty("foo")
 - true
 - > proto.foo
 - 1
 
這樣設(shè)計(jì)的目的是:一個(gè)原型可以為其所有的實(shí)例引入了一個(gè)公用的初始值(被繼承的屬性的值).如果給其中一個(gè)實(shí)例的同名屬性執(zhí)行賦值操作可以改變原型上的那個(gè)公用的屬性值的話,那么所有實(shí)例的初始值都會(huì)被改變.為了防止這種情況發(fā)生,同時(shí)還允許你修改某單個(gè)實(shí)例的初始值,屬性的賦值操作被設(shè)計(jì)為:僅允許你改變一個(gè)已存在的自身屬性的值.如果還沒有這個(gè)自身屬性,則會(huì)自動(dòng)創(chuàng)建,再賦值.
訪問器和原型鏈
一個(gè)存在于原型鏈上的訪問器屬性[3]可以阻止"在該原型鏈的起始對象上創(chuàng)建同名的自身屬性".假如對象obj繼承了一個(gè)擁有g(shù)etter和setter的對象:
- var obj = {
 - __proto__: {
 - get foo() {
 - return 1;
 - },
 - set foo(x) {
 - console.log("Setter called: "+x);
 - }
 - }
 - };
 
給對象obj的屬性foo賦值的話,會(huì)調(diào)用到其原型上的setter訪問器,而不會(huì)給obj創(chuàng)建一個(gè)自身屬性foo,同理,讀取obj的foo屬性的話,也會(huì)調(diào)用到其原型上的getter訪問器:
- > obj.foo = 2;
 - Setter called: 2
 - > obj.foo
 - 1
 
如果你想禁止該屬性的賦值操作的話(也就是只讀),可以不提供setter:
- var obj = {
 - __proto__: {
 - get foo() {
 - return 1;
 - }
 - }
 - };
 
這樣的賦值操作,在非嚴(yán)格模式下會(huì)靜默失敗,在嚴(yán)格模式下,會(huì)拋出異常:
- > (function () { "use strict"; obj.foo = 2; }());
 - TypeError: Cannot set property foo of obj which has only a getter
 
原型鏈上的只讀屬性
如果原型鏈上的起始對象繼承了一個(gè)只讀屬性,則你無法通過賦值操作改變這個(gè)屬性的值.例如,下面的代碼:
- var proto = Object.defineProperty({},
 - "foo",
 - {
 - value: 1,
 - writable: false
 - });
 - var obj = { __proto__: proto };
 
你無法給obj.foo賦值:
- > (function () { "use strict"; obj.foo = 2; }());
 - TypeError: obj.foo is read-only
 
這正好和只有g(shù)etter的訪問器屬性的表現(xiàn)相一致.這一次,原型上的屬性同樣可以作為一個(gè)共享的初始值,不同的是,我們要防止單個(gè)實(shí)例更改自己的初始值.如果你想要給obj創(chuàng)建一個(gè)自身屬性foo,則你可以使用Object.defineProperty()和Object.defineProperties()來完成.
英文原文:http://www.2ality.com/2012/11/property-assignment-prototype-chain.html
原文鏈接:http://www.cnblogs.com/ziyunfei/archive/2012/11/08/2759680.html















 
 
 











 
 
 
 