詳解Javascript中的Object對象

来源:http://www.cnblogs.com/lrzw32/archive/2016/02/28/5225218.html
-Advertisement-
Play Games

Object是在javascript中一個被我們經常使用的類型,而且JS中的所有對象都是繼承自Object對象的。雖說我們平時只是簡單地使用了Object對象來存儲數據,並沒有使用到太多其他功能,但是Object對象其實包含了很多很有用的屬性和方法,尤其是ES5增加的方法,因此,本文將從最基本的介紹...


Object是在javascript中一個被我們經常使用的類型,而且JS中的所有對象都是繼承自Object對象的。雖說我們平時只是簡單地使用了Object對象來存儲數據,並沒有使用到太多其他功能,但是Object對象其實包含了很多很有用的屬性和方法,尤其是ES5增加的方法,因此,本文將從最基本的介紹開始,詳細說明瞭Object的常用方法和應用。

基礎介紹

創建對象

首先我們都知道,對象就是一組相似數據和功能的集合,我們就是用它來模擬我們現實世界中的對象的。那在Javascript中,創建對象的方式通常有兩種方式:構造函數和對象字面量。

new構造函數法
1 var person = new Object();
2 person.name = "狼狼的藍胖子";
3 person.age = 25;

這種方式使用new關鍵字,接著跟上Object構造函數,再來給對象實例動態添加上不同的屬性。這種方式相對來說比較繁瑣,一般推薦使用對象字面量來創建對象。

對象字面量

對象字面量很好理解,使用key/value的形式直接創建對象,簡潔方便。

1 var person = {
2     name: “狼狼的藍胖子”,
3     age: 25
4 };

這種方式直接通過花括弧將對象的屬性包起來,使用key/value的方式創建對象屬性,每個屬性之間用逗號隔開。
註意:如果是最後一個屬性,後面就不要加逗號,因為在一些舊的瀏覽器下會報錯。

對象實例的屬性和方法

不管通過哪種方式創建了對象實例後,該實例都會擁有下麵的屬性和方法,下麵將會一一說明。

constructor屬性

constructor屬性是保存當前對象的構造函數,前面的例子中,constructor保存的就是Object方法。

1 var obj1 = new Object();
2 obj1.id = "obj1";
3 var obj2 = {
4     "id": "obj2"
5 };
6 
7 console.log(obj1.constructor);//function Object(){}
8 console.log(obj2.constructor);//function Object(){}
hasOwnProperty(propertyName)方法

hasOwnProperty方法接收一個字元串參數,該參數表示屬性名稱,用來判斷該屬性是否在當前對象實例中,而不是在對象的原型鏈中。我們來看看下麵這個例子:

1 var arr = [];        
2 console.log(arr.hasOwnProperty("length"));//true
3 console.log(arr.hasOwnProperty("hasOwnProperty"));//false

在這個例子中,首先通過定義了一個數組對象的實例arr,我們知道數組對象實際是通過原型鏈繼承了Object對象,然後擁有自己的一些屬性,我們通過hasOwnProperty方法判斷length是arr自己的屬性,而hasOwnProperty是在原型鏈上的屬性。
hasOwnProperty方法可以和for..in結合起來獲取對象自己的key。

isPrototypeOf(Object)方法

isPrototype方法接收一個對象,用來判斷當前對象是否在傳入的參數對象的原型鏈上,說起來有點抽象,我們來看看代碼。

1 function MyObject() {}
2 var obj = new MyObject();
3 console.log(Object.prototype.isPrototypeOf(obj));

我們知道MyObject是繼承自Object對象的,而在JS中,繼承是通過prototype來實現的,所以Object的prototype必定在MyObject對象實例的原型鏈上。

propertyIsEnumerable(prototypeName)方法

prototypeIsEnumerable用來判斷給定的屬性是否可以被for..in語句給枚舉出來。看下麵代碼:

1 var obj = {
2     name: "objName"
3 }  
4 for (var i in obj) {
5     console.log(i);
6 }

執行這段代碼輸出字元串“name”,這就說明通過for…in語句可以得到obj的name這個屬性,但是我們知道,obj的屬性還有很多,比如constructor,比如hasOwnPrototype等等,但是它們沒有被輸出,說明這些屬性不能被for…in給枚舉出來,可以通過propertyIsEnumerable方法來得到。

1 console.log(obj.propertyIsEnumerable("constructor"));//false

判斷“constructor”是否可以被枚舉,輸出false說明無法被枚舉出來。

toLocaleString()方法

toLocalString方法返回對象的字元串表示,和代碼的執行環境有關。

1 var obj = {};
2 console.log(obj.toLocaleString());//[object Object]  
3 
4 var date = new Date();
5 console.log(date.toLocaleString());//2016/2/28 下午1:39:27
toString()方法

toString用來返回對象的字元串表示。

1 var obj = {};
2 console.log(obj.toString());//[object Object]
3 
4 var date = new Date();
5 console.log(date.toString());//Sun Feb 28 2016 13:40:36 GMT+0800 (中國標準時間)
valueOf()方法

valueOf方法返回對象的原始值,可能是字元串、數值或bool值等,看具體的對象。

 1 var obj = {
 2     name: "obj"
 3 };
 4 console.log(obj.valueOf());//Object {name: "obj"}
 5 
 6 var arr = [1];
 7 console.log(arr.valueOf());//[1]
 8 
 9 var date = new Date();
10 console.log(date.valueOf());//1456638436303

如代碼所示,三個不同的對象實例調用valueOf返回不同的數據。

屬性的類型

在Javascript中,屬性有兩種類型,分別是數據屬性和訪問器屬性,我們來看看這兩種屬性具體是什麼東西。

數據屬性

數據屬性我們可以理解為我們平時定義對象時賦予的屬性,它可以進行讀和寫。但是,ES5中定義了一些特性,這些特性是用來描述屬性的各種特征,特性是內部值,不能直接訪問到。特性通過用兩對方括弧表示,比如[[Enumerable]]。屬性的特性會有一些預設值,要修改特性的預設值,必須使用ES5定義的新方法Object.defineProperty方法來修改。
數據屬性有4個描述其特征的特性,下麵將依次說明每一個特性:
(1)[[Configurable]]:該特性表示是否可以通過delete操作符來刪除屬性,預設值是true。

1 var obj = {};
2 obj.name = "myname";
3 
4 delete obj.name;
5 console.log(obj.name);//undefined

這段代碼很明顯,通過delete刪除了obj的name屬性後,我們再訪問name屬性就訪問不到了。
我們通過Object.defineProperty方法來修改[[Configurable]]特性。

1 var obj = {};
2 obj.name = "myname";
3 Object.defineProperty(obj, "name", {
4     configurable: false
5 })                
6 
7 delete obj.name;
8 console.log(obj.name);//myname

通過將configurable特性設置成false之後,delete就無法刪除name屬性了,如果在嚴格模式下,使用delete去刪除就會報錯。

(2)[[Enumerable]]:表示是否能夠通過for…in語句來枚舉出屬性,預設是true
我們來看看前面的例子:

1 var obj = {
2     name: "objName"
3 }  
4 for (var i in obj) {
5     console.log(i);//name
6 }

這段代碼只輸出了name屬性,我們來將constructor屬性的[[Enumerable]]設置為true試試。

 1 var obj = {
 2         name: "objName"
 3 }
 4 Object.defineProperty(obj, "constructor", {
 5     enumerable: true
 6 })
 7 
 8 for (var i in obj) {
 9     console.log(i);//name,constructor
10 }
11 console.log(obj.propertyIsEnumerable("constructor"));//true

這段代碼中,for…in迴圈得到了name和constructor兩個屬性,而通過propertyIsEnumerable方法來判斷constructor也返回了true。

(3)[[Writable]]:表示屬性值是否可以修改,預設為true
如果[[Writable]]被設置成false,嘗試修改時將沒有效果,在嚴格模式下會報錯

(4)[[Value]]:表示屬性的值,預設為undefined

我們通過一個簡單的例子來看看這兩個特性:

 1 var obj = {
 2     name: "name"
 3 };
 4 console.log(obj.name);//name        
 5 
 6 Object.defineProperty(obj, "name", {
 7     value: "newValue",
 8     writable: false
 9 })
10 console.log(obj.name);//newValue
11 
12 obj.name = "oldValue";
13 console.log(obj.name);//newValue

我們首先定義了obj對象的name屬性值為“name”,然後通過defineProperty方法來修改值,並且將其設置為不可修改的。接著我們再修改name屬性的值,可以發現修改無效。
如果我們通過defineProperty來修改name屬性的值,是否可以修改呢?答案是可以的:

1 Object.defineProperty(obj, "name", {
2     value: "oldValue"
3 })
4 console.log(obj.name); //oldValue
訪問器屬性

訪問器屬性有點類似於C#中的屬性,和數據屬性的區別在於,它沒有數據屬性的[[Writable]]和[[Value]]兩個特性,而是擁有一對getter和setter函數。
[[Get]]:讀取屬性時調用的函數,預設是undefined
[[Set]]:設置屬性時調用的函數,預設是undefined
getter和setter是一個很有用的東西,假設有兩個屬性,其中第二個屬性值會隨著第一個屬性值的變化而變化。這種場景在我們平時的編碼中起始是非常常見的。在之前的做法中,我們往往要去手動修改第二個屬性的值,那現在我們就可以通過get和set函數來解決這個問題。看下麵這個例子:

 1 var person = {
 2     age: 10
 3 }
 4 
 5 Object.defineProperty(person, "type", {
 6     get: function () {
 7         if (person.age > 17) {
 8             return "成人";
 9         }
10         return "小孩";
11     }
12 })
13 
14 console.log(person.type);//小孩
15 
16 person.age = 18;
17 console.log(person.type);//成人

通過修改age的值,type的值也會相應的修改,這樣我們就不用再手動的去修改type的值了。
下麵這種方式也是可以實現同樣的效果:

 1 var person = {
 2     _age: 10,
 3     type: "小孩"
 4 } 
 5 
 6 Object.defineProperty(person, "age", {
 7     get: function () {
 8         return this._age;
 9     },
10     set: function (newValue) {
11         this._age = newValue;
12         this.type = newValue > 17 ? "成人" : "小孩";
13     }
14 })
15 console.log(person.type);
16 
17 person.age = 18;
18 console.log(person.type);

關於訪問器屬性,有幾點要註意:
1、嚴格模式下,必須同時設置get和set
2、非嚴格模式下,可以只設置其中一個,如果只設置get,則屬性是只讀的,如果只設置set,屬性則無法讀取
3、Object.defineProperty是ES5中的新方法,IE9(IE8部分實現,只有dom對象才支持)以下瀏覽器不支持,一些舊的瀏覽器可以通過非標準方法defineGetter()和defineSetter()來設置,這裡就不說明瞭,有興趣的同學可以查找相關資料。

特性操作的相關方法

ES5提供了一些讀取或操作屬性特性的方法,前面用到的Object.defineProperty就是其中之一。我總結了一些比較常用的方法如下:

(1)Object.defineProperty
定義一個對象的屬性,這個方法前面我們已經用到多次,簡單說說其用法。

1 Object.defineProperty(obj,propName,descriptor);

defineProperty有點類似於定於在Object上的靜態方法,通過Object直接調用,它接收3個參數:
obj:需要定義屬性的對象
propNane:需要被定義的屬性名稱
defineProperty:屬性描述符,包含一些屬性的特性定義
例子如下:

1 var obj = {};
2 Object.defineProperty(obj, "name", {
3     value: "name",
4     configurable: true,
5     writable: true,
6     enumerable: true
7 });

(2)Object.defineProperties
和defineProperty類似,是用來定義對象屬性的,不同的是它可以用來同時定義多個屬性,我們通過命名也可以看出來,用法如下:

 1 var obj = {};
 2 Object.defineProperty(obj, {
 3     "name": {
 4         value: "name",
 5         configurable: true,
 6         writable: true,
 7         enumerable: true
 8     },
 9     "age": {
10         value: 20 
11     }
12 });

(3)Object.getOwnPropertyDescriptor
ES5中還提供了一個讀取特性值的方法,該方法接收對象及其屬性名作為兩個參數,返回一個對象,根據屬性類型的不同,返回對象會包含不同的值。

 1 var person = {
 2     _age: 10,
 3     type: "小孩"
 4 }
 5 Object.defineProperty(person, "age", {
 6     get: function () {
 7         return this._age;
 8     },
 9     set: function (newValue) {
10         this._age = newValue;
11         this.type = newValue > 17 ? "成人" : "小孩";
12     }
13 })
14 
15 console.log(Object.getOwnPropertyDescriptor(person, "type"));//Object {value: "成人", writable: true, enumerable: true, configurable: true}
16 console.log(Object.getOwnPropertyDescriptor(person, "age")); //Object {enumerable: false, configurable: false, get: function(),set: function ()}

Object的方法

在ES5中,Object對象上新增了一批方法,這些方法可以直接通過Object進行訪問,前面用到的defineProperty就是新增的方法之一。除此之外還有很多方法,我將其總結歸納如下:

對象創建型方法

Object.create(proto, [propertiesObject])

在前面我們提到,創建一個對象有兩種方法:構造函數和對象字面量。
這兩種方法有一個缺點就是:如果要創建多個對象,寫起來很繁瑣,所以後來就有了一種創建自定義構造函數的方法來創建對象,如下所示:

1 function Person(name, age) {
2     this.name = name;
3     this.age = age;
4 }
5 
6 var person = new Person("Jack", 15);

這種方式可以很方便的創建多個同樣的對象,也是目前比較常用的方法。

ES5提供的Object.create方法也是一個創建對象的方法,這個方法允許為創建的對象選擇原型對象,不需要定義一個構造函數。用法如下:

1 var obj = Object.create(Object.prototype, { 
2     name: {
3         value: "Jack"
4     }
5 })
6 console.log(obj.name);//Jack

這個方法接收的第一個參數作為被創建對象的原型,第二個參數是對象的屬性。註意:在這個例子中,name屬性是無法被修改的,因為它沒有設置writable特性,預設則為false。
個人看法:Object.create這種創建對象的方式略顯繁瑣,除非是需要修改屬性的特性,否則不建議使用這種方式創建對象。

屬性獲取型方法

Object.keys

Object.keys是用來獲取給定對象的所有可枚舉的自身屬性的屬性名,它返回一個數組。

 1 function Parent() {
 2     this.lastName = "Black"
 3 }
 4 function Child(firstName) {
 5     this.firstName = firstName;
 6 }
 7 Child.prototype = new Parent();
 8 
 9 var son = new Child("Jack");
10 console.log(Object.keys(son));//["firstName"]

代碼中返回了firstName,並沒有返回從prototype繼承而來的lastName和不可枚舉的相關屬性。
在一些舊的瀏覽器中,我們可以使用hasOwnProperty和for…in來達到類似的效果。

 1 Object.keys = Object.keys ||
 2     function (obj) {
 3         var keys = [];
 4         for (var key in obj) {
 5             if (obj.hasOwnProperty(key)) {
 6                 keys.push(key);
 7             }
 8         }
 9         return keys;
10     }
Object.getOwnPropertyNames()

getOwnPropertyNames用來獲取對象自身的所有屬性,包括可枚舉和不可枚舉的所有屬性,如下所示:

 1 function Parent() {
 2     this.lastName = "Black"
 3 }
 4 function Child(firstName) {
 5     this.firstName = firstName;
 6 }
 7 Child.prototype = new Parent();
 8 
 9 var son = new Child("Jack");
10 Object.defineProperty(son, "age", {
11     enumerable: false
12 })
13 console.log(Object.keys(son));//["firstName"]  
14 console.log(Object.getOwnPropertyNames(son));//["firstName", "age"]

我們定義給son對象定義了一個不可枚舉的屬性age,然後通過keys和getOwnPropertyNames兩個方法來獲取屬性列表,能明顯看出了兩者區別。

屬性特性型方法

這個主要是前面提到的三個方法:defineProperty,defineProperties和getOwnPropertyDescriptor三個方法

對象限制型方法

ES5中提供了一系列限制對象被修改的方法,用來防止被某些對象被無意間修改導致的錯誤。每種限制類型包含一個判斷方法和一個設置方法。

阻止對象擴展

Object.preventExtensions()用來限制對象的擴展,設置之後,對象將無法添加新屬性,用法如下:

1 Object.preventExtensions(obj);

該方法接收一個要被設置成無法擴展的對象作為參數,需要註意兩點:
1、對象的屬性不可用擴展,但是已存在的屬性可以被刪除
2、無法添加新屬性指的是無法在自身上添加屬性,如果是在對象的原型上,還是可以添加屬性的。

 1 function Person(name) {
 2     this.name = name;
 3 }
 4 var person = new Person("Jack");
 5 Object.preventExtensions(person);
 6 
 7 delete person.name;
 8 console.log(person.name);//undefined
 9 
10 Person.prototype.age = 15;
11 console.log(person.age);//15

Object.isExtensible方法用來判斷一個對象是否可擴展,預設情況是true

將對象密封

Object.seal可以密封一個對象並返回被密封的對象。
密封對象無法添加或刪除已有屬性,也無法修改屬性的enumerable,writable,configurable,但是可以修改屬性值。

1 function Person(name) {
2     this.name = name;
3 }
4 var person = new Person("Jack");
5 Object.seal(person);
6 delete person.name;
7 console.log(person.name);//Jack

將對象密封後,使用delete刪除對象屬性,還是可以訪問得到屬性。

通過Object.isSealed可以用來判斷一個對象是否被密封了。

凍結對象

Object.freeze方法用來凍結一個對象,被凍結的對象將無法添加,修改,刪除屬性值,也無法修改屬性的特性值,即這個對象無法被修改。

 1 function Person(name) {
 2     this.name = name;
 3 }
 4 var person = new Person("Jack");
 5 Object.freeze(person);
 6 
 7 delete person.name;
 8 console.log(person.name);//Jack
 9 
10 Person.prototype.age = 15;
11 console.log(person.age);//15

分析上面的代碼我們可以發現,被凍結的對象無法刪除自身的屬性,但是通過其原型對象還是可以新增屬性的。

通過Object.isFrozen可以用來判斷一個對象是否被凍結了。

可以發現:這三個限制對象的方法的限製程度是依次上升的。

總結

Object雖說是一個我們平時開發中最經常用到的對象,但是它的很多功能還沒有被我們挖掘出來。本文首先介紹了Object的基本使用,接著介紹了一些比較少使用到的屬性特性,最後分析了一些比較常用的方法,尤其是ES5中提供的新方法。歡迎大家交流!!

 

本文地址:http://luopq.com/2016/02/28/Object-in-Javascript/,轉載請註明


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...