- 原型是function對象的一個屬性,它定義了構造函數製造出的對象的公共祖先。
- 通過該構造函數產生的對象,可以繼承該原型的屬性和方法。
- 原型也是對象。
- 原型就像是批處理添加水印:預設好的統一處理,有顏色主題不合適的單獨設計。
訪問對象的屬性,如果本身沒有,會向原型上面找。
由構造函數創建的對象,有隠式屬性this對象。
this對象有一個屬性 _ proto_ [指針,指向對象的原型]
this . _ proto_ = Function.prototype
由構造函數創建的對象的屬性[this]的屬性[_ proto_]的值等於構造函數的屬性[prototype]的值。
這兩個指向的值是一個對象,即原型對象。
obj.attributes
->
if(obj.attributes){return obj._proto_.attributes}
原型應用:
CarFactory.prototype.door = 4;
CarFactory.prototype.distance = 0;
CarFactory.prototype.run = function() {
this.distance += 100;
}
CarFactory.prototype.aurhor = {
name: 'cst',
money: 999999
}
//提取全部實例的公共特點,添加到遠行對象裏
//相當於給每一個實例初始化,添加水印,節約性能
function CarFactory(wheelNum, carColor) {
this.wheel = wheelNum;
this.color = carColor;
}
var oCar1 = new CarFactory(3, 'red');
var oCar2 = new CarFactory(5,'yellow');
oCar1.door = 6;
// 實例本身新增door屬性,就不會找原型,也不會影響原型和其他實例
console.log(oCar.door);
delete oCar1.chair; // true 刪除不存在的屬性
oCar1.author.money = 200;
console.log(oCar2.author.money); // 改變實例本身屬性,還是改變原型屬性
[改變原型對象的指向] 和 [改變原型對象內的值]
CarFactory.prototype.door = 4;
var oCar1 = new CarFactory();
CarFactory.prototype = {
door:6; //已經創建好的對象不會被新改變的原型影響
}
// this._proto_ --鏈接-- Function.prototype
// 這兩個值對應的是一個對象,過程是F.p把地址給了t._p_
// 當改變了F.p,它會指向一個新的對象,有一個新的地址
// 而t._p_還是以前的地址
// 兩個值不是時刻牽引的,是一次性賦給相同地址,之後撒手
// 讓F.p等於一個新對象,相當於斷開了與t._p_的聯繫與羈絆
// 讓F.p.attributes等於一個新的值,並沒有斷開兩者的聯繫,
// 因此會出現給F.p賦值新對象不會影響已經創建的對象
// 而給F.p賦值新的屬性值,會影響已經創建的對象
// 因爲聯繫還在,f._p_是跟着對象走的
// 兩個都是屬性名而已,兩張入場券,進入同一個地方,這個地方里面存着原型信息
// 要在一張入場券上增加或修改演員,要麼把入場券引向別的場次
// 跟對象直接聯繫的是__proto__,只要看它的值就行了,是保持鏈接屬性更新。
// 還是斷開鏈接,屬性不變
var PrototypeSelf = {name:'cst'};
var __proto__Self = PrototypeSelf;
PrototypeSelf = {name:'duyi'};
__Proto__Self.name // -> cst
練習
Person.prototype.name = 'sunny';
function Person() {}
var oPerson = new Person();
Person.prototype.name = 'cherry';
console.log(oPerson.name); // cherry
//======================================
Person.prototype.name = 'sunny';
function Person() {}
Person.prototype.name = 'cherry';
var oPerson = new Person();
console.log(oPerson.name); // cherry
//======================================
Person.prototype.name = 'sunny';
function Person() {}
var oPerson = new Person();
Person.prototype = {
name: 'cherry'
};
console.log(oPerson.name); // sunny
//=======================================
Person.prototype.name = 'sunny';
function Person() {}
Person.prototype = {
name: 'cherry'
};
var oPerson = new Person();
console.log(oPerson.name); // cherry
查詢對象構造函數
object.prototype
原型鏈
GrandFather.prototype.lastName = 'yang';
function GrandFather() {
this.bike = 1;
}
Father.prototype = new GrandFather();
function Father() {
this.fortune = {
money: 999999,
house: 4
}
this.name = 'jaja'
}
Son.prototype = new Father();
function Son() {
this.name = 'heihei',
this.age = 20
}
var oSon = new Son();
console.log(oSon.lastName);
oSon.fortune.house += 1; //訪問fortune對象的屬性並賦值,改變相同地址的引用值, 相當於改變原型上的屬性
oSon.fortune = {}; //將fortune屬性指向另一個對象地址,換了一個引用值, 相當於給oSon自己添加屬性
var oSon2 = new Son();
console.log(oSon2.fortune.house); // 5 這個是引用值,後續會受影響
- 除(object.create()創建的對象之外),沿着原型鏈一直向上遊查詢,找到頭都是object.prototype -> {}
- 函數的原型對象constructor默認指向函數本身,原型對象除了有原型屬性外,爲了實現繼承,還有一個原型鏈指針proto,該指針指向上一層的原型對象,而上一層的原型對象的結構依然類似,這樣利用proto一直指向Object的原型對象上,而Object的原型對象用Object.prototype.proto = null表示原型鏈的最頂端,如此變形成了javascript的原型鏈繼承,同時也解釋了爲什麼所有的javascript對象都具有Object的基本方法。
原型方法的重寫
如果原型鏈中上游已經有一個函數,可以在下游重新定義。
改變this指向
function.call(host,num1,num2)
function.apply(host,[num1,num2])
function test(){
console.log(this);
}
test(); //this是window
相當於window.test.call(window);
function.call(調用者)
function Person(name, age) {
this.name = name;
this.age = age;
}
function Student(name, age, myClass, myGrade) {
Person(); // !!沒有寫出來是誰調用的,都是window調用
Person.call(this, name, age); // Studnet函數調用Person函數,保證Person函數的參數
} // call(name,age)->Student(name,age)->Student(實參)
// this是當前調用的函數Student
new Student('cst', 18, 2, 4); //構造函數會在內部隠式創建this對象並返回,
//原因是構造函數本身就是用於創建對象並初始化
//構造函數身份象徵:new
var numObj = {
x: 1,
y: 2
}
function add(a, b) {
console.log(this.x + a + this.y + b);
}
add(); // NaN
add.call(numObj, 3, 4); // 10
繼承
聖盃模式:閉包
var inherit = (function() {
var Cache = function() {}; //緩存函數,每次執行都需要創建一個,沒有必要,寫入閉包
return function(Target, Origin) {
Cache.prototype = Origin.prototype; //下游不影響上游
Target.prototype = new Cache();
Target.prototype.constructor = Target;
Target.prototype.uber = Origin;
}
})();
防止變量污染
立即執行函數