一、函數(建構子)、原型、實例物件之間的關係
A、函數與原型的關係
1、只要建立了一個函數,那麼它就會根據一組特定的規則為該函數創建一個prototype屬性(原型物件)
如:
function fun(){
}
console.log(fun.prototype); //fun {},說明prototype是一個物件中定義的屬性、方法:原型中定義的屬性、方法是所有呼叫建構子實例化物件所共享的
如果建構函式中定義了原型中的同名屬性方法時,那麼實例就會呼叫重新定義的屬性與方法了;當一個函式使用new運算元實例化一個物件時,它用來識別實例化物件的類型(並沒有太大的實際意義)
如:
function fun(name){
console.log(fun.prototype.name == this.name); //true(yjh)
this.name = "yjh1";
console.log(this.name);//yjh1
console.log(fun.prototype.name ==
console.log(fun.prototype.name ==
console.log(fun.prototype.name ==
); ,yjh1)
}
fun.prototype = {
constructor: fun,
name: "yjh"
}
var fun1 = new fun();
console.log(fun1.constructor == fun); //true
B、實例化物件與原型的關係
如:
function fun(name,age){
this.name = name;
this.age = age;
. sayName = function(){
alert(this.name);
}
}
fun.prototype = { }: constructor func. {
alert(this.age);
}
}
var fun1 = new fun("yjh","23");
console.log(fun1.__proto__) //fun { age="22", sayAge=function()}
console.log(funconsole. .__proto__ == fun.prototype); //true
C、實例物件與函數(建構子)的關係
由於原型(prototype)中的constructor屬性指向建構函數,因此實例物件也擁有建構子中定義的屬性和方法
如:
function fun(name ,age){
this.name = name;
this.age = age;
this.sayName = function(){
un("yjh", "23");
fun1.sayName(); //yjh
D、函數(建構子)與實例物件、原型三者之間的關係
1、在呼叫實例化物件屬性,方法時,那麼首先會搜尋實例物件本身定義的屬性和方法,如果沒有的話,會繼續搜尋原型
function fun(name,age){
this.name = name; this.age = age;sayName age; = function(){
alert(this.name);
}
}
fun.prototype.age = "22";
}
var fun1 = new fun("yjh","23");
fun1.age = 24;
fun1.sayAge(); //24 ,呼叫了原型中的方法;
首先搜尋sayAge方法,實例物件中沒有,搜尋原型,在原型中找到sayName方法,繼續搜尋age屬性,發現在fun1實例物件中已有定義age值,因此直接使用,不再繼續搜尋了;如果沒有直接在fun1實例物件定義age屬性的話,那麼結果就是23了,原因是因為建構子重新定義了實例物件的age屬性
________________________________________
二、物件導向模式:
對函數的初步理解:
a、JavaScript中的任何一個函數都是一個Function類型的一個實例,也是一個Object類型的實例,定義了一個function函數,那麼它就是一個實例對象,實例對象的內部屬性__proto__指向了Object構造函數的原型prototype屬性,因此實例繼承了Object對象的預設屬性和方法;
b、普通函數預設回傳undefined,建構子回傳一個實例對象。
1、創建對象,使用一個特定接口new Object()
缺點:使用同一個接口創建很多對象,會產生大量重複的代碼
2、使用工廠模式,用函數來封裝,以特定接口創建對象
如:
function createObj(name,age){
var o = new Object();
o.name = name;
o.age = 5age; ,23)
優點:解決了使用一個介面建立多個相似物件產生大量重複程式碼的問題
缺點:沒有解決物件辨識的問題,即o1是怎麼樣的一個物件類型
3、建構函式模式,JavaScript沒有類概念
如:
this.name = name;
this.age = age;
this.sayName = function(){
alert("hi" + this.name);
}
}
var obj1 = new CreateObj("yjh1",23);
var obj2 = new CreateObj("yjh2",23);
化優點類型www.2cto.com
缺點:建構子定義的屬性和方法不是所有實例所共享的,各實例調用的方法是兩個不同Function類型的實例(obj1.sayName != obj2.sayName)
4、原型模式
如:
}
CreateObj.prototype = {
constructor: CreateObj,
name: "yjh",): ],
sayName: function(){
alert(this.name);
}
}
var obj1 = new CreateObj();
var obj2 = new CreateObj();
alert(obj1.sayName == obj2.sayName);/ /true
obj1.colors.push("c");
alert(obj2.colors);//a,b,c
說明:呼叫obj1,obj2實例的屬性和方法,首先會搜尋實例本身定義的屬性和方法,如果沒有,由於實例的__proto__內部屬性指向原型,
因此會繼續搜尋原型中定義的屬性和方法
優點:原型中定義的屬性和方法是所有實例物件所共享的,解決了多個函數實現相同功能的問題
缺點:如果在原型中定義的屬性包含的是引用類型的值,那麼透過修改一個實例屬性值會影響到另一個實例屬性值,這正是由於原型的共享本質所造成的
5、組合模式(建構子模式與原型模式)
function CreateObj(name,age){
console.log(this.name);//yjhyjh
this.colors = ["a","b"];
}
CreateObj.prototype = {
constructor: CreateObj,: "
constructor: 名詞 return this.name;
}
}
var obj1 = new CreateObj("yjh1",23);
var obj2 = new CreateObj("yjh2",23);
alert(obj.sayName Name /true
alert(obj1.sayName());//yjh1
alert(obj2.sayName());//yjh2
obj1.colors.push("c");
alert(obj2.colors);// a,b
說明:把所有實例不需要共享的屬性定義在構造函數中,把需要共享的屬性,方法定義在原型中,互補構造函數模式和原型模式的優缺點,
原型是所有實例化對象的原型物件,實例與原型之間是透過實例內部屬性__proto__連接到原型,所有實例共享原型中的屬性和方法,如果構造函數中重新定義了原型中的同名屬性、方法,
那麼實例對象將會呼叫建構函式中定義的屬性與方法。
6、繼承(實現繼承,原型鏈)
就是把一個構造函數的原型作為另一個構造函數的實例化對象,那麼這個實例化原型對象就會繼承另一個構造函數的原型屬性和方法,這就是所謂的原型鏈
如:
function Fun1(){
this.name = ["yjh1","yjh2"];
}
Fun1.prototype = {. alert (this.name)
}
}
function Fun2(){}
Fun2.prototype = new Fun1();
var fun2 = new Fun2();
name.push("yjh3"); //fun2.name = ["yjh1","yjh2","yjh3"];
var fun3 = new Fun2();
alert(fun3.name);//yjh1, yjh2,yjh3
缺點:來自包含引用類型值的原型,原型中定義的屬性,方法是所有實例所共享的,Fun2.prototype原型物件是Fun1類型的一個實例,
因此原型物件中有包含引用類型值的name屬性,當實例化多個Fun2類型物件時,所有的實例物件都共享這個原型name屬性,透過修改實例中的name屬性值,
會直接修改原型中定義的name屬性值
7、組合繼承(繼承與借用建構子)
如:
function Fun1(){
}
Fun1.prototype = {🜠2"];
}
Fun1.prototype = {🜠. ){
alert(this.name)
}
}
function Fun2(){
Fun1.call(Function Fun2(){
Fun1.call(F); fun2 = new Fun2();
fun2 .sayName();//yjh1,yjh2
fun2.name.push("yjh3"); //fun2.name = ["yjh1","yjh2","yjh3"];
var fun3 = new Fun2() ;
alert(fun2.name);//yjh1,yjh2,yjh3
alert(fun3.name);//yjh1,yjh2
說明:由於構造函數中定義的屬性,方法不是所有實例共享的,而且會覆蓋原型中定義的屬性與方法,所以它不會因為實例化原型物件(Fun2.prototype)中包含了引用型別值的屬性而
存在的問題