亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

詳解js中的幾種常用設(shè)計(jì)模式

 更新時(shí)間:2020年07月16日 09:19:31   作者:菜小牛  
這篇文章主要介紹了js中的幾種設(shè)計(jì)模式,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下

工廠模式

function createPerson(name, age){
  var o = new Object();  // 創(chuàng)建一個(gè)對(duì)象
  o.name = name;
  o.age = age;
  o.sayName = function(){
   console.log(this.name)
  }
  return o;  // 返回這個(gè)對(duì)象
}
var person1 = createPerson('ccc', 18)
var person2 = createPerson('www', 18)

工廠函數(shù)的問題:
工廠模式雖然解決了創(chuàng)建多個(gè)相似對(duì)象的問題,但是沒有解決對(duì)象識(shí)別問題(即怎樣知道一個(gè)對(duì)象的類型)。如下

person1 instanceof createPerson  // --> false
person1 instanceof Object  // --> true

構(gòu)造函數(shù)模式

function Person(name , age){
 this.name = name;
 this.age = age;
 this.sayName = function(){
 console.log(this.name)
 }
}

var person1 = new Person('ccc', 18)
var person2 = new Person('www', 18)
person1.sayName()  // --> 'ccc'

person1 和person2 分別保存著Person的一個(gè)不同的實(shí)例。這兩個(gè)對(duì)象都有一個(gè)constructor(構(gòu)造函數(shù))屬性指向Person。這正是構(gòu)造函數(shù)模式勝過工廠模式的地方。如下:

console.log(person1 instanceof Person)  // --> true
console.log(person1 instanceof Object)  // --> true
console.log(person2 instanceof Person)  // --> true
console.log(person2 instanceof Object)  // --> true

構(gòu)造函數(shù)模式與工廠模式的區(qū)別:

  1. 沒有顯式的創(chuàng)建對(duì)象
  2. 直接將屬性和方法賦給了this對(duì)象
  3. 沒有return 語(yǔ)句

要?jiǎng)?chuàng)建Person的新實(shí)例,必須使用new操作符。以這種方式調(diào)用構(gòu)造函數(shù)實(shí)際上會(huì)經(jīng)歷一下4個(gè)步驟:

  1. 創(chuàng)建一個(gè)新對(duì)象
  2. 將構(gòu)造函數(shù)的作用域賦給新對(duì)象(因此this就指向了這個(gè)新對(duì)象)
  3. 執(zhí)行構(gòu)造函數(shù)中的代碼(為這個(gè)新對(duì)象添加屬性)
  4. 返回新對(duì)象

構(gòu)造函數(shù)的問題:

使用構(gòu)造函數(shù)的重要問題,就是每個(gè)方法都要在每個(gè)實(shí)例上重新創(chuàng)建一遍。person1和person2中都有一個(gè)名為sayName()的方法,但那兩個(gè)方法不是同一個(gè)Function實(shí)例。因?yàn)樵贓CMAscript中函數(shù)就是對(duì)象,因此每定義一個(gè)函數(shù),也就是實(shí)例化了一個(gè)對(duì)象。從邏輯角度上講,此時(shí)的構(gòu)造函數(shù)也可以你這樣定義:

function Person(name , age){
 this.name = name;
 this.age = age;
 this.sayName = new Function('console.log(this.name)')  // eslint: The Function constructor is eval. (no-new-func)
}

這會(huì)導(dǎo)致,創(chuàng)建的不同的實(shí)例上的同名函數(shù)是不相等的,比如:console.log(person1.sayName() === person2.sayName()) // -->false,然而創(chuàng)建兩個(gè)完全相同的任務(wù)的Function實(shí)例是沒有必要的??梢酝ㄟ^把函數(shù)定義轉(zhuǎn)移到構(gòu)造函數(shù)外部來解決這個(gè)問題。

function Person(name , age){
 this.name = name;
 this.age = age;
 this.sayName = sayName
}
function sayName(){
 console.log(this.name)
}
var person1 = new Person('ccc', 18)
var person2 = new Person('www', 18)

這樣,由于sayName包含的是一個(gè)指向函數(shù)的指針,因此person1和person2對(duì)象就共享了在全局作用域中定義的同一個(gè)sayName()函數(shù)。這樣做確實(shí)解決了兩個(gè)函數(shù)做同一件事的問題,可是新問題又來了:在全局作用域中定義的函數(shù)實(shí)際上只能被某個(gè)對(duì)象調(diào)用,這讓全局作用域有點(diǎn)名不副實(shí)。
帶來的新問題:
如果對(duì)象需要定義很多方法,那么就要定義很多個(gè)全局函數(shù),于是我們這個(gè)自定義的引用類型就絲毫沒有封裝性可言。

原型模式

關(guān)于原型,原型鏈內(nèi)容不在此描述,只討論原型設(shè)計(jì)模式
我們創(chuàng)建的每一個(gè)函數(shù)都有一個(gè)prototype(原型)屬性,這個(gè)屬性是一個(gè)指針,指向一個(gè)對(duì)象,而這個(gè)對(duì)象的用途是包含可以由特定類型的所有實(shí)例共享的屬性和方法。即不必在構(gòu)造函數(shù)中定義對(duì)象實(shí)例的信息,而是將這些信息直接添加到原型對(duì)象中。

function Person(){
}
Person.prototype.name = 'ccc'
Person.prototype.age = 18
Person.prototype.sayName = function(){
 console.log(this.name)
}
var person1 = new Person()
person1.sayName()  // --> ccc

var person2 = new Person()
person2.sayName()  // --> ccc

console.log(person1.sayName === person2.sayName)  // --> true

原型模式的問題:

它省略了為構(gòu)造函數(shù)傳遞參數(shù)初始化參數(shù)的環(huán)節(jié),結(jié)果所有的實(shí)例在默認(rèn)情況下都將取得相同的屬性值。另外,原型模式的最大問題是由其共享的本性所導(dǎo)致的??慈缦聠栴}:

function Person(){
}
Person.prototype = {
 constructor: Person,
 name: 'ccc',
 age: 18,
 friends:['www', 'aaa'],
 sayName: function () {
 console.log(this.name)
 }
}
var person1 = new Person()
var person2 = new Person()

person1.friends.push('bbb')

console.log(person1.friends)  // --> ["www", "aaa", "bbb"]
console.log(person2.friends)  // --> ["www", "aaa", "bbb"]
console.log(person1.friends === person2.friends)  // --> true

帶來的新問題:

如果我們的初衷就是這樣,所有的實(shí)例共用一個(gè)數(shù)組,那么這個(gè)結(jié)果就是想要的??墒?,實(shí)例一般都是要有屬于自己的全部屬性的,這個(gè)問題正是我們很少看到有人單獨(dú)使用原型模式的原因所在。

組合使用構(gòu)造函數(shù)模式和原型模式

創(chuàng)建自定義類型的最常見方式,就是組合使用構(gòu)造函數(shù)模式與原型模式。構(gòu)造函數(shù)模式用于定義實(shí)例屬性,而原型模式用于定義方法和共享的屬性。這種方式還支持向構(gòu)造函數(shù)傳遞參數(shù)。

function Person(name, age){
 this.name = name;
 this.age = age;
 this.friends = ['aaa', 'bbb']
}
Person.prototype = {
 constructor: Person,
 sayName: function(){
 console.log(this.name)
 }
}
var person1 = new Person('ccc', 18)
var person2 = new Person('www', 18)
person1.friends.push('ddd')

console.log(person1.friends)  // --> ["aaa", "bbb", "ddd"]
console.log(person2.friends)  // --> ["aaa", "bbb"]
console.log(person1.friends === person2.friends)  // --> false
console.log(person1.sayName === person2.sayName)  // --> true

這種構(gòu)造函數(shù)與原型混成的模式,是目前ECMAscript中使用最廣泛、認(rèn)同度最高的一種創(chuàng)建自定義類型的方法??梢哉f,這是用來定義引用類型的一種默認(rèn)方式。

動(dòng)態(tài)原型模式

動(dòng)態(tài)原型模式就是可以通過檢查某個(gè)應(yīng)該存在的方法是否有效,來決定是否需要初始化原型。

function Person(name, age){
 // 屬性
 this.name = name
 this.age = age
 // 方法
 if(typeof this.sayName !== 'function'){
 Person.prototype.sayName = function(){
  console.log(this.name)
 }
 }
}

var person1 = new Person('ccc', 18)
person1.sayName()  // --> ccc

這里只有在sayName()方法不存在的情況下,才會(huì)將它添加到原型中。這段代碼只會(huì)在初次調(diào)用構(gòu)造函數(shù)時(shí)才會(huì)執(zhí)行。
注意:

  • 在這里對(duì)原型所做的修改,能夠立即在所有實(shí)例中得到反映。
  • 使用動(dòng)態(tài)原型模式時(shí),不能使用對(duì)象字面量重寫原型。如果在已經(jīng)創(chuàng)建了實(shí)例的情況下重寫原型,那么就會(huì)切斷現(xiàn)有實(shí)例與新原型之間的聯(lián)系。(參考原型與原型鏈中的內(nèi)容)

其它模式

還有寄生構(gòu)造函數(shù)模式和穩(wěn)妥構(gòu)造函數(shù)模式,可自行了解。以上所以知識(shí)內(nèi)容來自《JavaScript高級(jí)程序設(shè)計(jì)》(第三版)。

以上就是詳解js中的幾種常用設(shè)計(jì)模式的詳細(xì)內(nèi)容,更多關(guān)于JS 設(shè)計(jì)模式的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論