方式一: Object構(gòu)造函數(shù)模式
- 套路: 先創(chuàng)建空Object對象, 再動態(tài)添加屬性/方法
- 適用場景: 起始時不確定對象內(nèi)部數(shù)據(jù)
- 問題: 語句太多
var p = new Object()//先創(chuàng)建空Object對象
p.name = 'Tom'
p.age = 12
p.setName = function (name) {
this.name = name
}
方式二: 對象字面量模式
- 套路: 使用{}創(chuàng)建對象, 同時指定屬性/方法
- 適用場景: 起始時對象內(nèi)部數(shù)據(jù)是確定的
- 問題: 如果創(chuàng)建多個對象, 有重復(fù)代碼
var p = {
name: 'Tom',
age: 12,
setName: function (name) {
this.name = name
}
}
方式三: 工廠模式
- 套路: 通過工廠函數(shù)動態(tài)創(chuàng)建對象并返回
- 適用場景: 需要創(chuàng)建多個對象
- 問題: 對象沒有一個具體的類型, 都是Object類型
function createPerson(name, age) {
var obj = {//返回一個對象的函數(shù)
name: name,
age: age,
setName: function (name) {
this.name = name
}
}
return obj
}
工廠模式無法識別對象的類型,因為它們直接由 Object() 構(gòu)造函數(shù)創(chuàng)建一忱,原型鏈上只有 Object.prototype 對象魁亦,不像Date叠赐、Array等泳赋。
方式四: 自定義構(gòu)造函數(shù)模式
- 套路: 自定義構(gòu)造函數(shù), 通過new創(chuàng)建對象
- 適用場景: 需要創(chuàng)建多個類型確定的對象
- 問題: 每個對象都有相同的數(shù)據(jù), 浪費內(nèi)存
構(gòu)造函數(shù)的目的就是為了創(chuàng)建一個自定義類爸舒,并且創(chuàng)建這個類的實例臣淤。構(gòu)造函數(shù)模式中擁有了類和實例的概念顶猜,并且實例和實例之間是相互獨立的,即實例識別粤剧。
構(gòu)造函數(shù)就是一個普通的函數(shù)歇竟,創(chuàng)建方式和普通函數(shù)沒有區(qū)別,不同的是構(gòu)造函數(shù)習(xí)慣上首字母大寫抵恋。另外就是調(diào)用方式的不同焕议,普通函數(shù)是直接調(diào)用,而構(gòu)造函數(shù)需要使用new關(guān)鍵字來調(diào)用弧关。
1.構(gòu)造函數(shù)的執(zhí)行流程:
1.立刻創(chuàng)建一個新的對象
2.將新建的對象設(shè)置為函數(shù)中this
3.逐行執(zhí)行函數(shù)中的代碼
4.將新建的對象作為返回值返回
function Person(name, age) {
this.name = name
this.age = age
this.setName = function (name) {
this.name = name
}
}
var p1 = new Person('Tom', 12)
function Student(name, price) {
this.name = name
this.price = price
this.setName = function (name) {
this.name = name
}
}
var s1 = new Student('Bob', 13000)
console.log(p1 instanceof Person)//true
console.log(s1 instanceof Student)//true
console.log(p1,s1)
使用instanceof可以檢查一個對象是否是一個類的實例盅安。所有的對象都是Object的后代,所以任何對象和Object左instanceof檢查時都會返回true世囊。
2.注意點
p1和p2都是Person這個類的實例别瞭,所以都擁有setName這個方法,但是不同實例之間的方法是不一樣的株憾。在類中給實例增加的屬性(this.xxx=xxx)屬于當(dāng)前實例的私有的屬性蝙寨,實例和實例之間是單獨的個體晒衩,所以私有的屬性之間是不相等的。
var p2 = new Person('jack', 12)
console.log(p1.setName === p2.setName);
每創(chuàng)建一個Person構(gòu)造函數(shù)墙歪,在Person構(gòu)造函數(shù)中听系,為每一個對象都添加了一個setName方法,也就是說構(gòu)造函數(shù)每執(zhí)行一次就會創(chuàng)建一個新的setName方法箱亿。這樣就導(dǎo)致了構(gòu)造函數(shù)執(zhí)行一次就會創(chuàng)建一個新的方法跛锌,執(zhí)行10000次就會創(chuàng)建10000個新的方法,而10000個方法都是一模一樣的届惋,這是完全沒有必要髓帽,完全可以使所有的對象共享同一個方法。
function Person(name, age) {
this.name = name
this.age = age
this.setName = fun
}
function fun(){
alert("Hello大家好脑豹,我是:"+this.name);
};
將函數(shù)定義在全局作用域這種方法郑藏,雖然會提升性能,但污染了全局作用域的命名空間,而且定義在全局作用域中也很不安全瘩欺。那么有沒有更好的辦法呢必盖?
方式五: 構(gòu)造函數(shù)+原型的組合模式
- 套路: 自定義構(gòu)造函數(shù), 屬性在函數(shù)中初始化, 方法添加到原型上
- 適用場景: 需要創(chuàng)建多個類型確定的對象
我們所創(chuàng)建的每一個函數(shù),解析器都會向函數(shù)中添加一個屬性prototype
俱饿,這個屬性對應(yīng)著一個對象歌粥,這個對象就是我們所謂的原型對象。如果函數(shù)作為普通函數(shù)調(diào)用prototype
沒有任何作用拍埠。當(dāng)函數(shù)以構(gòu)造函數(shù)的形式調(diào)用時失驶,它所創(chuàng)建的對象中都會有一個隱含的屬性,指向該構(gòu)造函數(shù)的原型對象枣购,我們可以通過__proto__
來訪問該屬性嬉探。
function MyClass() {}
var mc = new MyClass()
console.log(mc.__proto__ === MyClass.prototype)//true
原型對象就相當(dāng)于一個公共的區(qū)域,所有同一個類的實例都可以訪問到這個原型對象棉圈,我們可以將對象中共有的內(nèi)容涩堤,統(tǒng)一設(shè)置到原型對象中。當(dāng)我們訪問對象的一個屬性或方法時分瘾,它會先在對象自身中尋找胎围,如果有則直接使用,如果沒有則會去原型對象中尋找德召,如果找到則直接使用白魂。如果沒有則去原型的原型中尋找,直到找到Object對象的原型,Object對象的原型沒有原型氏捞,如果在Object原型中依然沒有找到,則返回undefined冒版。
function Person(name, age) { //在構(gòu)造函數(shù)中只初始化一般函數(shù)
this.name = name
this.age = age
}
Person.prototype.setName = function (name) {
this.name = name
}
var p1 = new Person('Tom', 23)
var p2 = new Person('Jack', 24)
console.log(p1, p2)
p1.setName("james")//p1沒有這個方法液茎,就會去原型對象中尋找
console.log(p1)//Person{name: "james", age: 23}
以后我們創(chuàng)建構(gòu)造函數(shù)時,可以將這些對象共有的屬性和方法,統(tǒng)一添加到構(gòu)造函數(shù)的原型對象中捆等,這樣不用分別為每一個對象添加滞造,也不會影響到全局作用域,就可以使每個對象都具有這些屬性和方法了栋烤。
如果覺得文章對你有些許幫助谒养,歡迎在我的GitHub博客點贊和關(guān)注,感激不盡明郭!