摘要:理解的函數(shù)在進(jìn)入今天的內(nèi)容之前我們可以先考慮這么一個(gè)場(chǎng)景在你的項(xiàng)目中你有這么一個(gè)對(duì)象如下所示我們的要求就是你要給添加一個(gè)屬性當(dāng)?shù)幕蛘甙l(fā)生變化的時(shí)候也要隨之變化而且當(dāng)我們?cè)O(shè)置了的值的時(shí)候那么相應(yīng)的它的和也隨之發(fā)生變化那么我們應(yīng)該怎么做呢如果你
理解JavaScript的Object.defineProperty()函數(shù)
在進(jìn)入今天的內(nèi)容之前,我們可以先考慮這么一個(gè)場(chǎng)景,在你的項(xiàng)目中你有這么一個(gè)對(duì)象如下所示:
var dreamapple = { firstName: "dream", lastName: "apple" };
我們的要求就是你要給dreamapple添加一個(gè)fullName屬性,當(dāng)dreamapple的firstName或者lastName發(fā)生變化的時(shí)候,fullName也要隨之變化;而且當(dāng)我們?cè)O(shè)置了fullName的值的時(shí)候,那么相應(yīng)的它的firstName和lastName也隨之發(fā)生變化; 那么我們應(yīng)該怎么做呢?
如果你使用過(guò)Vue.js的話,那么你可以使用它的計(jì)算屬性來(lái)達(dá)到這個(gè)目的,大概的代碼應(yīng)該是下面這個(gè)樣子:
// ... computed: { fullName: { // getter get: function () { return this.firstName + " " + this.lastName }, // setter set: function (newValue) { var names = newValue.split(" ") this.firstName = names[0] this.lastName = names[names.length - 1] } } } // ...
如果你使用過(guò)Angular 1.x的話,那么你可能會(huì)使用$watch來(lái)達(dá)到這個(gè)目的,大概的代碼應(yīng)該是下面這個(gè)樣子:
// 在控制器中使用 var vm = this; $scope.$watch("vm.firstName", function() { vm.fullName = vm.firstName + " " + vm.lastName; }); $scope.$watch("vm.lastName", function() { vm.fullName = vm.firstName + " " + vm.lastName; }); $scope.$watch("vm.fullName", function() { var names = vm.fullName.trim().split(" "); if(2 === names.length) { vm.firstName = names[0]; vm.lastName = names[1]; } else { // TODO } });
那我們使用原生的JavaScript可不可以達(dá)到這個(gè)目的呢?當(dāng)然可以了;那么我們需要怎么做呢?比較簡(jiǎn)單的做法就是給這個(gè)對(duì)象的屬性fullName設(shè)置一個(gè)getter和一個(gè)setter,因?yàn)檫@是ES5的特性所以較低版本的瀏覽器不支持這種特性,但是基本所有的現(xiàn)代瀏覽器都已經(jīng)支持.我們只需要寫(xiě)出下面的代碼就可以了:
var dreamapple = { firstName: "dream", lastName: "apple", get fullName() { return this.firstName + " " + this.lastName; }, set fullName(fullName) { var names = fullName.trim().split(" "); if(2 === names.length) { this.firstName = names[0]; this.lastName = names[1]; } } }; dreamapple.firstName = "Dream"; dreamapple.lastName = "Apple"; console.log(dreamapple.fullName); // Dream Apple dreamapple.fullName = "Jams King"; console.log(dreamapple.firstName); // Jams console.log(dreamapple.lastName); // King
是不是很方便呢?我們通過(guò)給dreamapple這個(gè)對(duì)象設(shè)置了屬性fullName的getter和setter方法,就達(dá)到了我們想要的那種效果.
當(dāng)然更好的一種方法就是使用Object.defineProperty()這個(gè)函數(shù)了,下面我們就來(lái)好好的探討一下這個(gè)函數(shù).這個(gè)方法的作用就是直接在一個(gè)對(duì)象上定義一個(gè)新屬性,或者修改一個(gè)已經(jīng)存在的屬性,并返回這個(gè)對(duì)象;我們先來(lái)看一下怎么使用這個(gè)方法:
Object.defineProperty(obj, prop, descriptor)
其中參數(shù)obj表示的是需要定義屬性的那個(gè)對(duì)象,參數(shù)prop表示需要被定義或者修改的屬性名,參數(shù)descriptor就是我們定義的那個(gè)屬性prop的描述;我們接下來(lái)主要講解這個(gè)descriptor.它是一個(gè)對(duì)象,它有許多的屬性,我們接下來(lái)來(lái)分析這些屬性都是干什么用的:
value 該屬性對(duì)應(yīng)的值,可以是任何有效的JavaScript值(數(shù)值,對(duì)象,函數(shù)等),默認(rèn)為undefined.我們可以看下面的一個(gè)小例子:
var dream = {}; Object.defineProperty(dream, "name", { value: "dreamapple" }); console.log(dream.name); // dreamapple dream.name = "apple"; // 修改name屬性 console.log(dream.name); // 并不是apple,依舊是dreamapple
從上面的代碼中我們可以看到,我們給dream定義了一個(gè)新的屬性name,然后我們打印出這個(gè)屬性就是我們預(yù)期的那樣,得到的是dreamapple;但是,當(dāng)我們嘗試改變這個(gè)屬性的時(shí)候,卻發(fā)現(xiàn)這個(gè)屬性并沒(méi)有改變,還以第一次我們賦給它的值;這是為什么呢?原來(lái),只有當(dāng)我們這個(gè)屬性的writable修飾為true時(shí),我們這個(gè)屬性才可以被修改.
writable 當(dāng)且僅當(dāng)僅當(dāng)該屬性的writable為true時(shí),該屬性才能被賦值運(yùn)算符改變;它的默認(rèn)值為false.我們來(lái)修改一下上面的代碼,讓屬性name可以被修改:
Object.defineProperty(dream, "name", { value: "dreamapple", writable: true }); console.log(dream.name); // dreamapple dream.name = "apple"; // 修改name屬性 console.log(dream.name); // apple
我們可以看到,當(dāng)我們把writable修改為true時(shí),我們就可以修改name屬性了.
enumerable 這個(gè)特性決定了我們定義的屬性是否是可枚舉的類(lèi)型,默認(rèn)是false;只有我們把它設(shè)置為true的時(shí)候這個(gè)屬性才可以使用for(prop in obj)和Object.keys()中枚舉出來(lái).就像下面這樣:
Object.defineProperty(dream, "a", { value: 1, enumerable: false // 不可枚舉 }); Object.defineProperty(dream, "b", { value: 2, enumerable: true // 可枚舉 }); // 只會(huì)輸出 b for(prop in dream) { console.log(prop); } console.log(Object.keys(dream)); // ["b"] console.log(dream.propertyIsEnumerable("a")); // false console.log(dream.propertyIsEnumerable("b")); // true
所以當(dāng)我們想給你個(gè)對(duì)象添加一個(gè)不可枚舉的屬性的時(shí)候,就應(yīng)該把enumerable設(shè)置為false.
configurable 這個(gè)特性決定了對(duì)象的屬性是否可以被刪除,以及除writable特性外的其它特性是否可以被修改;并且writable特性值只可以是false我們可以寫(xiě)一個(gè)代碼示例來(lái)演示一下這個(gè)特性:
Object.defineProperty(dream, "c", { value: 3, configurable: false }); //throws a TypeError Object.defineProperty(dream, "c", { configurable: true }); //throws a TypeError Object.defineProperty(dream, "c", { writable: true }); //won"t throws a TypeError Object.defineProperty(dream, "c", { writable: false }); delete dream.c; // 屬性不可以被刪除 console.log(dream.c); // 3
get 一個(gè)給屬性提供getter的方法,如果沒(méi)有getter則為undefined;該方法返回值被用作屬性值,默認(rèn)為undefined.
set 一個(gè)給屬性提供setter的方法,如果沒(méi)有setter則為undefined;該方法將接受唯一參數(shù),并將該參數(shù)的新值分配給該屬性,默認(rèn)為undefined.知道了這些之后我們就可以使用更標(biāo)準(zhǔn)的一種方式去解決我們?cè)谖闹虚_(kāi)頭的問(wèn)題了:
Object.defineProperty(dreamapple, "fullName", { enumerable: true, get: function () { return this.firstName + " " + this.lastName; }, set: function (fullName) { var names = fullName.trim().split(" "); if (2 === names.length) { this.firstName = names[0]; this.lastName = names[1]; } } });
還有一點(diǎn)需要注意的是,value和get,set是不可以共存的,就是說(shuō)你定義了value后就不能夠再定義get,set特性了.
好啦,今天的文章就寫(xiě)到這里了,相信大家對(duì)于Object.defineProperty(obj, prop, descriptor)這個(gè)方法應(yīng)該掌握了;還有一點(diǎn)需要提及的是其實(shí)Vue.js的計(jì)算屬性也是在這個(gè)函數(shù)的基礎(chǔ)上進(jìn)行的一些改進(jìn),詳情可以看這里計(jì)算屬性的奧秘.
如果你對(duì)這篇文章有什么意見(jiàn)或者建議可以在這里提出來(lái)issues
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/90886.html
摘要:深入理解中的屬性和特性中屬性和特性是完全不同的兩個(gè)概念,這里我將根據(jù)自己所學(xué),來(lái)深入理解中的屬性和特性。其中第三個(gè)參數(shù)描述符對(duì)象是對(duì)象字面量的方法創(chuàng)建的,里面的屬性和屬性值實(shí)際上保存的是要修改的特性和特性值。 深入理解JavaScript中的屬性和特性 JavaScript中屬性和特性是完全不同的兩個(gè)概念,這里我將根據(jù)自己所學(xué),來(lái)深入理解JavaScript中的屬性和特性。 主...
摘要:面向?qū)ο蟮某绦蛟O(shè)計(jì)理解對(duì)象前言最近在細(xì)讀高級(jí)程序設(shè)計(jì),對(duì)于我而言,中文版,書(shū)中很多地方翻譯的差強(qiáng)人意,所以用自己所理解的,嘗試解讀下??偨Y(jié)如果英語(yǔ)水平足夠好的話,建議看英文原版書(shū)籍或者國(guó)外大師的博客。 JS面向?qū)ο蟮某绦蛟O(shè)計(jì)_理解對(duì)象 前言:最近在細(xì)讀Javascript高級(jí)程序設(shè)計(jì),對(duì)于我而言,中文版,書(shū)中很多地方翻譯的差強(qiáng)人意,所以用自己所理解的,嘗試解讀下。 如有紕漏或錯(cuò)誤,會(huì)非...
摘要:今天結(jié)合高編第六章開(kāi)始回顧和深入學(xué)習(xí)面向?qū)ο蟛糠职▽?duì)象原型原型鏈繼承等部分。二對(duì)象的屬性類(lèi)型勾鑫宇,數(shù)據(jù)屬性訪問(wèn)器屬性書(shū)上講到屬性類(lèi)型時(shí),只是簡(jiǎn)單提了一下是為了表示對(duì)象的特性,描述了屬性的特征,并且在中不能直接訪問(wèn)。 前言 JavaScript發(fā)明之始,從技術(shù)上來(lái)講就是一門(mén)面向?qū)ο蟮恼Z(yǔ)言,但在ES6之前,JS的很多特性和傳統(tǒng)的面向?qū)ο笳Z(yǔ)言有所不同,比如沒(méi)有類(lèi)的概念(ES6有了clas...
摘要:返回值被傳遞給函數(shù)的對(duì)象。描述該方法允許精確添加或修改對(duì)象的屬性。描述符必須是兩種形式之一不能同時(shí)是兩者??梢允侨魏斡行У闹禂?shù)值,對(duì)象,函數(shù)等。該方法返回值被用作屬性值。該方法將接受唯一參數(shù),并將該參數(shù)的新值分配給該屬性。 Object.defineProperties() Object.defineProperty() 方法會(huì)直接在一個(gè)對(duì)象上定義一個(gè)新屬性,或者修改一個(gè)對(duì)象的現(xiàn)有屬性...
摘要:上一篇面向?qū)ο蟀鎵K之理解對(duì)象下一篇面向?qū)ο蟀鎵K之定義多個(gè)對(duì)象屬性以及讀取屬性特性 這是 javascript 面向?qū)ο蟀鎵K的第二篇文章,主要講解的是對(duì)象的屬性,首先創(chuàng)建一個(gè)對(duì)象: var person = { name: Nicholas, age: 29, job: Software Engineer, sayName: function () { conso...
閱讀 3120·2021-11-12 10:36
閱讀 5008·2021-09-22 10:57
閱讀 1776·2021-09-22 10:53
閱讀 2782·2019-08-30 15:55
閱讀 3554·2019-08-29 17:00
閱讀 3410·2019-08-29 16:36
閱讀 2525·2019-08-29 13:46
閱讀 1405·2019-08-26 11:45