對象,垃圾回收

創建對象的方式

1. 使用構造函數

 let user = new Object(); // 使用構造函數

2. 使用字面量:本質上還是調用構造函數

		let user2 = {
            name: '葉葉'
        };

對象屬性

1. 普通屬性

  		let user3 = {
            name: 'li葉葉', // 鍵"name",值'li葉葉'
            age: 30, // 鍵"age",值30
            /* 可以使用多個單詞作爲屬性名,但是必須加上引號 */
            'likes birds': true,
            /* 最後一個屬性後面可以添加一個逗號,叫做尾逗號,或者懸掛逗號,方便我們添加,刪除,移動屬性 */
        };

2. 計算屬性 在對象字面量中使用方括號.這樣的屬性叫做計算屬性

		let fruit = prompt("請選擇你要購買的水果", 'apple');

        let bag = {
            [fruit]: 5, // 屬性名從fruit變量中計算
        };
        alert(bag.apple); // 如果 fruit='apple'

對象操作

1. 讀取對象屬性

 		console.log(user3.name); // li葉葉
        console.log(user3.age); // 30
        // 這種使用方括號的語法,對任何屬性都適用
        // 方括號裏如果是變量或表達式,計算變量的值
        console.log(user3['likes birds']);
        console.log(user3.isAdmin); //undefined

2. 添加對象屬性

 		user3.isAdmin = true;
        console.log(user3.isAdmin); //true

3. 移除一個屬性

		delete user3.isAdmin;
        console.log(user3.isAdmin); // undefined

實際應用:屬性值簡寫

		function makeUser(name, age) {
            return {
                name: name,
                age: age
            };
        }
        // 可以簡寫爲
        function makeUser2(name, age) {
            return {
                name,
                age
            };
        }
        let use = makeUser('花花', 20);
        alert(use.name + use.age);

4. 檢查屬性是否存在
4.1訪問一個不存在的屬性會返回undefined

	let user4 = {};
	alert(user4.noSuchProperty === undefined);

4.2 使用in來檢查屬性是否存在

		alert('blabla' in user4);
        // 注意
        let obj = {
            test: undefined
        };
        alert(obj.test); // undefined,表示屬性不存在,這是錯誤的
        alert("test" in obj); // true屬性存在

for…in循環

		for(key in object){
			各個屬性的執行區
    	}
        let user5 = {
            name: '葉葉',
            age: 20,
            isAdmin: true
        };
        for (let key in user5) {
            console.log(key);
            console.log(user5[key]);
        }

5. 拷貝對象(而不是拷貝對象的引用)
5.1 遍歷原始對象的屬性,複製給新的對象

		let user6 = {
            name: 'li葉葉',
            age: 30
        };
        let clone = {};
        for (let key in user6) {
            clone[key] = user6[key];
        }

5.2 通過Object.assign(這是淺拷貝,如果對象的屬性不是原始值,而是指向一個對象,則複製後的對象共享這個指向的對象)

  Object.assign(dest[,src1,src2,src3,...])
        dest和src1,...srcN是對象
        複製了src1,src2,...,srcN的所有對象到 dest
        如果有同樣屬性名的屬性,前面的會被覆蓋
		let user7 = {
            name: "John"
        };

        let permissions1 = {
            canView: true
        };
        let permissions2 = {
            canEdit: true
        };

        // 把permissions1和permissions2的所有屬性都拷貝給user
        Object.assign(user7, permissions1, permissions2);
        console.log(user7); //{name: "John", canView: true, canEdit: true}

垃圾回收

JavaScript主要的內存管理概念是可達性
1. 什麼是可達性?
以某種方式可以訪問或可用的值,這樣的值被稱爲可達值.必須存儲在內存中,不能被釋放
如果一個值可以通過引用或引用鏈,從可達值(也稱爲根)訪問到,則認爲這個值時可達的
如:
比方說,如果局部變量中有一個對象,並且該對象具有引用另一個對象的 property,則該對象被認爲是可達的。而且它引用的內容也是可達的。
2. 舉例
當前函數的局部變量和參數
嵌套調用時,當前調用鏈上所有函數的變量與參數
全局變量
等等
3.垃圾回收的算法
基本算法被稱爲 “mark-and-sweep”
3.1 垃圾收集器找到所有的根,並"標記"它們
3.2 並遍歷標記來自它們的所有參考
3.3 遍歷到標記的對象並標記它們的引用,所有被遍歷到的對象都會被記住,以免將來再次遍歷到同一個對象
3.4 一直這樣,直到有未訪問的引用
3.5 沒有被標記的所有對象都被刪除
4.優化
分代收集 —— 對象被分成兩組:『新的』和『舊的』。許多對象出現,完成他們的工作並快速釋放,他們可以很快被清理。那些長期存活下來的對象會變得『老舊』,而且檢查的次數也會減少。
增量收集 —— 如果有許多對象,並且我們試圖一次遍歷並標記整個對象集,則可能需要一些時間並在執行過程中帶來明顯的延遲。所以引擎試圖將垃圾收集工作分成幾部分來做,然後將這幾部分逐一處理。這需要他們之間額外的標記來追蹤變化,但是會有許多微小的延遲而不是大的延遲。
閒時收集 —— 垃圾收集器只會在 CPU 空閒時嘗試運行,以減少可能對代碼執行的影響。

對象的原始值轉換

  • 對象—boolean 所有對象都是true
  • 對象—number 發生在對象相減或應用數學函數時
  • 對象—string 輸出對象和類似的上下文轉換中
    當一個對象被用在需要原始值的上下文中時,例如,在 alert 或數學運算中,它會使用 ToPrimitive 算法轉換爲原始值(標準)該算法允許我們使用特殊的對象方法自定義轉換。
		1.string 當一個操作希望是一個字符串時
            // 1.1 輸出時
            alert(obj);
            // 1.2 使用對象作爲屬性鍵
            anotherObj[obj] = 123;
        2.number 當一個操作需要一個數字時
            // 2.1 顯示轉換
            let num = Number(obj);
            // 2.2 數學運算
            let n = +obj;
            let delta =date1-date2;
            let greater = user1>user2;
        3.default 在少數情況下不確定期望的類型時
            // +
            let total = car1 +car2;     //類型時數字和字符串都可以
            // == 
            if(user == 1){}     //對象與一個字符串,數字或符號進行比較時

爲了進行轉換,JavaScript嘗試查找並調用這三個對象方法

  • 調用objSymbol.toPrimitive ,如果存在
  • 否則如果暗示是"string"
    嘗試調用obj.toString()和obj.valueOf()
  • 否則如果暗示是"number"或"default"
    嘗試調用 obj.valueOf()和obj.toString()
Symbol.toPrimitive

名爲 Symbol.toPrimitive 的內置符號用來命名轉換方法

		obj[Symbol.toPrimitive] = function(hint){
            // 返回一個原始值
            // hint="string","number",和"default"中的一個
        }
 	<script>
        let user = {
            name:'葉葉',
            money: 1000,
            [Symbol.toPrimitive](hint){
                alert(`hint: ${hint}`);
                return hint == 'string'? `{name: "${this.name}"}` : this.money;
            }
        };

        alert(user);    // object --- >string
        alert(+user);   // object --- >number
        alert(user+500);// object --- > default */
        /* 2.toString/vauleOf */
        let user2 = {
            name:'花花',
            money:2000,

            toString(){
                return `{name:"${this.name}"}`;
            },

            // 對於number或default
            valueOf(){
                return this.money;
            }
        };
        alert(user2);    // object --- >string
        alert(+user2);   // object --- >number
        alert(500+user2);// object --- > default
    </script>

構造函數和new操作符

構造函數(在技術上是常規函數)

  • 他們的首字母用大寫字母命名。
  • 它們只能用 “new” 操作符來執行。
  • 通常,構造函數沒有return語句,它的任務是將必要的東西寫入this,並自動轉換
  • 如果有return 語句,return
    對象;返回該對象,否則返回this
    當一個函數作爲new User()執行時,它會執行以下步驟
  1. 一個新的空對象被創建並分配給this
  2. 函數體執行,通常會修改this,爲其添加新的屬性
  3. 返回this的值
    雙語法構造函數
    在一個函數內部,我們可以使用new.target屬性來檢查它被調用時,是否使用了new,常規調用爲空,如果通過new 調用,就等於函數
<script>

        function User(){
            alert(new.target);
        }
        new User();
        User();
        function User2(){
            if(!new.target){
                return new User2();
            }
            this.name = name;
        }
    </script>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章