摘要:通過創(chuàng)建的對象運(yùn)算符創(chuàng)建并初始化一個(gè)新對象,關(guān)鍵字后跟隨一個(gè)函數(shù)調(diào)用,這里的函數(shù)稱作構(gòu)造函數(shù),構(gòu)造函數(shù)用以初始化一個(gè)新創(chuàng)建的對象。
該文章以收錄: 《JavaScript深入探索之路》 前言
對象是Javascript 的基本類型。對象是一種復(fù)合值,它將很多值(原始值或者其他對象)聚合在一起,可通過名字訪問這些值。對象也可看做是屬性的無序集合。每個(gè)屬性都是一個(gè)名/值對。JavaScript對象還可以從一個(gè)稱為原型的對象繼承屬性。
需要注意的是ES6中對對象也做了一些擴(kuò)展,本文章并沒有特別說明,如果你想了解,可以看看阮老師的ES6書籍。
我們可以把對象的屬性分為三大類
內(nèi)置對象:是有ECMAScript規(guī)范定義的對象或類。例如數(shù)組、函數(shù)、日期和正則表達(dá)式都是內(nèi)置對象。
宿主對象: 是由JavaScript 解析器所嵌入的宿主環(huán)境,客戶端JavaScript 中表示網(wǎng)頁結(jié)構(gòu)的HTMLElement對像均是宿主對象。宿主對象也可以當(dāng)成內(nèi)置對象。
自定義對象:是由運(yùn)行中的JavaScript 代碼創(chuàng)建的對象。
另外還有兩類屬性
自有屬性: 是直接在隊(duì)形中定義的屬性
繼承屬性: 是在對象的原型對象中定義的屬性
創(chuàng)建對象 1.對象字面量(也稱為對象直接量)創(chuàng)建對象最簡單的方式就是在JavaScripot代碼中使用對象直接量。
let obj = { name: "web", age: 23, sex: "man" }
對象的屬性名可以是Symbol值,這時(shí)ES6新出的一個(gè)數(shù)據(jù)類型。對象直接量是一個(gè)表達(dá)式,這個(gè)表達(dá)式的每次運(yùn)算都創(chuàng)建并初始化一個(gè)新的對象。每次計(jì)算對象直接量的時(shí)候,也都會計(jì)算它的每個(gè)屬性值。也就是說,如果在一個(gè)重復(fù)調(diào)用的函數(shù)中的循環(huán)體內(nèi)使用了對象直接量,它將創(chuàng)建很多新對象,并且每次創(chuàng)建的對象那個(gè)的屬性值也有可能不同。
2.通過new創(chuàng)建的對象new運(yùn)算符創(chuàng)建并初始化一個(gè)新對象,關(guān)鍵字new 后跟隨一個(gè)函數(shù)調(diào)用,這里的函數(shù)稱作構(gòu)造函數(shù),構(gòu)造函數(shù)用以初始化一個(gè)新創(chuàng)建的對象。JavaScript語言核心中的原始類型都包含內(nèi)置構(gòu)造函數(shù)。
let obj = new fun(); let ary = new Array();
另外我們需要知道使用new創(chuàng)建的構(gòu)造函數(shù)時(shí)沒有原型的,但是他們最終都會繼承Object.prototype
let ary = new Array(); ary.prototype // undefind3.Object.create()方法創(chuàng)建對象
Object.create() 該方法創(chuàng)建一個(gè)新對象,它有兩個(gè)參數(shù),第一個(gè)參數(shù)是這個(gè)對象的原型。第二個(gè)參數(shù)用以對對象的屬性進(jìn)行進(jìn)一步描述。Object.create() 是一個(gè)靜態(tài)函數(shù),而不是提供給某個(gè)對象調(diào)用的方法。
let o = { name: "jhon", age: 23 } let obj = Object.create(o); obj.name // jhon obj.__proto__ === o // true obj的原型鏈指向?qū)ο?o obj.name === o.name // true
它的第二個(gè)參數(shù)是對屬性的一些數(shù)值,下面我們會講到,對對象屬性特征的一些設(shè)置
對象的屬性操作 1.查詢對象屬性的查詢我們有可以使用.運(yùn)算符、[]運(yùn)算符或者使用ES6提供的Reflect.get() 方法
let o = { name: "jhon", age: 23 } console.log(o.name) // "jhon" console.log(o["name"]) // "jhon" console.log(Reflect.get(o, "name")) // "jhon"
對于[]來說,方括號內(nèi)必須是一個(gè)計(jì)算結(jié)果為字符串的表達(dá)式(也可以直接是字符串),一般我們用來獲取動態(tài)的屬性。另外我這里不在講解ES6的東西,想了解ES6,可以看看阮一峰老師關(guān)于es6基礎(chǔ)的書籍。
2.刪除delete 操作符可以刪除屬性,它的操作數(shù)應(yīng)當(dāng)是一個(gè)屬性訪問表達(dá)式,delete只是斷開屬性和宿主對象的聯(lián)系,而不會去操作屬性中的屬性。
let o = { name: "jhon", age: 23, other: { address: "HangHai", }, } var obj = o.name; delete o.name console.log(o.name) // underfind console.log(obj) // "jhon"
另外delete運(yùn)算符只能刪除自有屬性,不能刪除繼承屬性,它也不能刪除某些屬性配置為false的屬性。還有全局函數(shù)和var聲明的變量也是不能刪除的。
3.繼承屬性是可以繼承的,JavaScript對象具有“自有屬性”,也有一些是從原型對象上繼承的屬性。例如函數(shù)的toString()方法我們繼承自O(shè)bject的原型。
4.檢測檢測屬性的歸屬我們可以使用in運(yùn)算符, hasOwnPreperty() 和 protertyIsEnumerable() 方法。
let o = { name: "jhon", age: 23, other: { address: "HangHai", }, } //使用 in 操作符來判讀屬性是否是該對象的自有屬性 // 或繼承的屬性 console.log("name" in o) // true console.log("toString" in o) // true //hasOwnProperty()判讀屬性是否是該對象的自有屬性 console.log(o.hasOwnProperty("name")) // true console.log(o.hasOwnProperty("toString")) // false
propertyIsEnumerable() 是 hasOwnProperty() 的增強(qiáng)版,只有檢測是自有屬性且這個(gè)蘇醒的可枚舉性為true時(shí)它才返回true。
// toString 是不可枚舉的屬性 console.log(o.propertyIsEnumerable("toString")) // false5.枚舉屬性
我們可以使用for/in 遍歷(枚舉) 屬性,我們可以使用以下方法來遍歷對象的自有屬性
let o = { name: "jhon", age: 23, other: { address: "HangHai", }, } let obj = {} for (prop in o){ if(o.hasOwnProperty[prop]) continue; obj[prop] = o[prop]; }6.屬性的set和get
在ECMAScrit5中屬性值是可以用一個(gè)或兩個(gè)方法替代,這兩個(gè)方法就是getter 和 setter,由getter和setter定義的屬性稱做“存取器屬性”,它不同于“數(shù)據(jù)屬性”。
當(dāng)程序查詢存取器屬性的值時(shí),JavaScript調(diào)用getter方法(無參數(shù))。這個(gè)方法的返回值就是屬性存去表達(dá)式的值,當(dāng)程序設(shè)置一個(gè)存去器屬性的值時(shí),JavaScript調(diào)用setter方法,將賦值表達(dá)式右側(cè)的值當(dāng)做參數(shù)傳入setter。
和數(shù)據(jù)屬性不同的是,存取器屬性不具有可寫性。如果屬性同時(shí)具有g(shù)etter和setter方法,那它是一個(gè)讀/寫屬性,如果它只有g(shù)etter方法,那么他是一個(gè)只讀屬性,如果它只有setter方法,那么他是一個(gè)只寫屬性。
定義存取器屬性的最簡單方法是使用對象直接量的語法:
let o = { name: "jhon", age: 23, get g(){ console.log("您已經(jīng)拿到年齡") return this.age + 10; }, set g(value){ console.log("您設(shè)置的年齡為: "+ this.age) }, } console.log(o) o.g // 您已經(jīng)拿到年齡 o.g = 10 // 您設(shè)置的年齡為: 23屬性的幾個(gè)特征
屬性除了名字和值之外,還包含一些表示他們可寫、可枚舉、可配置的特性。
數(shù)據(jù)屬性特性包括:
值 value
可寫性 writable 默認(rèn) true
可枚舉性 enumerable 默認(rèn) true
可配置性 configurable 默認(rèn) true
存取器屬性特性包括:
讀取 get
寫入 set
可沒舉性 enumerable
可配置性 configurable
為了實(shí)現(xiàn)屬性特性的查詢和設(shè)置操作,ECMAScript5 定義了一個(gè)名為 “屬性描述符”的對象
defineProperty() 設(shè)置某個(gè)屬性的特性
let obj = { name: "jhon", age: 23, } Object.defineProperty(obj,"name",{ value: "King", // 改寫默認(rèn)值 writable: false, // 不可修改屬性值 enumerable: true, // 可枚舉該屬性 configurable: true // 可配置該屬性 }) console.log(obj.name); // "King" obj.name = "Tom"; // 改寫不會成功 console.log( obj.name); // "King"
我們也可以設(shè)置器存取屬性特性:
let obj = { name: "jhon", age: 23, } // 我們將name設(shè)置成存取屬性器 Object.defineProperty(obj,"name",{ get: function(){ return "更改為存取屬性器" }, enumerable: true, // 可枚舉該屬性 configurable: true // 可配置該屬性 }) console.log(obj.name);
definePeoperties() 設(shè)置多個(gè)屬性的特性
我們可以使用 definePeoperties()來對多個(gè)屬性的特性進(jìn)行設(shè)置
let obj = { name: "jhon", age: 23, } Object.defineProperties(obj,{ name:{ get: function(){ return "更改為存取屬性器" }, enumerable: true, // 可枚舉該屬性 configurable: true // 可配置該屬性 }, age:{ writable: false, // 禁止改寫age } }) console.log(obj.name); //更改為存取屬性器 obj.age = 10; console.log(obj.age) // 23
getOwnpropertyDescriptor() 獲取某個(gè)對象自有屬性的屬性描述
let obj = { name:"jhon" } let descriptor = Object.getOwnPropertyDescriptor(obj,"name"); // Object {value: "jhon", writable: true, enumerable: true, configurable: true} console.log(descriptor)對象的三個(gè)屬性 1.原型屬性
對象的原型屬性是用來繼承屬性的,原型屬性實(shí)例創(chuàng)建之初就設(shè)置好了,通過對象直接量創(chuàng)建的對象使用對象 Object.prototype 作為他們的原型,通過new創(chuàng)建的對象,使用構(gòu)造函數(shù)prototype屬性作為它們的原型,通過Object.create() 創(chuàng)建的對象使用第一個(gè)參數(shù)(也可以是null)作為他們的原型
在ECMAScript5中,將對象作為參數(shù)傳入Object.getPrototypeOf() 可以查看他的原型。
let obja = { name:"jhon" } let proto = Object.getPrototypeOf(obja); console.log(proto) // 返回Objcet的原型
如果想要檢測一個(gè)對象是否是另一個(gè)對象的原型(或處于原型鏈中),可以使用isPrototypeOf() 方法。
function fun(name){ this.name = name } fun.prototype = function(){ console.log("原型") } let newFun = new fun("jhon"); // true console.log(fun.prototype.isPrototypeOf(newFun)) // 另外我們還可以通過 instanceof 來檢測一個(gè)對象是否是另一個(gè)對象的實(shí)例 console.log( newFun instanceof fun) // true2.類屬性
對象的雷屬性是一個(gè)字符串,用以表示對象的類型信息,我們可以通過一種間接的方法查詢它。
默認(rèn)的 toString() 方法(繼承自O(shè)bject.prototype) 返回這種格式的字符串:[object class]
我們可以通過 Object.prototype.toString.call() 來檢測對象的class
function fun (){ } let className = Object.prototype.toString.call(fun); console.log(className) // [object Function]3.可擴(kuò)展性
對象的可擴(kuò)展性用以表示是否可以給對象添加新屬相,所有內(nèi)置對象和自定義對象都是顯式可擴(kuò)展的。
這里我們可以通過 Object.esExtensible(),來判斷該對象是否可擴(kuò)展的。
let obj = { name: "jhon", age: 23, } // true 對象obj默認(rèn)是可擴(kuò)展的 console.log(Object.isExtensible(obj))
如果想將對象轉(zhuǎn)換為不可擴(kuò)展的,可以使用 Object.preventExtensions()
let obj = { name: "jhon", age: 23, } Object.preventExtensions(obj); obj.address = "BeiJing" console.log(obj) // obj并沒有多出一個(gè)address屬性 console.log(Object.isExtensible(obj)) // false
注意一旦將對象轉(zhuǎn)換為不可擴(kuò)展的,就無法在將其轉(zhuǎn)換回可擴(kuò)展的了。
如果想將對象轉(zhuǎn)換為不可擴(kuò)展的,并且對象的所有自有屬性都設(shè)置為不可配置(也就是封閉對象),可以使用 Object.seal()
判讀封閉對象可以使用Object.isSealed()
如果想將對象轉(zhuǎn)換為不可擴(kuò)展的,對象的所有自有屬性都設(shè)置為不可配置并且是只讀(也就是凍結(jié)對象),可以使用 Object.frozen(), 如果對象的存取器屬性具有setter方法,存取器屬性將不受影響。 使用Object.isFrozen() 來檢測對象是否凍結(jié)。
Object.preventExtensions()、Object.seal() 和Object.frozen()都返回傳入的對象。
對象的方法所用的JavaScript對象都從Objcet.prototype繼承屬性(除了那些不通過原型顯示創(chuàng)建的對象),以下這些方法我不在詳細(xì)介紹,因?yàn)樗麄冞€是比較常用的。
1.toString() 方法
2.toLocaleString() 方法
它僅僅調(diào)用了 toString() 方法并返回對應(yīng)值,Date和Number 類對該方法做了定制。
3.toJson() 方法
Objcet.prototype實(shí)際上沒有定義toJson() 方法,但對于需要執(zhí)行序列化的對象來說,JSON.stringify()方法會調(diào)用該方法。
4.valueOf 方法
當(dāng)JavaScript需要將對象轉(zhuǎn)換為某種原始值而非字符串的時(shí)候才會調(diào)用它。
結(jié)束參考書籍:《JavaScript權(quán)威指南》
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/89882.html
摘要:深入之繼承的多種方式和優(yōu)缺點(diǎn)深入系列第十五篇,講解各種繼承方式和優(yōu)缺點(diǎn)。對于解釋型語言例如來說,通過詞法分析語法分析語法樹,就可以開始解釋執(zhí)行了。 JavaScript深入之繼承的多種方式和優(yōu)缺點(diǎn) JavaScript深入系列第十五篇,講解JavaScript各種繼承方式和優(yōu)缺點(diǎn)。 寫在前面 本文講解JavaScript各種繼承方式和優(yōu)缺點(diǎn)。 但是注意: 這篇文章更像是筆記,哎,再讓我...
摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復(fù)雜性。寫一個(gè)符合規(guī)范并可配合使用的寫一個(gè)符合規(guī)范并可配合使用的理解的工作原理采用回調(diào)函數(shù)來處理異步編程。 JavaScript怎么使用循環(huán)代替(異步)遞歸 問題描述 在開發(fā)過程中,遇到一個(gè)需求:在系統(tǒng)初始化時(shí)通過http獲取一個(gè)第三方服務(wù)器端的列表,第三方服務(wù)器提供了一個(gè)接口,可通過...
摘要:下面就讓我們來一起深入了解下,為以后的策馬奔騰做好鋪墊。整數(shù)整數(shù),可以通過十進(jìn)制,八進(jìn)制,十六進(jìn)制的字面值來表示。對前面定義的八進(jìn)制和十六進(jìn)制數(shù)值進(jìn)行運(yùn)算浮點(diǎn)數(shù)浮點(diǎn)數(shù)其實(shí)就是我們通常所說的小數(shù),所以一定有個(gè)小數(shù)點(diǎn)。 Number 類型作為 JS 的基本數(shù)據(jù)類型之一,被應(yīng)用在程序中的各種場景,其重要性就如數(shù)字對于我們?nèi)粘I?。下面就讓我們來一起深入了解下,為以后的策馬奔騰做好鋪墊。 定義...
摘要:結(jié)合實(shí)際中的情況來看,有意或無意中涉及到隱式類型轉(zhuǎn)換的情況還是很多的。此外當(dāng)進(jìn)行某些操作時(shí),變量可以進(jìn)行類型轉(zhuǎn)換,我們主動進(jìn)行的就是顯式類型轉(zhuǎn)換,另一種就是隱式類型轉(zhuǎn)換了。 前言 相信剛開始了解js的時(shí)候,都會遇到 2 ==2,但 1+2 == 1+2為false的情況。這時(shí)候應(yīng)該會是一臉懵逼的狀態(tài),不得不感慨js弱類型的靈活讓人發(fā)指,隱式類型轉(zhuǎn)換就是這么猝不及防。結(jié)合實(shí)際中的情況來看...
摘要:模塊化是隨著前端技術(shù)的發(fā)展,前端代碼爆炸式增長后,工程化所采取的必然措施。目前模塊化的思想分為和。特別指出,事件不等同于異步,回調(diào)也不等同于異步。將會討論安全的類型檢測惰性載入函數(shù)凍結(jié)對象定時(shí)器等話題。 Vue.js 前后端同構(gòu)方案之準(zhǔn)備篇——代碼優(yōu)化 目前 Vue.js 的火爆不亞于當(dāng)初的 React,本人對寫代碼有潔癖,代碼也是藝術(shù)。此篇是準(zhǔn)備篇,工欲善其事,必先利其器。我們先在代...
摘要:設(shè)計(jì)模式是以面向?qū)ο缶幊虨榛A(chǔ)的,的面向?qū)ο缶幊毯蛡鹘y(tǒng)的的面向?qū)ο缶幊逃行┎顒e,這讓我一開始接觸的時(shí)候感到十分痛苦,但是這只能靠自己慢慢積累慢慢思考。想繼續(xù)了解設(shè)計(jì)模式必須要先搞懂面向?qū)ο缶幊?,否則只會讓你自己更痛苦。 JavaScript 中的構(gòu)造函數(shù) 學(xué)習(xí)總結(jié)。知識只有分享才有存在的意義。 是時(shí)候替換你的 for 循環(huán)大法了~ 《小分享》JavaScript中數(shù)組的那些迭代方法~ ...
閱讀 856·2023-04-25 21:21
閱讀 3237·2021-11-24 09:39
閱讀 3079·2021-09-02 15:41
閱讀 2009·2021-08-26 14:13
閱讀 1839·2019-08-30 11:18
閱讀 2786·2019-08-29 16:25
閱讀 517·2019-08-28 18:27
閱讀 1590·2019-08-28 18:17