JavaScript學習筆記整理:對象篇

語法


對象兩種定義形式javascript

  1. 聲明(文字)形式前端

  2. 構造形式java

//聲明(文字)形式
var myObj = {
    key: value
    // ...
}

//構造形式
var myObj = new Object();
myObj.key = value;

類型


對象是 JavaScript 的基礎。在 JavaScript 中一共有六種主要類型(術語語言類型算法

  • string編程

  • number數組

  • boolean安全

  • null微信

  • undefined編程語言

  • object函數

注意,簡單基本類型(string,number,boolean,undefined,null)自己並非對象。

null 有時會被當作對象類型,但這其實只是語言自己的一個 bug,即對 null 執行 typeof null 時會返回"object" 。實際上,null 自己是基本類型。

函數式對象的一個子類型,JavaScript 中的函數是「一等公民」

內置對象


JavaScript 中還有一些對象子類型,一般被稱爲內置對象。有些內置對象的名字看起來和簡單基礎類型同樣,不過實際上它們的關係更復雜,

  • String

  • Number

  • Boolean

  • Object

  • Function

  • Array

  • Date

  • RegExp

  • Error

這些內置函數能夠當作構造函數(由 new 產生的函數調用)來使用,從而能夠構造一個對應子類型的新對象。舉例來講:

var strPrimitive = "I am string"; //文字形式定義
typeof(strPrimitive);             // "string"
strPrimitive instanceof String;   // false

var strObject = new String("I am string");//構造形式定義
typeof(strObject);                        //"object"
strObject instanceof String;              //true

//檢查 sub-type 對象
Object.prototype.toString.call(strObject);//[object String]

Object.prototype.toString...咱們能夠認爲子類型在內部借用了 Object 中的 toString()方法。

因爲 javascript 弱類型的編程語言,原始值 "I am string"在必要的時候回自動把字符串字面量轉換成一個 String 對象。

思考下面代碼:

var strPrimitive = "I am a string";
console.log(strPrimitive.length);   //13
console.log(strPrimitive.charAt(3));//m

使用以上兩種方法,咱們均可以直接在字符串字面量上訪問屬性和方法,之因此能夠這麼作,是由於引擎自動把字面量轉換成 String 對象,因此能夠訪問屬性和方法。

null 和 undefined 沒有對應的構造形式,他們只有文字形式。相反,Date 只有構造,沒有文字形式。

內容


對象的內容是由一些存儲在特定命名位置的(任意類型的)值組成的,咱們稱之爲屬性。

var myObject = {
    a:2,
    'a_arr':3
}

myObject.a;    //2  屬性訪問
myObject["a"]; //2  鍵訪問

myObject["a_arr"];  //3

.操做符要求屬性命名知足標識符的命名規範,而["..."]語法能夠接受任意 UTF-8/Unicode 字符串爲屬性名

在對象中,屬性名永遠都是字符串。若是你使用 string(字面量)之外的其餘值做爲屬性名,那它首先會被轉換爲一個字符串。即便是數字也不例外,雖然在數組下標中使用的的確是數字,可是在對象屬性名中數字會被轉換成字符串,因此小心不要搞混對象和數字的用法。

var myObject = {}

myObject[true] = "foo";
myObject[3] = "bar";
myObject[myObject] = "baz";

myObject["true"];             //"foo"
myObject["3"];                //"bar"
myObject["[object Object]"];  //"baz"

可計算屬性名

ES6 增長了可計算屬性名,能夠再文字形式中使用[]包裹一個表達式來當作屬性名:

var prefix = "foo";

var myObject = {
    [prefix + "bar"]:"hello",
    [prefix + "baz"]:"world",
};

myObject["foobar"]; //hello
myObject["foobaz"]; //world

可計算屬性名最經常使用的場景多是 ES6的符號(Symbol)

它是一種新的基礎數據類型,包含一個不透明且沒法預測的值

數組

數組也支持[]訪問形式,數組期房的是數值下標,也就是說值存儲的位置(索引)是整數。

var arr =[1,"a",2];
arr.length;      //3
arr[0];          //1
arr[1];          //"a"

arr.x = "x";
arr.length;     //3
arr.x;          //"x"

arr["3"] = 3;
arr.length;     //4
arr[3];         //3

數組也是對象,因此雖然每一個下標都是整數,你仍然能夠給數組添加屬性

注意: 若是你試圖向數組添加一個屬性,當時屬性名「看起來」想一個數字,那他會編程一個數值下標(所以會修改數組的內容而不是添加一個屬性)

複製對象

javascript 初學者最多見的問題之一就是如何複製一個對象。實際上咱們沒法選擇默認一個複製算法。

舉例來講,思考一下這個對象:

function anotherFunction(){/**/}

var anohterObject = {
    c: true
};

var anotherArray = [];

var myObject = {
    a: 2,
    b: anotherObject,//引用,不是副本
    c: anotherArray,//另外一個引用
    d: anotherFunction
};

anotherArray.push( anotherObject, myObject);

對象複製時,咱們應該判斷它是淺複製仍是深複製。

對於淺拷貝來講,複製出的新對象中 a 的值會複製舊對象中 b、c、d 引用的對象是同樣的。

對於深拷貝來講,除了複製 myObject 之外還會複製 anotherObject 和 anotherArray。這時問題就來了,anotherArray 引用了 anotherObject 和 myObject,因此又須要複製 myObject,這樣就會因爲循環引用致使死循環。

有一巧妙的複製方法:

var newObj = JSON.parse(JSON.stringify( someObj ));

這種方法須要保證對象是 Json 安全的的,因此只適用於部分狀況。

相對於深複製,淺複製就很是易懂而且問題要少得多,因此 ES6定義了 Object.assign(...)方法來實現淺複製。

Object.assign() :第一個參數是目標對象,以後能夠跟一個或多個源對象。
它會遍歷一個或多個源對象的全部可枚舉的自由鍵並把他們複製到目標對象,最後返回目標對象。

var obj = Object.assign({},myObject);
obj.a;     //2
obj.b === anotherObject;//true
obj.c === anotherArray;//true
obj.d === anotherFunction;//true

屬性描述符

ES5以前,JavaScript 語言自己並無提供能夠直接檢測屬性特性的方法,好比判斷屬性是否可讀。

可是從 ES5開始,全部的屬性都具有了屬性描述符

思考下面代碼:

var myObject = {
    a:2
};

Object.getOwnPropertyDescriptor( myObject,"a" );
// {
//     value:2,
//     writable:true,
//     enumerable:true,
//     configurable:true
// }

能夠經過 Object.defineProperty(...) 添加或者修改一個已有屬性

Vue 的雙向綁定的基礎就是基於這個函數,重寫 get set 方法,在使用發佈-訂閱模式來完成數據的動態更新

詳情能夠看Vue 動態數據綁定(一)Vue 動態數據綁定三大難點

configurable:false 時:

  1. 它將不能再使用Object.defineProperty(...)進行配置

  2. 可是能夠將 writable的狀態由 true->false(沒法 false->true)

  3. delete 無效

不變性

對象常量

結合 writable:false 和 configurable:false

var myObject ={};

Object.defineProperty( myObject, "NUMBER",{
    value:42,
    writable:false,
    configurable:false
});

禁止擴展

若是你想禁止一個對象添加新屬性而且保存已有屬性,可使用 Object.preventExtensions(...)

var myObject ={
    a:2
}
Object.preventExtensions(myObject);

myObject.b =3;
myObject.b; //undefined

在費嚴格模式下,建立屬性 b 會靜默失敗。在嚴格模式下,將會拋出 TypeError 錯誤。

密封

Object.seal(...)會建立一個"密封"的對象,這個訪問實際上會在一個現有對象上調用 Object.preventExtensions(...)並把全部現有屬性標記爲configurable:false。

密封后,不能添加新屬性,也不能從新配置或刪除任何現有屬性(能夠修改屬性的值)

凍結

Object.freeze(...)會建立一個凍結對象,這個方法實際上會在一個現有對象調用 Object.seal(...)並把全部「數據訪問」屬性 wirtable:false,這樣就沒法修改他們的值了


更多內容能夠訂閱本人微信公衆號,一塊兒開啓前端小白進階的世界!

圖片描述

相關文章
相關標籤/搜索