創建對象的方式
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()執行時,它會執行以下步驟
- 一個新的空對象被創建並分配給this
- 函數體執行,通常會修改this,爲其添加新的屬性
- 返回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>