javascript
javascript onsubmit返回false仍然能提交_JavaScript对象-Get和Put
這篇文章我們來了解一下對象屬性值讀寫的具體過程。
1.getter和setter
之前我們了解了對象的屬性描述符,這里我們來聊一下與之相對應的訪問描述符-getter和setter。
在ES5中可以使用getter和setter部分改寫默認操作,但是只能應用在單個屬性上,無法應用在整個對象上。
getter是一個隱藏函數,會在獲取屬性值時調用。setter也是一個隱藏函數,會在設置屬性值時調用。
當你給一個屬性定義getter、setter或者兩者都有時,這個屬性會被定義為“訪問描述符”(和“屬性描述符”相對)。對于訪問描述符來說,JavaScript會忽略它們的value和writable特性,取而代之的是關心set和get。
看一段代碼:
var obj = {get a() {return 1;} }; Object.defineProperty(obj, 'b', {get: function(){return 2;} }); obj.a; //1 obj.b; //2上面代碼展示的就是定義getter的兩種方式,不管是對象文字語法中的get a(){..},還是defineProperty(..)中的顯式定義,二者都會在對象中創建一個不包含值的屬性,對于這個屬性的訪問會自動調用一個隱藏函數,它的返回值會被當作屬性訪問的返回值。
通常來說getter和setter是成對出現的,getter一般也不會只返回一個靜態的值:
var obj = {get a() {return this._a_;},set a(val) {this._a_ = val * 2;} }; obj.a = 1; obj.a; //2對象中一個屬性的getter/settter和writable/value不能同時被定義。
2.對象的讀寫
【下面的內容需要你對JavaScript的原型鏈有一定的了解】
1.[[Get]]
JavaScript中對象屬性的訪問是有一套完整的規則的,思考下面代碼:
var obj = {a : 2}; obj.a; //2obj.a是一次屬性的訪問,但是這條語句并不僅僅是在obj中查找名字為a的屬性。在JavaScript的語言規范中,obj.a實際上是實現了[[Get]]操作。
對象默認的內置[[Get]]操作首先在對象中查找是否有名稱相同的屬性,如果有,就返回這個屬性的值。
如果沒有,就會繼續訪問對象的原型([[Prototype]])鏈:
var obj1 = {a : 1}; var obj = Object.create(obj1); obj.hasOwnProperty('a'); //false obj.a; // 1Object.create會創建一個對象并把這個對象的[[Prototype]]關聯到指定的對象。
可以通過Object.getPrototypeOf獲取到對象的原型([[Prototype]]):
Object.getPrototypeOf(obj) === obj1; // true //在瀏覽器中,一般可以通過__proto__訪問到對象原型 obj.__proto__ === obj1; // true現在obj的原型關聯到了obj1。
在訪問obj.a的時候,盡管a不存在于obj中,但是屬性訪問仍然成功的(在obj1中)找到了a的值為1。
如果obj中也找不到a并且原型鏈不為空的話,就會繼續查找下去。
這個過程會持續到 找到匹配的屬性名或者查找完整條原型鏈。如果是后者的話,[[Get]]操作的返回值是undefined。
所有普通的原型鏈最終都會指向內置的Object.prototype。
2.[[Put]]
既然有可以獲取屬性值的[[Get]]操作,就一定有對應的[[Put]]操作。 JavaScript中對象屬性的設置是也有一套完整的規則的,思考下面代碼:
var obj = {foo: 1}; obj.foo = 2; obj.foo; //2在給對象屬性賦值的時候,如果已經存在這個屬性,[[Put]]算法大致如下。
如果這個屬性不存在,會出現以下3種情況:
1.如果在obj的原型鏈上層存在名為foo的普通數據訪問屬性并且沒有被標記為只讀(writable:false),那就會直接在obj中添加一個名為foo的新屬性,它是屏蔽屬性。
var obj1 = {foo : 1}; var obj = Object.create(obj1); obj.foo; //1 obj.foo = 2; obj.foo; //2 obj1.foo; //1什么是屏蔽屬性?
如果一個屬性名既出現在當前對象中也出現在當前對象的原型鏈上層,那么就會發生屏蔽。
當前對象中包含的屬性會屏蔽原型鏈上層的所有同名屬性,因為屬性訪問總是會選擇原型鏈中最底層的屬性。
上面代碼片段中在給obj.foo重新賦值之后,再通過obj訪問屬性foo,就只能訪問到新設置在當前foo對象上的foo的值了。
2.如果在obj的原型鏈上層存在foo,但是它被標記為只讀(writable:false),那么無法修改已有屬性或者在obj上創建屏蔽屬性。如果運行在嚴格模式下,代碼會拋出一個錯誤。
var obj1 = {} Object.defineProperty(obj1,'foo', {value: 1,writable: false }); var obj = Object.create(obj1); obj.foo; //1 obj.foo = 2;//嚴格模式會拋出錯誤TypeError obj.foo; //1 obj1.foo; //13.如果在obj的原型鏈上層存在foo并且它是一個setter,那就一定會調用這個setter。foo不會被添加到obj。
var obj1 = {}; Object.defineProperty(obj1, 'foo', {set: function(val){console.log('setter of obj1:' + val)} }) var obj = Object.create(obj1); obj.foo = 1; //輸出:setter of obj1:1 obj.hasOwnProperty('foo'); //false從上面代碼片段可以看出,在執行obj.foo的時候,實際上只執行了obj1.foo的setter方法,并沒有在obj上創建屏蔽屬性。
如果你希望在第二種和第三種情況下也屏蔽foo,那就不能使用=操作符來賦值,而是使用Object.defineProperty來向obj添加foo:
var obj1 = {} Object.defineProperty(obj1,'foo', {value: 1,writable: false }); var obj = Object.create(obj1); Object.defineProperty(obj,'foo', {value: 2 }); obj.foo; //2總結
以上是生活随笔為你收集整理的javascript onsubmit返回false仍然能提交_JavaScript对象-Get和Put的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 云端存储能代替U盘吗 谁会成为最后的王者
- 下一篇: pythin怎么根据月份获取月初和月末_