通過Object構(gòu)造函數(shù)或者字面量創(chuàng)建對象
var obj01 = new Object();
var obj02 = {};
- 弊端:無論通過Object來創(chuàng)建對象, 還是通過字面量來創(chuàng)建對象都存在一個弊端,每次創(chuàng)建都需要重新編寫一次, 如果創(chuàng)建的多個對象的屬性和方法名稱一樣赤惊,浪費時間
通過工廠函數(shù)創(chuàng)建對象
//所以我們可以通過工廠函數(shù)來創(chuàng)建對象
*/
// 工廠函數(shù)
function createPerson(name, age) {
// 1.通過Object創(chuàng)建一個空對象
// var obj = new Object();
var obj = {};
// 2.動態(tài)的給空對象添加屬性和方法
obj.name = name;
obj.age = age;
obj.say = function () {
console.log("hello");
};
// 3.將函數(shù)中創(chuàng)建的對象返回給調(diào)用者
return obj;
}
var obj1 = createPerson("luodou", 13);
var obj2 = createPerson("doudou", 18);
console.log(obj1);
console.log(obj2);
console.log(typeof obj1); // object
console.log(obj1.constructor); // ? Object() { [native code] }
- 工廠函數(shù)實質(zhì)上是Object或字面量創(chuàng)建對象的封裝,調(diào)用函數(shù)即可創(chuàng)建對象
- 弊端:通過Object對象, 或者通過字面量, 或者通過工廠函數(shù)創(chuàng)建的對象, 我們無法判斷這個對象是誰創(chuàng)建出來的凰锡,代碼最后一行constructor指向的是一個Object
通過構(gòu)造函數(shù)創(chuàng)建對象
-
什么是構(gòu)造函數(shù)?
- 構(gòu)造函數(shù)也是一個函數(shù), 只不過是專門用于創(chuàng)建對象的函數(shù)而已
-
構(gòu)造函數(shù)和普通函數(shù)的區(qū)別?
- 構(gòu)造函數(shù)的函數(shù)名稱首字母必須大寫
- 構(gòu)造函數(shù)必須使用new 來調(diào)用
-
構(gòu)造函數(shù)本質(zhì)上是對工廠函數(shù)的簡化
- 在構(gòu)造函數(shù)中默認會創(chuàng)建一個空的對象, 會將創(chuàng)建的對象賦值給this,會將創(chuàng)建的對象返回給調(diào)用者
過去通過Object對象, 或者通過字面量, 或者通過工廠函數(shù)創(chuàng)建的對象, 我們無法判斷這個對象是誰創(chuàng)建出來的,但是通過構(gòu)造函數(shù)創(chuàng)建的對象, 我們可以判斷這個對象是誰創(chuàng)建出來的(見代碼里obj.constructor)
默認情況下每一個對象都有一個隱藏的屬性, 叫做constructor, 這個屬性指向了創(chuàng)建當前對象的構(gòu)造函數(shù)
// 1.自定義一個構(gòu)造函數(shù)
function Person(name, age) {
// 1.var obj = new Object();
// 2.this = obj;
this.name = name; // obj.name = name;
this.age = age;
this.say = function () {
console.log("hello");
}
// 3.return obj;
}
/*
new Person("luodou", 13);做了什么事情?
1.會在構(gòu)造函數(shù)中創(chuàng)建一個空的對象
2.將創(chuàng)建好的空對象賦值給this
3.將創(chuàng)建好的對象返回給調(diào)用者
*/
var obj = new Person("luodou", 13);
console.log(obj);
console.log(typeof obj); // object
console.log(obj.constructor); // ? Person(name, age) {}
// 判斷obj對象是否是Person構(gòu)造函數(shù)創(chuàng)建出來的
// console.log(obj.constructor === Person); // 不推薦
// 如果想判斷某個對象時候是某個構(gòu)造函數(shù)創(chuàng)建出來的
// 可以使用 對象名稱 instanceof 構(gòu)造函數(shù)名稱, 來判斷
console.log(obj instanceof Person); // true
function Student(name, age, score) {
this.name = name; // obj.name = name;
this.age = age;
this.score = score;
}
var obj2 = new Student("dou", 11, 99);
console.log(obj2 instanceof Person); //false
console.log(obj2 instanceof Student); //true
- 弊端:默認情況下, 只要創(chuàng)建一個對象就會在對象中開辟一塊存儲空間未舟,該存儲空間中會存儲對象的所有數(shù)據(jù),浪費空間
function Person(name, age) {
this.name = name;
this.age = age;
this.say = function () {
// obj1.name, obj1.age
// obj2.name, obj2.age
console.log(this.name, this.age);
};
}
var obj1 = new Person("lnj", 13);
obj1.say();
var obj2 = new Person("zq", 18);
obj2.say();
// 這里的===是在判斷兩個函數(shù)的地址是否相同
console.log(obj1.say === obj2.say); //false
- 解決方案:
- 將方法定義在外面, 將定義在外面函數(shù)的地址賦值給屬性掂为,每次創(chuàng)建對象, 對象中say保存的都是函數(shù)的地址, 就不會重復(fù)保存了
/*
注意點: 在JavaScript中, 函數(shù)也是一個對象
*/
function say() {
console.log(this.name, this.age);
}
// var say = function () {
// console.log(this.name, this.age);
// };
// var say = new Function("console.log(this.name, this.age);");
// 定義了一個構(gòu)造函數(shù)
function Person(name, age) {
this.name = name;
this.age = age;
this.say = say;
}
var obj1 = new Person("luodou", 13);
obj1.say();
var obj2 = new Person("dou", 18);
obj2.say();
// 這里的===是在判斷兩個函數(shù)的地址是否相同
console.log(obj1.say === obj2.say); // true
弊端:因為將函數(shù)定義在了全局作用域中, 所以如果定義了多個函數(shù), 會導(dǎo)致全局作用域的名稱匱乏
-
解決方案2.0
- 將所有函數(shù)都封裝到另外一個對象中, 這樣函數(shù)名稱就不在全局作用域中了, 這就不會導(dǎo)致全局作用域命名匱乏問題了裕膀,然后將對象中方法的地址復(fù)制給使用者即可
var fns = {
say: function() {
console.log(this.name, this.age);
},
eat: function () {
console.log("eat");
}
};
// 定義了一個構(gòu)造函數(shù)
function Person(name, age) {
this.name = name;
this.age = age;
this.say = fns.say;
this.eat = fns.eat;
}
var obj1 = new Person("luodou", 13);
obj1.say();
var obj2 = new Person("dou", 18);
obj2.say();
// 這里的===是在判斷兩個函數(shù)的地址是否相同
console.log(obj1.say === obj2.say); // true
終極解決方案
前面的通通忘掉!
在JavaScript中,每一個構(gòu)造函數(shù)都有一個默認的屬性, 這個屬性叫做prototype,prototype屬性指向一個對象, 這個對象我們稱之為構(gòu)造函數(shù)的原型對象
既然構(gòu)造函數(shù)的prototype就對應(yīng)一個對象, 所以我們就可以將方法都放到這個對象中
注意點:所有通過同一個構(gòu)造函數(shù)創(chuàng)建出來的對象, 都可以訪問該構(gòu)造函數(shù)的原型對象勇哗,并且所有通過同一個構(gòu)造函數(shù)創(chuàng)建出來的對象, 訪問的都是同一個原型對象
// 定義了一個構(gòu)造函數(shù)
function Person(name, age) {
this.name = name;
this.age = age;
}
/*
私有成員(一般就是非函數(shù)成員)放到構(gòu)造函數(shù)中
共享成員(一般就是函數(shù))放到原型對象中
如果重置了 prototype 記得修正 constructor 的指向
*/
Person.prototype.say = function () {
console.log(this.name, this.age);
};
// console.log(Person.prototype);
var obj1 = new Person("luodou", 13);
obj1.say();
var obj2 = new Person("dou", 18);
obj2.say();
// 這里的===是在判斷兩個函數(shù)的地址是否相同
console.log(obj1.say === obj2.say); // true