標籤:efi 工廠 define 理解 訪問 對象 自己 直接 知識
物件導向
1、原廠模式
function createObject(name,age){ let obj = new Object(); this.name = name; this.age = age; return obj; }let objA = createObject(‘Tom‘,24);let objB = createObject(‘Jane‘,23);typeof ObjA; //Objecttypeof ObjB; //ObjectObjA instanceof Object;ObjA instanceof Object;//方法缺點:不能區分對象執行個體,所有對象執行個體都由Object執行個體化
2、建構函式模式
function Box(name,age){ this.name = name; this.age = age; this.run = function (){ return this.name + this.age; } }function Desk(name,age){ this.name = name; this.age = age; this.run = function (){ return this.name + this.age; } }let box = new Box(‘Tom‘,24);let desk = new Desk(‘Jane‘,23);box instanceof Box; //truebox instanceof Desk; //falsedesk instanceof Desk; //true////知識延伸,對象冒充let o = new Object();Box.call(o,‘Ha‘,25);o.name;
建構函式方式和原型方式變數儲存的方式
3、原型
我們建立的每一個函數都有一個prototype(原型屬性),這個屬性是一個對象,它的用途是包含可以由特定類型的所有執行個體共用的屬性和方法。邏輯上可以這麼理解:prototype通過調用建構函式而建立的那個對象的原型對象。使用原型的好處可以讓所有對象執行個體共用它所包含的屬性和方法。也就是說,不必在建構函式中定義對象資訊,而是可以直接將這些資訊添加到原型中。(我自己的理解,通過建構函式建立的對象會自動建立一個原型對象prototype。)
function Box(){}
Box.prototype.name = ‘Lee‘; //原型屬性
Box.prototype.age = 100;
Box.prototype.run = function () { //原型方法
return this.name + this.age + ‘運行中‘;
}
證明:原型對象內的屬性和方法都被執行個體對象共用
let box1 = new Box();
let box2 = new Box();
Object.is(box1.run,box2.run); //true Object.is(),判斷兩個變數是否相等 (等於box1.run === box2.run);
說明box1和box2中的run方法都指向同一個引用地址。
在原型模式聲明中,多了兩個屬性,這兩個屬性都是建立對象時自動產生的。__proto__屬性是執行個體指向原型對象的一個指標,它的作用就是指向建構函式的原型屬性constructor。通過這兩個屬性,就可以訪問到原型裡的屬性和方法了。
//判斷一個執行個體對象是否指向了原型對象,只要執行個體化了,會自動指向的
Box.prototype.isPrototypeOf(box1); //true 接著上面的代碼
let obj = new Object(); //
Box.prototype.isPrototypeOf(obj);
如果執行個體對象中有name屬性,原型對象中也有name屬性,通過 . 訪問name會列印處執行個體對象中的name屬性。
function Box () {}
Box.prototype.name = ‘guaguaerhao‘;
let box1 = new Box();
box1.name = ‘呱呱二號‘;
console.log(box1.name); //呱呱二號
原型模式的執行流程:
1、先尋找執行個體對象中是否存在屬性,如果存在,則返回
2、如果執行個體對象中沒有該屬性,則在原型對象中尋找,如果存在,則返回
判斷執行個體中是否存在屬性
box1.hasOwnProperty(‘name‘); //true
(name in box1) //不管是原型中有name屬性還是執行個體中有name屬性,都會返回true
判斷只有原型中是否存在屬性
function hasPrototypeProperty(object,property){
return !object.hasOwnProperty(property) && (property in object);
}
4、字面量原型模式
function Box () {}
Box.prototype = {
constructor: Box, //將原型對象的constructor強制指向回Box
name: ‘guaguaerhao‘,
age: 24,
run: function(){
return this.name + this.age;
}
}
ps:原型中最大的缺點就是它的優點,共用。原型模式建立的對象,省略了建構函式傳參,帶來的缺點就是初始化的值都是一樣的。
5、建構函式加原型模式(建構函式和方法分開,沒有一種封裝的感覺,感覺很零碎)
function Box(name,age){ //不共用的使用建構函式
this.name = name;
this.age = age;
this.family = [‘爸爸‘,‘媽媽‘,‘哥哥‘,‘我‘];
}
Box.prototype = { //共用的使用原型
constructor: Box,
run: function () {
return this.name + this.age;
}
}
6、動態原型模式
function Box(name,age){
this.name = name;
this.age = age;
//可是,執行個體化對象的時候,每次都會建立run()方法,浪費記憶體,因為他在每一個對象中都是一樣的功能,沒有必要,每次執行個體化都建立,實際上只需要建立一次。
Box.prototype.run = function () {
return this.name + this.age;
}
}
所以
function Box(name,age){
this.name = name;
this.name = age;
if(typeof this.run !== ‘function‘){ //只會執行個體化一次
Box.prototype.run = function () {
return this.name + this.age;
}
}
}
7、寄生建構函式(原廠模式+建構函式)
function Box(name,age){
let obj = new Object();
obj.name = name;
obj.age = age;
obj.run = function (){
return this.name + this.age;
}
return obj;
}
let obj = new Box(‘ha‘,24);
obj.run();
7、寄生建構函式(原廠模式+建構函式)
function Box(name,age){
let obj = new Object();
obj.name = name;
obj.age = age;
obj.run = function (){
return this.name + this.age;
}
return obj;
}
let obj = Box(‘ha‘,24);
obj.run();
繼承
1、繼承是物件導向中比較核心的概念,ECMAScript只支援繼承:
function Parent(){
this.name = ‘p‘;
}
function Child(){
this.name = ‘c‘;
}
//通過原型鏈繼承,父類執行個體化後的對象執行個體,賦值給子類型的原型屬性
//new Parent()會將建構函式裡的資訊和原型的資訊都交給Child
Child.prototype = new Parent();
2、對象冒充模式
為瞭解決引用共用和超類型無法傳參的問題,採用一種叫借用建構函式的技術,或者成為對象冒充
function Parent(name,age){
this.name = name;
this.age = age;
}
//Parent.prototype.family = ‘家庭‘; //child執行個體無法訪問
function Child(name,age){
Parent.call(this,name,age); //對象冒充,給父類傳遞參數,對象冒充只能繼承建構函式中的屬性,原型中的無法訪問
}
let child = new Child(‘haha‘,24);
child.name;
child.family; //undefined
3、原型鏈加借用建構函式,組合模式
function Parent(age){
this.age = age;
}
Parent.prototype.run = function () { //解決了方法共用
return this.age;
}
function Child(age){
Parent.call(this,age);
}
Child.prototype = new Parent();
javascript物件導向和原型————呱呱二號