原型鏈模式基礎
//構造函數模式
function CreateJsPerson(name,age){
this.name = name;
this.age = age;
this.writeJs = function(){
console.log('my name is ' + this.name +'i can write js')
}
}
var p1 = new CreateJsPerson('zzz',20);
var p2 = new CreateJsPerson('aaa',12);
console.log(p1.writeJs === p2.writeJs)//false
構造函數模式中擁有了類和實例的概念,並且實例和實例之間是相互獨立開的–>實例識別
//原型鏈模式
function CreateJsPerson(name,age){
this.name = name;
this.age = age;
}
CreateJsPerson.prototype.writeJs = function (){
console.log('my name is ' + this.name +'i can write js')
}
var p1 = new CreateJsPerson('zzz',20);
var p2 = new CreateJsPerson('aaa',12);
console.log(p1.writeJs === p2.writeJs)//true
基於構造函數模式的原型模式解決了方法或者屬性共有的問題
把實例之間相同的屬性和方法提取成公有的屬性和方法
想讓誰公有就把它放在CreateJsPerson.prototype上
- 每一個函數數據類型(普通函數,類),都有一個天生自帶的屬性:prototype(原型),並且這個屬性是這個對象數據類型的值
- 並且在protype在瀏覽器上瀏覽器天生給它加一個屬性constructor(構造函數),屬性值是當前函數本身
- 每一個對象數據類型(普通的對象,實例,prototype…)也天生自帶一個屬性:__ proto __ ,這個屬性是當前實例所屬類的原型
function Fn(){
this.x = 100;
}
Fn.prototype.getX = function(){
console.log(this.x)
}
var f1 = new Fn;
var f2 = new Fn;
console.log(Fn.prototype.constructor === Fn);//true
f1.hasOwnPrototype('x');//hasOwnPrototype是f1的一個屬性
f1.getX === f2.getx //true
f1.__proto__getX === f2.getX//true
f1.getX === Fn.prototype.getX //true
Object是js中所有對象屬性類型的基類
- f1 instanceof Object -->true 因爲f1通過__proto__可以向上級查找,不管有多少級,最後總能找到Object
- 在Object.prototype上沒有__proto__這個屬性
- 原型鏈模式
- f1.hasOwnPrototype(‘x’);//hasOwnPrototype是f1的一個屬性
- 但是我們發現f1的私有屬性上並沒有這個方法,那如何處理呢?
- 通過對象名.屬性名的方式獲取屬性值的時候,首先在對象的私有的屬性進行查找,如果在私有中存在這個屬性,則獲取的是私有的屬性值
- 如果私有的沒有,則通過__proto__找到所屬類的原型(類的原型上定義的屬性和方法都是當前實例的公有屬性和方法)
- 如果原型上也沒有,則通過原型上的__proto__繼續向上查找,一直找到Object.prototype爲止
- 這種查找的機制就是我們的“原型鏈模式”
function Fn(){
this.x = 100;
this.sum = function(){};
}
Fn.prototype.getX = function(){
console.log(this.x)
}
Fn.prototype.sum = function(){};
var f1 = new Fn;
var f2 = new Fn;
f1.sum = function(){
//修改自己私有的sum
}
f1.__proto__.sum= function(){
//修改所屬類原型上的sum
}
f1.prototype.sum= function(){
//修改公有上的sum
}
原型鏈模式擴展-this和原型擴展
function Fn(){
this.x = 100;
this.y = 200;
this.getY = function(){
console.log(this.y)
}
}
Fn.prototype = {
constructor:Fn,
y:300,
getX:function(){
console.log(this.x);
},
getY:function(){
console.log(this.y);
}
};
var f = new Fn;
f.getX();//this是f-->console.log(f.x)-->100
f.__proto__.getX();//this是f.__proto__-->console.log(f.__proto__.x) -->undefined
Fn.prototype.getX();//this是Fn.prototype -->console.log(Fn.prototype.x) -->undefined
f.getY();//this是f-->console.log(f.y)-->200
f.__proto__.getY();//this是f.__proto__-->console.log(f.__proto__.y)-->
- 在原型模式中,this常用的有兩種情況
- 在類中this.xxx=xxx ->當前類的實例
- 在某一個方法中的this ->看執行的時候“.”,前面是誰,this就是誰
- 需要先確定this的指向(this是誰)
- 把this替換成對應的代碼
- 按照原型鏈
Array.prototype.myUnique = function(){
//this-->
}
var ary = [];
ary.myUnique();//this-->ary(常用)
Array.prototype.myUnique();//this-->Array.prototype
在內置類的原型上擴展我們的方法:去重(還有很多方式)
Array.prototype.myUnique = function(){
//this-->ary
var obj = {};
for(var i=0;i<this.length;i++){
var cur = this[i];
if(obj[cur] == cur){
this[i] = this[this.length - 1];
this.length--;
i--;
continue;
}
obj[cur] = cur;
}
obj = null;
}
var ary = [12,13,12,13,14,15];
ary.myUnique();//this-->ary(常用)
//鏈式寫法:執行完成數組的一個方法可以緊接着執行下一個方法
//原理:ary爲什麼可以使用sort方法?因爲sort是Array.prototype上公有的方法,而數組ary是Array這個類的一個實例
//sort執行完成的返回值是一個排序後的"數組",可以繼續執行reverse
//reverse執行完成的返回值是一個數組,可以繼續執行pop
//pop執行完成之後的返回值是被刪除的那個元素,不是一個數組了,所以在執行push報錯
ary.sort(function(a,b){
return a-b;
}).reverse().pop();