首頁 > web前端 > js教程 > 主體

JavaScript中建立物件的模式總結_javascript技巧

WBOY
發布: 2016-05-16 15:04:47
原創
1111 人瀏覽過

JavaScript中建立物件的模式總結

**JavaScript建立物件模式:

對象字面量
工廠模式
建構函式模式
原型模式
結合建構子與原型模式
原型動態模式
**

物件導向的語言大都有一個類別的概念,透過類別可以建立多個具有相同方法和屬性的物件。雖然從技術上講,javascript是一門物件導向的語言,但是javascript沒有類別的概念,一切都是物件。任意一個物件都是某種引用類型的實例,都是透過現有的參考類型建立;引用類型可以是原生的,也可以是自訂的。

1、物件字面量

var person = {
    name : 'Nicholas';
    age : '22';
    job :"software Engineer"
    sayName: function() {
      alter(this.name);
  }
}
登入後複製

範例中建立一個名為person的對象,並為它添加了三個屬性(name,age,job)和一個方法(sayName()),其中,sayName()方法用於顯示this.name(被解析為person.name)的值。

物件字面量可以用來建立單一對象,但這個方法有個明顯的缺點:使用同一個介面建立很多對象,會產生大量重複的程式碼。

2、工廠模式

工廠模式是軟體工程領域中一種廣為人知的設計模式,工廠模式抽象化了創建具體物件的過程,用函數來封裝以特定的介面創建物件的細節。

function createPerson(name,age,job){
  var o = new object{};
  o.name=name;
  o.age=age;
  o.job=job;
  o.sayName=function(){
    alert(this.name);
  };
  return o;
}
var person1=creatPerson("Nicholas",22,"software Engineer");
var person2=creatPerson("Greg",24,"student");
登入後複製

函數creatPerson{}能夠根據接受的參數建立一個包含所有必要資訊的Person物件。可以無數次的呼叫這個函數,每次都會傳回一個包含三個屬性一個方法的物件。

工廠模型雖然解決了創建多個相似物件的問題,卻沒有解決物件辨識的問題(也就是怎麼知道一個物件的類型)。

3、建構子模式

function Person(name,age,job) {
  this.name = name;
  this.age = age;
  this.job = job;
  this.sayName = function() {
    alert(this.name);
  }
}
//通过new操作符创建Person的实例
var person1 = new Person("Nicholas",22,"software Engineer");
var person2 = new Person("Greg",24,"student");
person1.sayName(); //Nicholas
person2.sayName(); //Greg
登入後複製

與工廠模式不同的是

沒有顯示的創建物件

直接將屬性和方法賦給了this物件

沒有return語句

建立Person的新實例,必須使用new運算元。呼叫建構子的4個步驟:

建立一個新物件

將建構函數的作用域賦給新物件(this指向了這個新物件)

執行建構函式中的程式碼

回傳新物件

這個例子中所建立的所有物件既是Object的實例,也是Person實例。可以透過instanceof操作符驗證。

alert(person1 instanceof Object);//true
登入後複製

建構函式模式也有自己的問題,實際上,sayName方法在每個實例上都會被重新創建一次,需要注意的是,透過實例化創建的方法並不相等,以下程式碼可以證明

alert(person1.sayName == person2.sayName);//false
登入後複製

可以將方法移到建構器的外部作為全域函數來解決這個問題。

function Person(name,age,job) {
  this.name = name;
  this.age = age;
  this.job = job;  
}
function sayName() {
    alert(this.name);
  }
登入後複製

在全域下建立的全域函數實際上只能被由Person建立的實例調用,這就有點名不副實了;如果物件需要定義很對方法,那麼就要定義很多個全域函數,缺少封裝性。

4、原型模式

JavaScript中創建的每個函數都有一個prototype(原型)屬性,它是一個指針,指向一個對象,包含了可以由特定類型的所有實例共享的屬性和方法(讓所有的對象實例共享它的屬性和方法)

function Person() {}
  Person.prototype.name ="Nicholas";
  Person.prototype.age = 22;
  Person.prototype.job = "software Engineer";  
  Person.prototype.sayName(){
    alert(this.name);
  };
 var person1 = new Person();
 person1.sayName(); //Nicholas
alert(person1.sayName == person2.sayName);//true
登入後複製

以上代码做了这几件事情:

定义了一个构造函数Person,Person函数自动获得一个prototype属性,该属性默认只包含一个指向Person的constructor属性
通过Person.prototype添加三个属性,和一个方法

创建一个Person的实例,随后在实例上调用了sayName()方法

JavaScript中建立物件的模式總結_javascript技巧

JavaScript中建立物件的模式總結_javascript技巧

JavaScript中建立物件的模式總結_javascript技巧

图中展示了Person构造函数、Person的原型属性以及Person的两个实例,之间的关系。Person.prototype指向了原型对象,Person.prototype.constructor有指回了Person。原型对象中除了包含constructor属性,还包含后来添加的其他属性和方法,Person的两个实例person1和person2都包含一个内部属性,该属性仅指向Person.prototype。

sayName()方法的调用过程:

在person1实例上查找logName()方法,发现没有这个方法,于是追溯到person1的原型

在person1的原型上查找sayame()方法,有这个方法,于是调用该方法

基于这样一个查找过程,我们可以通过在实例上定义原型中的同名属性,来阻止该实例访问原型上的同名属性,需要注意的是,这样做并不会删除原型上的同名属性,仅仅是阻止实例访问。

function Person() {}
  Person.prototype.name ="Nicholas";
  Person.prototype.age = 22;
  Person.prototype.job = "software Engineer";  
  Person.prototype.sayName(){
    alert(this.name);
  };
 var person1 = new Person();
 var person2 = new Person();
 person1.name="Greg"
alert(person1.name) //Greg 来自实例
alert(person2.name) //Nicholas 来自原型
登入後複製

使用delete操作符可以完全删除实例属性

delete person1.name;
alert(person1.name) //Nicholas 来自原型
登入後複製

使用hasOwnProperty()方法可以检测一个属性是存在于实例还是原型中

function Person() {}
  Person.prototype.name ="Nicholas";
  Person.prototype.age = 22;
  Person.prototype.job = "software Engineer";  
  Person.prototype.sayName(){
    alert(this.name);
  };
 var person1 = new Person();
 var person2 = new Person();
 alert(person1,hasOwnProperty("name"));//false
 person1.name="Greg"
alert(person1.name) //Greg 来自实例
 alert(person1,hasOwnProperty("name"));//true
alert(person2.name) //Nicholas 来自原型
 alert(person2,hasOwnProperty("name"));//false
 delete person1.name;
alert(person1.name) //Nicholas 来自原型
 alert(person1,hasOwnProperty("name"));//false
登入後複製

下图展示了在不同情况下实例与原型之间的关系

JavaScript中建立物件的模式總結_javascript技巧

简单的原型语法

function Person() {}
 Person.prototype={
 name :"Nicholas",
 age : 22,
 job : "software Engineer", 
 sayName:function(){
    alert(this.name);
    }
  };
登入後複製

在上面的代码中constructor属性不再指向Person了,通过constructor无法确定对象的类型了。可以像下面这样特意将他设置回适当的值

function Person() {}
 Person.prototype={
 constructor:Person,
 name :"Nicholas",
 age : 22,
 job : "software Engineer",  
 sayName:function(){
    alert(this.name);
    }
  };
登入後複製

重设constructor属性会导致它的[[Enumerable]]特性被设置为true,默认情况,原生的constructor属性是不可枚举的,可以使用Object.defineProperty()方法来改变

Object.defineProperty(Person.prototype,"constructor",{
  enumerable:false,
  value:Person
});
登入後複製

原型中查找值的过程是一次搜索,原型对象所做的任何修改都能从实例上立即反应出来

var friend=new Person();
Person.prototype.sayHi=function(){
  alert("hi);
}
friend,sayHi();//"hi"(没有问题)
登入後複製

person实例是在添加新方法之前创建的,但仍可以访问新添加的方法,原因是实例与原型之间的松散连接关系
重写原型对象后的情况

function Person() {}
var friend=new Person();
 Person.prototype={
 name :"Nicholas",
 age : 22,
 job : "software Engineer", 
 sayName:function(){
    alert(this.name);
    }
  };
  friend.sayName();//error
登入後複製

调用friend.sayName()时发生错误的原因是,friend指向的原型中不包含以该字段命名的属性,如下图。

JavaScript中建立物件的模式總結_javascript技巧

原型对象的问题

原型对象省略了为构造函数传递初始化参数这一环节,所有势力在默认情况下都取得相同的属性值。原型模型最大的问题是有其共享本性所导致的。当原型模型包含引用类型的属性来说,问题就比较严重了。来看下面的例子。

function Person() {}
 Person.prototype={
 constructor:Person,
 name :"Nicholas",
 age : 22,
 job : "software Engineer",  
 friends:["Shelby","Court"],
 sayName:function(){
    alert(this.name);
    }
  };
  var person1=new Person();
  var person2=new Person();
  person1.friend.push("Van");
  alert(person1.friends);//"Shelby,Court,Van"
  alert(person2.friends);//"Shelby,Court,Van"
 alert(person1.friends==person2.friends);//true
登入後複製

5、组合使用构造函数模式和原型模式

组合使用构造函数模式和原型模式中,构造函数用于定义实例属性,原型模型用于定义方法和共享的属性。这样每个实例都会有自己的一份实例属性的副本,同时也可以共享对方法的引用,最大限度的节省了内存。

function Person(name,age,job) {
  this.name = name;
  this.age = age;
  this.job = job;  
  this.friends=["Shelby","Court"];
}
Person.prototype={
 constructor:Person,
 sayName:function(){
    alert(this.name);
    }
  }
var person1=new Person("Nicholas",22,"software Engineer");
var person2 = new Person("Greg",24,"student");
person1.friend.push("Van");
  alert(person1.friends);//"Shelby,Court,Van"
  alert(person2.friends);//"Shelby,Court"
 alert(person1.friends==person2.friends);//false
 alert(person1.sayName==person2.sayName);//true
登入後複製

6、动态原型模式

原型动态模式将需要的所有信息都封装到构造函数中,通过if语句判断原型中的某个属性是否存在,若不存在(在第一次调用这个构造函数的时候),执行if语句内部的原型初始化代码。

function Person(name,age) {
  this.name = name;
  this.age = age;
  this.job =job;
//方法
  if(typeof this.sayName != 'function') {
  Person.prototype.sayName = function() {
      alert(this.name);
    };   
  }
}
var friend = new Person('Nicholas','22','Software Engineer');//初次调用构造函数,此时修改了原型
var person2 = new Person('amy','21');//此时sayName()方法已经存在,不会再修改原型
登入後複製

推薦閱讀:

js物件導向之常見建立物件的幾種方式(工廠模式、建構函式模式、原型模式)

以上所述是小編給大家介紹的JavaScript中創建物件的模式,希望對大家有幫助!

來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新問題
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板