iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 25
0

這個章節主要是介紹物件的結構,和他本身所擁有的各種預設的方法。

語法

有兩種形式

  1. 宣告式 ( declarative,或稱字面值 literal )
  2. 建構式 ( constructed form )
var declarativeObj = {
    key: value
}

var constructedObj = new Object();
constructedObj.key = value;

差異

  • 字面值可以一次整理 key/value pair。
  • 建構式要一條一條加。

型別

複習。
六大主要型別 ( symbol 不算在內 )。

「 JavaScript 的一切都是物件 」,這顯然不是真確的。

  • simple primitives - string, number, boolean, null, undefined
  • complex primitives - object, ( function, array )

其中 null 是 primitive type,別被 typeof null 混淆了。

內建物件

複習 Native。
可以當作建構器使用。

簡單分類

  • String, Number, Boolean
  • Object, Function, Array, RegExp
  • Error, Date
var strPrimitive = "I am a string";
typeof strPrimitive;             // "string"
strPrimitive instanceof String;  // false ??!!?!?

var strObject = new String( "I am a string" );
typeof strObject;            // "Object"
strObject instanceof String; // true ??!!?!?!!?

之後會講解 Object.prototype.toString...的部分運作的細節。


為什麼純值會有方法可以用?

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

在純值上呼叫屬性和方法,JS會強制轉型為 string 物件。

其他是否能呼叫建構式,書上又再複習了一下。

PS. 書上慣用特性來稱呼 property,但 Tony 習慣用屬性

內容

物件的內容 ( contents ) 由值 ( value ) 構成。
儲存在命名過的位置 ( locations ),叫做屬性 ( properties )。

但真正儲存在容器中的,是屬性名稱,是參考 ( referances )。

有兩種用屬性取得值的方式

  1. 屬性存取 ( property access)
  2. 鍵值存取 ( key access )
var myObj = {
    a: 2
};

myObj.a;    // 2 property access ( 後續以這個為主 )
myObj["a"]; // 2 key access

[..] 的特性

  • 相容於任何 UTF-8 或 Unicode 做屬性名稱。ex: -, !
  • 可以指定 ( assign )值。
  • 用了除了 string 以外的型別,會被強制轉型為 string。

屬性名稱可以計算

這對 Tony 來說是很神奇的方法,看看吧。

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

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

屬性 VS. 方法

嚴格來說,函式永遠都不會屬於物件。
每次存取一個物件上的屬性,那就是一次屬性存取,不管是什麼值,他都不會變成方法。

function foo() {
    console.log( "foo" );
}
var someFoo = foo;

var myObject = {
    someFoo: foo
};

foo;       // 直接呼叫
somefoo;   // 藉由函式運算式呼叫
myObject;  // 藉由物件屬性呼叫

以上都會出現 function foo(){..},都是指向 foo 的不同參考。

在 JavaScript 中,函式 ( function ) 與 方法 ( method ) 是可以互換的名詞。

就算值使用函式運算式也是多個參考之一。

var myObject = {
    foo: function foo() {
        console.log( "foo" );
    }
}

var someFoo = myObject.foo;

someFoo;      // function foo(){..}
myObject.foo; // function foo(){..}

為什麼在寫一次?
因為 foo: function foo(){..},在 ES6 有其他寫法。

陣列

陣列也是用鍵值存取 [..] 的形式。和物件的差別在使用數值索引。以非負整數來編號 0, 1, .., n

列出特性

  • 可以新增屬性到陣列上。( 非負整數以外的字串 )
  • 新增的屬性不算在陣列的長度值裡。( length )
  • 使用數字字串 "3" 當鍵值,會當成是 number 索引使用。

複製物件

如何複製一個物件?

這邊牽扯到 深拷貝淺拷貝

簡單的例子,說明淺拷貝。

var a = [1, [2, 3]];
var b = Array.from(a);
b[0] = 4;
a;     // [1, [2, 3]]
b;     // [4, [2, 3]]  第一層已經拷貝了 
b[1][0] = 10;
a;     // [1, [10, 3]]
b;     // [1, [10, 3]] 內層依然指向相同的位置

淺拷貝,會把第一層的值,另外做一個複製品。其他層的會用相同的參考。

那深拷貝呢?
從 a 物件 拷貝一個 b 物件
當修改 b 物件的任何內容,不管多深,a 的內容都不會跟著變動。

var anObject = {
    b: true
};

function aFunction() { /*..*/ }

var anArray = [];   // 創建 Object, Function, Array

var obj = {
    a: 2,
    b: anObject,
    c: aFunction,
    d: anArray
};

anArray.push( anObject, obj );

會有個無限的循環參考

而上面的例子展現了循環參考( circular reference )。

這和深拷貝和淺拷貝有什麼關係?
( Tony 還沒意會過來,但覺得這樣能用循環參考很酷 )

那如何複製物件呢?

  1. 用深拷貝處理
    可以使用
var newObj = JSON.parse( JSON.stringify( obj ) );

把物件轉成 JSON 字串,再重新剖析成物件,並存在新物件中。

  1. 用淺拷貝處理

assign( target, source );
可以將 source 的可列舉自有鍵值,複製到 target 上。

var newObj = Object.assign( {}, obj );

接下來呢?

會講到屬性描述器,取值送值和迭代。
屬性描述器有打到 Tony 的腦洞啊!

參考資料

  1. 你所不知道的JS
  2. [Javascript] 關於 JS 中的淺拷貝和深拷貝

上一篇
Day24 - 哪個 this 比較大?
下一篇
Day26 - 物件的屬性描述器
系列文
你為什麼不問問神奇 JavaScript 呢?30

尚未有邦友留言

立即登入留言