JavaScript:屬性賦值和原型鏈
本文要研究一下:一個(gè)對(duì)象的原型鏈?zhǔn)侨绾斡绊懺搶?duì)象自身的屬性賦值操作的.本文更詳細(xì)的闡述了一下上篇文章“[譯]JavaScript中的屬性:定義和賦值的區(qū)別”中提到的一個(gè)知識(shí)點(diǎn).
原型鏈
每個(gè)對(duì)象都有一個(gè)包含了一個(gè)或者多個(gè)對(duì)象的原型鏈,該對(duì)象正是這個(gè)原型鏈的起始對(duì)象.原型鏈上的所有對(duì)象的所有屬性都可以被該對(duì)象訪問到.例如:
- > var proto = { foo: 1 };
- > var obj = { __proto__: proto, bar: 2 };
- > obj.foo
- 1
- > obj.bar
- 2
我們用到了特殊屬性 __proto__ 來創(chuàng)建原型鏈(該屬性還沒有被所有瀏覽器廣泛支持).對(duì)象obj的原型鏈包含了三個(gè)對(duì)象:起始處是obj,緊跟著proto,***是Object.prototype. Object.prototype是Object構(gòu)造函數(shù)的原型對(duì)象,絕大部分原型鏈中都包含了它(大部分,但不是全部):
- > Object.prototype.isPrototypeOf({})
- true
- > Object.prototype.isPrototypeOf([])
- true
- > Object.prototype.isPrototypeOf(new Date())
- true
而且它是原型鏈的截止對(duì)象:
- > Object.getPrototypeOf(Object.prototype)
- null
普通對(duì)象的很多標(biāo)準(zhǔn)方法都是從Object.prototype上繼承下來的,比如toString()和hasOwnProperty().
為屬性賦值
如果你給一個(gè)屬性賦值,你通常只能修改原型鏈上的起始對(duì)象(也就是對(duì)象自身):如果自身屬性已經(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í)行賦值操作可以改變?cè)蜕系哪莻€(gè)公用的屬性值的話,那么所有實(shí)例的初始值都會(huì)被改變.為了防止這種情況發(fā)生,同時(shí)還允許你修改某單個(gè)實(shí)例的初始值,屬性的賦值操作被設(shè)計(jì)為:僅允許你改變一個(gè)已存在的自身屬性的值.如果還沒有這個(gè)自身屬性,則會(huì)自動(dòng)創(chuàng)建,再賦值.
訪問器和原型鏈
一個(gè)存在于原型鏈上的訪問器屬性[3]可以阻止"在該原型鏈的起始對(duì)象上創(chuàng)建同名的自身屬性".假如對(duì)象obj繼承了一個(gè)擁有g(shù)etter和setter的對(duì)象:
- var obj = {
- __proto__: {
- get foo() {
- return 1;
- },
- set foo(x) {
- console.log("Setter called: "+x);
- }
- }
- };
給對(duì)象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
原型鏈上的只讀屬性
如果原型鏈上的起始對(duì)象繼承了一個(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