構(gòu)造對象
先看一些老式的方法:
我們可以拋開類,使用字面量來構(gòu)造一個對象:
var obj1 = {
nick: 'Byron',
age: 20,
printName: function(){
console.log(obj1.nick);
}
}
var obj2 = {
nick: 'Casper',
age: 25,
printName: function(){
console.log(obj2.nick);
}
}
這樣構(gòu)造出來的對象有兩個明顯的問題。
- 太麻煩了,每次構(gòu)建一個對象都是復(fù)制一遍代碼
- 如果想個性化,只能通過手工賦值,使用者必需了解對象詳細(xì)
這兩個問題其實也是我們不能拋開類的重要原因,也是類的作用
優(yōu)化一下 使用函數(shù)做自動化
function createObj(nick, age){
var obj = {
nick: nick,
age: age,
printName: function(){
console.log(this.nick);
}
};
return obj;
}
var obj3 = createObj('Byron', 30);
obj3.printName();
我們通過創(chuàng)建一個函數(shù)來實現(xiàn)自動創(chuàng)建的對象的過程,至于個性化通過參數(shù)實現(xiàn),開發(fā)者不必再關(guān)注細(xì)節(jié),只需要傳入指定的參數(shù)即可。
這樣做也有個小問題 !
這種方法解決了構(gòu)造過程復(fù)雜,需要了解細(xì)節(jié)的問題,但是構(gòu)造出來的對象類型都是Object,沒有識別度。
該怎么辦呢?這個時候 構(gòu)造函數(shù) 橫空出世?。?!
構(gòu)造函數(shù)
面向?qū)ο缶幊痰牡谝徊剑褪且蓪ο?。前面說過,對象是單個實物的抽象。通常需要一個模板,表示某一類實物的共同特征,然后對象根據(jù)這個模板生成。
典型的面向?qū)ο缶幊陶Z言(比如 C++ 和 Java),都有“類”(class)這個概念。所謂“類”就是對象的模板,對象就是“類”的實例。但是,JavaScript 語言的對象體系,不是基于“類”的,而是基于構(gòu)造函數(shù)(constructor)和原型鏈(prototype)。
JavaScript 語言使用構(gòu)造函數(shù)(constructor)作為對象的模板。所謂”構(gòu)造函數(shù)”,就是專門用來生成實例對象的函數(shù)。它就是對象的模板,描述實例對象的基本結(jié)構(gòu)。一個構(gòu)造函數(shù),可以生成多個實例對象,這些實例對象都有相同的結(jié)構(gòu)。
構(gòu)造函數(shù)就是一個普通的函數(shù),但是有自己的特征和用法。
var Vehicle = function () {
this.price = 1000;
};
上面代碼中,Vehicle就是構(gòu)造函數(shù)。為了與普通函數(shù)區(qū)別,構(gòu)造函數(shù)名字的第一個字母通常大寫。
構(gòu)造函數(shù)的特點有兩個。
- 函數(shù)體內(nèi)部使用了this關(guān)鍵字,代表了所要生成的對象實例。
- 生成對象的時候,必須使用
new命令。
new
下面先介紹new命令。
function Person(name) {
this.name = name
this.sayName = function() {
console.log(this.name)
}
}
var p = new Person('hunger')
以上代碼的執(zhí)行過程如下:
1、執(zhí)行 new Person
- 創(chuàng)建一個空對象 {},假設(shè)名字是 tmpObj
- 執(zhí)行 Person 函數(shù),執(zhí)行過程中對 this 操作就是對 tmpObj 進(jìn)行操作
- 函數(shù)執(zhí)行完后返回剛剛創(chuàng)建的 tmpObj
2、把 tmpObj 賦值給 p (p也指向同一個對象)
在看下面的例子 new的本質(zhì)什什么
function Modal(msg){
this.msg = msg
}
var modal = new Modal()
- 創(chuàng)建類的實例。這步是把一個空的對象的 proto 屬性設(shè)置為 Modal.prototype 。
- 初始化實例。函數(shù) Modal 被傳入?yún)?shù)并調(diào)用,關(guān)鍵字 this 被設(shè)定為該實例。
- 返回實例, 賦值給 modal
instanceof
instanceof是一個操作符,可以判斷對象是否為某個類型的實例
p1 instanceof Person; // true
p1 instanceof Object;// true
instanceof判斷的是對象
1 instanceof Number; // false
構(gòu)造函數(shù) 原型(prototype)
任何函數(shù)使用
new表達(dá)式就是構(gòu)造函數(shù)每個函數(shù)都自動添加一個名稱為
prototype屬性,這是一個對象每個對象都有一個內(nèi)部屬性
__proto__(規(guī)范中沒有指定這個名稱,但是瀏覽器都這么實現(xiàn)的) 指向其類型的prototype屬性,類的實例也是對象,其__proto__屬性指向“類”的prototype。
prototype
十分重要的原型圖

通過圖示我們可以看出一些端倪,實例可以通過__prop__訪問到其類型的prototype屬性,這就意味著類的prototype對象可以作為一個公共容器,供所有實例訪問。
抽象重復(fù)
我們剛才的問題可以通過這個手段解決
所有實例都會通過原型鏈引用到類型的prototype
prototype相當(dāng)于特定類型所有實例都可以訪問到的一個公共容器
重復(fù)的東西移動到公共容器里放一份就可以了 看以下代碼 理解原型鏈
function Person(nick, age){
this.nick = nick;
this.age = age;
}
Person.prototype.sayName = function(){
console.log(this.nick);
}
var p1 = new Person();
p1.sayName();
這時候我們對應(yīng)的關(guān)系是這樣的

在舉幾個經(jīng)典的例子 有如下代碼 畫出原型圖
function People (name){
this.name = name;
}
People.prototype.walk = function(){
console.log(this.name + ' is walking');
}
var p1 = new People('饑人谷');
var p2 = new People('前端');

其實和上面的是一樣的
有如下代碼,代碼中并未添加 toString方法,這個方法是哪里來的?畫出原型鏈圖進(jìn)行解釋
function People(){
}
var p = new People()
p.toString()
