雖然Object構造函數或對象字面量可以方便地創建對象,但這些方式也有明顯不足: 創建具有同樣接口的多個對象需要重復編寫很多代碼??
1.工廠模式?
工廠模式是一種眾所周知的設計模式,廣泛應用于軟件工程領域,用于抽象創建特定對象的過程?
function createPerson(name,age){let o=new Object();?o.name=name;?o.age=age;?o.sayName=function(){console.log(this.name);};return o;}let person1=createPerson('a',18);let person2=createPerson('b',19)
可以根據用不同的參數多次調用這個函數,每次都會返回2個屬性和1個方法的對象,這種工廠模式雖然可以解決多個類似對象的問題,但沒有解決對象標識問題(即新創建的對象是什么類型),每次創建對象的時候方法都會創建??
2.構造函數模式?
//第一種寫法
function Person(name,age){this.name=name; this.age=age; this.sayName=function(){console.log(this.name) };
}let person1=new Person("Nicholas",29);
let person2=new Person('b',27)//第二種寫法
let Person =function(name,age,job){this.name=name; this.age=age; this.sayName=function(){console.log(this.name) };
}//不傳參數
function Person(){this.name="JaKe"; this.sayName=function(){console.log(this.name) };
}
let person1=new Person();
let Person2=new Person;
Person()構造函數代替了createPerson()工廠函數,實際上Person()內部的代碼跟createPerson()基本是一樣的,只是有如下區別?
- 沒有顯式地創建對象
- 屬性和方法直接復制給了this?
- 沒有return?
另外要注意按照慣例構造函數名稱的首字母要大寫,非構造函數則以小寫字母開頭,有助于區分構造函數和普通函數?
1.要創建Person的實例,應使用new操作符,使用new操作符會執行如下操作
- 在內存中創建一個新對象
- 這個新對象內部的[[prototype]]特性被賦值為構造函數的prototype屬性?
- 構造函數內部的this被賦值為這個新對象(即this指向新對象)
- 執行構造函數內部的代碼(給新對象添加屬性)
- 如果構造函數返回非空對象,則返回該對象;否則,返回剛創建的新對象?
上個例子,person1和person2分別保存著Person的不同實例,這兩個對象都有一個construcotr屬性指向Person,如下所示?
conosle.log(person1.constructor==Person); //true??
console.log(person2.constructor==Person); //true?
instanceof操作符? 用于判斷一個對象是否是某個構造函數的實例?
console.log(person1 instanceof Object) //true? ?因為Person1是通過構造函數Person創建的,而Person.prototype最終繼承自object.prototype 換句話說,所有對象的原型鏈最終都會指向Object.prototype?
console.log(person1 instanceof Person)?
2.1構造函數也是函數?
構造函數與普通函數唯一的區別就是調用方式不同,除此之外,構造函數也是函數,并沒有把某個函數定義為構造函數的特殊語法,任何函數只要使用new操作符調用就是構造函數,而不是用new操作符調用的函數就是普通函數?
//作為構造函數
let person=new Person('a',17)
person.sayName();?
//作為函數調用Person("Greg",27); //添加到window對象?
window.sayName(); //"Greg"
//在領一個對象的作用域中調用let o = new Object( );?
Person.call(o,'Kristen',25)
o.sayName(); //"Kristen"?
2.2? 構造函數的問題
構造函數雖然有用,但也不是沒有問題,構造函數的主要問題在于,其定義的方法會在每個實例上都創建一遍,因此對前面的例子而言,person1和person2都有名為sayName()的方法,但這兩個方法不是同一個Funtion實例,我們知道,js中的函數是對象,因此每次定義函數時,都會初始化一個對象
conosle.log(person1.sayName==person2.sayName); //false?
雖然可以把函數轉移到構造函數外部,但是這樣會搞亂全局作用域,這個新問題可以通過原型模式來解決?
3. 原型模式 (請看下面這篇文章)
js對象原型,原型鏈-CSDN博客
4.屬性枚舉順序
for-in循環,Object.keys(),Object.getOwnPropertyNames(),Object.getOwnProperty-Symbols()以及Object.assign()在屬性枚舉順序方面有很大區別,for-in循環和Object.keys()的枚舉順序是不確定的取決于js引擎,可能因瀏覽器而異?
Object.getOwnPropertyNames(),Object.getOwnpropertySymbols()和Object.assign()的枚舉順序是確定性的,先以升序枚舉數值鍵,然后以插入順序枚舉字符串和符號鍵,在對象字面量中定義的鍵以它們逗號分隔的順序插入?
let k1 = Symbol('k1'),k2 = Symbol('k2');let o = {1: 1,first: 'first',[k1]: 'sym2',second: 'second',0: 0
};o[k2] = 'sym2';
o[3] = 3;
o.third = 'third';
o[2] = 2;console.log(Object.getOwnPropertyNames(o));
// ["0", "1", "2", "3", "first", "second", "third"]console.log(Object.getOwnPropertySymbols(o));
// [Symbol(k1), Symbol(k2)]
5. 對象迭代?
1.Object.values() //返回對象值的數組
2. Object.entries() //返回健/值對的數組?
const o = {foo: 'bar',baz: 1,qux: {}
};console.log(Object.values(o));
// ["bar", 1, {}]console.log(Object.entries((o)));
// [["foo", "bar"], ["baz", 1], ["qux", {}]]注意: 非字符串屬性會被轉換為字符串輸出,另外,這兩個方法執行對象的淺復制: const o = {qux: {}
};console.log(Object.values(o)[0] === o.qux);
//true console.log(Object.entries(o)[0][1]=== o.qux);
//true 符號屬性會被忽略:
const sym=Symbol();
const o={[sym]: 'foo'
};
console.log(Object.values(o));
// []
console.log(Object.entries((o)));
// []