本篇不講任何推導過程裹唆,直接說結論。
構造函數常識
每定義一個函數,引擎就自動定義了該函數的prototype屬性和該函數的原型對象舍咖,然后讓prototype屬性指向這個原型對象。
現在我們知道函數自帶prototype屬性和原型對象就行了锉桑。
引擎給原型對象搞了一個constructor屬性排霉,指向函數本身。別問為什么民轴。
function Foo() {}
console.log(Foo.prototype); // prototype屬性攻柠,指向Foo的原型對象
console.log(Foo.prototype.constructor === Foo); // true
實例對象常識
把Foo函數new一下子,出來個新對象(叫實例對象)后裸,這個對象也自帶一個屬性叫__proto__瑰钮,是不是跟prototype很像?沒錯微驶,__proto__屬性也指向Foo的原型對象浪谴。
JS引擎給__proto__屬性也鼓搗了一個constructor屬性,指向函數本身因苹。別問為什么苟耻。
function Foo() {}
var a = new Foo();
console.log(a.__proto__); // a的__proto__屬性,也指向Foo的原型對象
console.log(a.__proto__.constructor === Foo); // true
先這么記憶:
Foo.prototype.constructor === Foo
a.proto.constructor === Foo
原型對象常識
原型對象可以定義屬性和方法扶檐,當new出實例對象之后凶杖,對象就可以用這些屬性和方法。
function Foo() {}
Foo.prototype.name = 'zhangsan';
Foo.prototype.sayName = function() {return this.name};
var a = new Foo();
console.log(a.name); // zhangsan
console.log(a.sayName()); // zhangsan
function Foo() {}
Foo.prototype = { // 一次性定義所有屬性和方法
name: 'zhangsan',
sayName: function() {return this.name}
};
var a = new Foo();
console.log(a.name); // zhangsan
console.log(a.sayName()); // zhangsan
定義對象的普遍方式:混合構造函數模式和原型模式
定義對象的方式蘸秘,前輩們研究了很久官卡,最普遍、最簡單醋虏、較為科學的方式就是混合構造函數模式和原型模式寻咒。也就是,屬性定義在構造函數里颈嚼,方法定義在原型對象上毛秘,另外在原型對象上重置constructor屬性指向構造函數:
function Foo() {
this.name = 'zhangsan';
}
Foo.prototype = {
constructor: Foo,
sayName: function() {
return this.name
}
};
var a = new Foo();
console.log(a.name); // zhangsan
console.log(a.sayName()); // zhangsan
定義對象的第二普遍方式:動態(tài)原型模式
批評混合的構造函數/原型方式的人認為,在構造函數內部找屬性,在其外部找方法的做法不合邏輯叫挟。因此艰匙,他們設計了動態(tài)原型方法,以提供更友好的編碼風格抹恳。
動態(tài)原型方法的基本想法與混合的構造函數/原型方式相同员凝,即在構造函數內定義非函數屬性,而函數屬性則利用原型屬性定義奋献。唯一的區(qū)別是賦予對象方法的位置健霹。
function Foo() {
this.name = 'zhangsan';
if ( typeof this.sayName !== 'function' ) {
Foo.prototype.sayName = function() {
return this.name;
}
}
}
var a = new Foo();
console.log(a.name); // zhangsan
console.log(a.sayName()); // zhangsan