JavaScript 中的所有事物都是對象:字符串、數(shù)值、數(shù)組、函數(shù)......
此外,JavaScript允許自定義對象
JavaScript 對象
JavaScript 提供多個內(nèi)建的對象出爹,比如String,Date,Array等等
對象是帶有屬性和方法的特殊數(shù)據(jù)類型
1,工廠模式
function createPerson(name,age,job){
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function(){
console.log(this);
console.log(this.name);
}
return o;
}
var person01 = createPerson("nasha",25,"doc")
person01.sayName();
console.log(person01 instanceof creatPerson) // ERR
// this 指向的是 {o產(chǎn)生的對象 }
// nasha
弊端:沒有解決對象的識別問題缎除,即怎么知道一個對象的類型
2严就,構(gòu)造函數(shù)模式
function Person(name,age,job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
console.log(this) // Person
console.log(this.name) //bbb|| aaa
}
}
var person01 = new Person("aaa",20,"doc")
var person02 = new Person("bbb",30,"teacher")
console.log(person01 instanceof Person) // true
console.log(person01 instanceof Object) // true
console.log(person01.sayName())
// Person{...}
// aa
與工廠模式相比:
1,沒有顯式的創(chuàng)建對象
2器罐,直接將屬性和方法賦值給了this對象
3梢为,沒有return語句
要創(chuàng)建person的實例,必須使用new操作符轰坊,以這種方式調(diào)用構(gòu)造函數(shù)實際上會經(jīng)歷4個步驟
1铸董,創(chuàng)建一個新的對象
2,將構(gòu)造函數(shù)的作用域賦值給新對象
3肴沫,執(zhí)行構(gòu)造函數(shù)里的代碼
4粟害,返回新的對象
創(chuàng)建自定義的構(gòu)造函數(shù)可以將它的實際標(biāo)識為一種特定的類型。
缺點(diǎn):
1颤芬,每個方法都有在每個實例上重新創(chuàng)新一遍悲幅;
2,person01和person02都有一個sayName()的方法站蝠,但兩個方法不是同一個Function實例汰具。即不同實例上同名函數(shù)是不相等的,創(chuàng)建兩個完成相同任務(wù)的function是不必要的菱魔,而且還有this對象在留荔,不需要執(zhí)行代碼前就把函數(shù)綁定在特定對象上,這樣豌习,上面的函數(shù)就可以寫成
function Person(name,age,job){
this.name = name;
this.age = age;
this.job = job;
this.sayname= sayname;
}
function sayname(){
console.log(this);
// do sth
}
把sayname屬性設(shè)置成全局的sayname函數(shù)存谎,這樣拔疚,由于sayname包含的是一個指向函數(shù)的指針肥隆,因此person01與person02對象就共享了同一個函數(shù)。
但是稚失,如果有很多方法栋艳,那么就定義了很多全局函數(shù),自定義的引用類型無封裝可言句各,為了解決上述問題吸占,就引入了原型模式晴叨。
3,原型模式
每創(chuàng)建一個對象都有prototype屬性(null除外)矾屯,這個屬性是一個指針兼蕊,指向一個對象,而這個對象的用途是包含可以由特定類型的所有實例共享的屬性和方法件蚕。
使用原型對象的好處是可以讓所有對象實例共享它所包含的屬性和方法孙技。
function Person() {};
Person.prototype.name = "bigbang";
Person.prototype.job = "dosth";
Person.prototype.age = 25;
Person.prototype.sayname = function() {
console.log(this.name);
}
var person01 = new Person();
方法 isPrototypeOf()確定實例和原型之間的關(guān)聯(lián)
console.log(Person.prototype.isPrototypeOf(person01)); // true
Object.getPrototypeOf()返回的是[[prototype]]的值;
console.log(Object.getPrototypeOf(person01))
console.log(Object.getPrototypeOf(person01) === Person.prototype) // true
hasOwnProperty()方法可以檢測一個屬性是存在于一個實例中排作,還是存在原型中的牵啦。true為屬性存在于實例中。
console.log(person01.hasOwnProperty("name")); // false
更常見的做法是用一個包含所有屬性和方法的對象字面量來重寫整個原型對象妄痪,并重設(shè)constructor屬性
function Person(){}
Person.prototype = {
name:"...",
age: 24,
job:"sadf",
sayname: function(){
...
}
};
Object.defineProperty(Person.prototype,"constructor",{
enumerable: false,
value: Person
})
原型與in操作符
有兩種方法使用in操作符:單獨(dú)使用和for-in中循環(huán)使用哈雏。
使用for-in循環(huán),返回的是所有能夠通過對象訪問的衫生,可枚舉的屬性悦冀。包括實例中的屬性,也包括存在于屬性中的屬性丘损。
var person = {
toString: function(){
return "My Object"
}
}
for(var prop in person){
if(prop == "toString"){
console.log('get it')
}
}
原型對象的缺點(diǎn):
1蟹腾,省略了構(gòu)造函數(shù)傳遞初始化參數(shù)這一環(huán)節(jié),結(jié)果所有實例在默認(rèn)情況下都將獲取到相同的屬性值站故,這不是最大問題皆怕,最大問題是由其共享本性所決定的。
2西篓,對于包含基本值的屬性愈腾,可以在實例上添加同名屬性隱藏原型中的屬性,然后岂津,對于包含引用數(shù)據(jù)類型的值來說虱黄,會導(dǎo)致問題。
4吮成,組合使用構(gòu)造函數(shù)模式和原型模式
構(gòu)造函數(shù)模式用于定義實例屬性橱乱,而原型模式用于定義方法和共享的屬性。所以每個實例都會有自己的一份實例屬性副本粱甫,但同時共享著對方法的引用泳叠,最大限度的節(jié)省了內(nèi)存,同時支持向構(gòu)造函數(shù)傳遞參數(shù)茶宵。
function Person(name,age,job){
this.name = name;
this.age = age;
this.job = job;
this.friends = ['a','b'];
}
Person.prototype = {
constructor: Person,
sayName: function(){
console.log(this,this.name)
}
}
var person01 = new Person(...)
5危纫,動態(tài)原型模式
function Person(name,age,job){
this.name = name;
this.age = age;
this.job = job;
if(typeof this.sayName != "function"){
Person.prototype.sayName = function(){
console.log(this,this.name)
}
}
}
這段代碼只會在初次調(diào)用構(gòu)造函數(shù)的時候才執(zhí)行。這里對原型所做的修改,能夠立即在所有實例中得到反映种蝶。
6契耿,Object.create()
ES5定義了一個名為Object.create()的方法,它創(chuàng)建了一個新對象螃征,其中第一個參數(shù)是這個對象的原型搪桂,第二個參數(shù)對對象屬性的進(jìn)一步描述。