js資料型別--object

hf_驕陽似火發表於2018-09-02

系列文章

1 、從資料型別講原型原型鏈

內容回顧

在JavaScript中,資料型別可以分為原始型別以及引用型別

其中原始型別包括string,number, boolean, null, undefined, symbol(ES6新增,表示獨一無二的值),這6種資料型別是按照值進行分配的,是存放在(stack)記憶體中的簡單資料段,可以直接訪問,資料大小確定,記憶體空間大小可以分配。

引用型別包括function,object,array等可以可以使用new建立的資料,又叫物件型別,他們是存放在(heap)記憶體中的資料,如var a = {},變數a實際儲存的是一個指標,這個指標指向對記憶體中的資料 {}

物件型別包含但不限於object、function、array、string、boolean、number、date、regexp。

這一篇文章則主要講object型別的功能及用法。

一、開篇

在js中,function型別的資料叫函式,又叫方法,array型別的資料叫陣列,而object型別的資料就叫物件,需要根據實際情況來區分一些文章中的物件與物件型別。

什麼是物件?

物件就是封裝一個事物的屬性和功能的程式結構,是記憶體中儲存多個屬性和方法的一塊儲存空間。

什麼是物件導向程式設計?

物件導向程式設計(OOP)是一種程式設計思想,是一種對現實世界理解和抽象的方法,是計算機程式設計技術發展到一定階段後的產物。它的特徵是封裝、繼承、多型,優點是易維護、易擴充套件、質量高、效率高。通俗的講就是以物件為基礎來進行軟體開發的思想,舉個例子,比如我們做一個雨滴落地的動畫,那麼可以用物件導向的方法把雨滴看成一個物件,這個物件中包含顏色、形狀、大小、速度等屬性,同時還包括了開始下落、下落過程、落地後等方法 。

二、建立物件

1、直接量(字面量)建立

因為這種建立方法很直接,所以叫直接量,又叫字面量

var obj = {a:1}
複製程式碼

2、建構函式建立

這一方法建立物件又叫工廠函式建立物件,顧名思義就是批量生產,使用這個方法我們需要用到關鍵字new。執行環境內建了一個物件的建構函式—Object,我們直接使用就可以了

var  obj = new Object({a:1}); 
複製程式碼

上面的例子中,我們在Object中加了一個引數,這個引數是初始化的值(將引數賦值給新物件,不是克隆),這個引數的格式需要符合物件的格式要求,如果你傳入了一個別的型別的引數,那麼建立的就不是object型別的物件了(資料型別還是物件,但不是object)

var a = new Object('a'); // String {"a"}
var b = new Object('{a:1}'); // String {"{a:1}"}
var c = new Object(1); // Number {1}
複製程式碼

另外,如果沒有引數需要傳入,則Object後面的()可以省略,即

var a = new Object; //{}
複製程式碼

除了環境自帶的建構函式,我們還可以根據實際需求自定義建構函式

function Student(name,age){
	this.name = name
	this.age = age
}
var xm = new Student(‘xiaoM’,12); // Student {name: "xiaoM", age: 12}
var xh = new Student(‘xiaoH’,14); // Student {name: "xiaoH", age: 14}
複製程式碼

3、Object.create建立物件

我們知道,Object是一個建構函式,而js中函式也是物件型別的資料,所以函式也是有屬性的,而create就是其中的一個方法,該方法的作用是根據現有的物件新建立一個子物件。

var son=Object.create(父物件);
複製程式碼

這句話做了2件事: 1. 建立空物件son 2. 設定son的__proto__指向父物件

上面的解釋其實是有一點瑕疵的,因為我們不但可以根據現有的物件來建立子物件,還可以根據null來建立子物件,我這麼說是想強調下null不是一個物件,雖然Object.prototype繼承自null,但null也不是一個物件,你可能會說:

typeof null === "object" // true
Object.prototype.toString(null) === "[object Object]" // true
複製程式碼

但它確實不是一個物件,這是js的歷史遺留問題,詳細可以看這裡 typeof null的前世今生

繼續回到我們的文章上來,如果我們使用了null作為父物件來建立一個子物件,那麼

子物件.__proto__ === null //true
複製程式碼

和Object.prototype一個級別的!!!不過不同的是,Object.prototype是執行環境封裝的,裡面天生有一些屬性及方法,而用null建立的子物件就像一個新生兒一樣,裡面乾乾淨淨的,什麼都沒有。

使用null建立子物件的缺點就是我們不再能夠使用Object.prototype自帶的一些屬性及API,如果需要的話,你就得自己去實現了,好處就是這個子物件是一個乾乾淨淨的物件,裡面的一些屬性及方法可以按照自己的想法來,不用擔心與原型鏈上屬性重名,造成變數汙染,多用於儲存資料。

4、ES6 的 class建立物件

class關鍵字是ES6引入的概念,用於定義類(物件),用法如下:

//定義類
class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  toString() {
    return '(' + this.x + ', ' + this.y + ')';
  }
}
複製程式碼

可以看到裡面有一個constructor方法,這就是構造方法,而this關鍵字則代表例項物件Point。

Point類除了構造方法,還定義了一個toString方法。注意,定義“類”的方法的時候,前面不需要加上function這個關鍵字,直接把函式定義放進去了就可以了。另外,方法之間不需要逗號分隔,加了會報錯。

ES6 的類,完全可以看作建構函式的另一種寫法。

class Point {
  // ...
}

typeof Point // "function"
Point === Point.prototype.constructor // true
複製程式碼

上面程式碼表明,類的資料型別就是函式,類本身就指向建構函式。使用的時候,也是直接對類使用new命令,跟建構函式的用法完全一致。

var point = new Point(2,3);
point.toString() // "(2,3)"
複製程式碼

這裡執行new Point(2,3)可以看作是執行了類Point裡的constructor方法為x,y賦值,同時把toString函式掛到Point.prototype上去

建構函式的prototype屬性,在 ES6 的“類”上面繼續存在。事實上,類的所有方法都定義在類的prototype屬性上面。

更多class的使用說明及其他es6的特性看一看阮一峰老師的ECMAScript 6 入門,講的很詳細,上面關於class的講解也都摘抄自阮一峰老師的這本書裡。

三、物件的遍歷

遍歷就是依次處理該資料結構的所有成員,JavaScript中的遍歷是針對表示“集合”的資料結構,主要是陣列(Array)和物件(Object),ES6 又新增了Map和Set。其中物件的遍歷主要是使用for…in結構,用法如下:

var a = {a:1,b:2}
for(var k in a){
	console.log(k)
}
//a b
複製程式碼

for…in 的使用中,我們需要小心的是,他不但可以遍歷自己的私有屬性,還會遍歷其原型鏈上的公有屬性。

私有屬性:物件本身所具有的屬性 公有屬性:包括私有屬性在內的其原型鏈上的可訪問到的屬性

var a = {a:1,b:2}
a.__proto__ = {c:4}
for(var k in a){
	console.log(k)
}
//a b c
複製程式碼

我們可以通過obj.hasOwnProperty來判斷一個屬性是不是物件的自有屬性

for(var k in a){
	if( a.hasOwnProperty( k ) ){
        console.log(k)
	}
}
//a b
複製程式碼

以上,我們把所有可以遍歷到的屬性叫做可列舉屬性,那麼什麼是可列舉屬性不可列舉屬性呢?

可列舉屬性是指那些內部 “可列舉” 標誌(enumerable)設定為 true 的屬性,對於通過直接的賦值和屬性初始化的屬性,該標識值預設為即為 true,對於通過 Object.definePropertyObject.create 等定義的屬性,該標識值預設為 false。可列舉的屬性可以通過 for...in 迴圈進行遍歷(除非該屬性名是一個 Symbol)。相對的,不可列舉屬性就是用 for...in 遍歷不到的屬性,js中內建屬性是遍歷不到的。

四、Object/Object.prototype常用API介紹

我們知道無論是object、function、array還是string、boolean、number、date,他們都是物件型別的資料,我們在可以使用console.dir()來檢視一個資料的結構。這樣我們就可以很全面的看到一個物件上有哪些屬性了。

1、Object建構函式的方法

Object是object的建構函式,我們使用console.dir(Object),可以看到:

Object

Object.assign() 通過複製一個或多個物件來建立一個新的物件。

Object.create() 使用指定的原型物件和屬性建立一個新物件。

Object.defineProperty() 給物件新增一個屬性並指定該屬性的配置。

Object.defineProperties() 給物件新增多個屬性並分別指定它們的配置。

Object.entries() 返回給定物件自身可列舉屬性的[key, value]陣列。

Object.freeze() 凍結物件:其他程式碼不能刪除或更改任何屬性。

Object.getOwnPropertyDescriptor() 返回物件指定的屬性配置。

Object.getOwnPropertyNames() 返回一個陣列,它包含了指定物件所有的可列舉或不可列舉的屬性名。

Object.getOwnPropertySymbols() 返回一個陣列,它包含了指定物件自身所有的符號屬性。

Object.getPrototypeOf() 返回指定物件的原型物件。

Object.is() 比較兩個值是否相同。所有 NaN 值都相等(這與==和===不同)。

Object.isExtensible() 判斷物件是否可擴充套件。

Object.isFrozen() 判斷物件是否已經凍結。

Object.isSealed() 判斷物件是否已經密封。

Object.keys() 返回一個包含所有給定物件自身可列舉屬性名稱的陣列。

Object.preventExtensions() 防止物件的任何擴充套件。

Object.seal() 防止其他程式碼刪除物件的屬性。

Object.setPrototypeOf() 設定物件的原型(即內部[[Prototype]]屬性)。

Object.values() 返回給定物件自身可列舉值的陣列。

2、Object 例項和Object 原型物件的方法

Object.prototype本身是一個物件,所以我們使用console.log(Object.prototype),就可以看到他的結構:

Object.prototype

Object.prototype.hasOwnProperty() 返回一個布林值 ,表示某個物件是否含有指定的屬性,而且此屬性非原型鏈繼承的。

Object.prototype.isPrototypeOf() 返回一個布林值,表示指定的物件是否在本物件的原型鏈中。

Object.prototype.propertyIsEnumerable() 判斷指定屬性是否可列舉

Object.prototype.toLocaleString() 直接呼叫 toString()方法。

Object.prototype.toString() 返回物件的字串表示。

Object.prototype.valueOf() 返回指定物件的原始值。

由於 Object 以及 Object.prototype 的屬性太多,這裡就不詳細闡述了,感興趣的小夥伴可以到 MDN 觀看,強烈建議把Object、Object.prototype的屬性都過一遍。

相關文章