1. 程式人生 > >javascript面向對象和原型————呱呱二號

javascript面向對象和原型————呱呱二號

無法訪問 原型模式 冒充 判斷 傳遞 pre asp clas 相等

面向對象

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;    //Object
typeof ObjB;    //Object
ObjA 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;  //true box instanceof Desk;  //false desk 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面向對象和原型————呱呱二號