單例設計模式(Singleton Pattern)
1. 單例模式解決的問題:
表現形式:
Var obj = {
xxx; xxx,
…
}
2. 作用:
把描述同一件事物的屬性和特徵進行“分組、分類”(存儲在同一個推內存空間中),因此避免了全局變量之間的衝突和污染
var pattern1 = {name: ‘xxx’}
var pattern2 = { name: ‘xxx’}
//name值並不是一個值,屬於兩個堆內存空間中
在單例設計模型中,obj不僅僅是對象名,它被稱爲”命名空間[NameSpace]”,<br />把描述事務的屬性存放到命名空間中,多個命名空間是獨立分開的,互不衝突
3. 單例設計模式命名的由來
每一個命名空間都是js中Object這個內置基類的實例,而實例之間是相互對立不干擾的,所以我們稱它爲“單例”:單獨的實例
4. 高級單例模式
- 在給命名空間賦值的時候,不是直接賦值一個對象,而是先執行匿名函數,形成一個私有作用域AA(不銷燬的棧內存),在AA中創建以愛國堆內存,把內存地址賦值給命名空間
- 這種模式的好處:我們完全可以在AA中創造很多內容(變量或者函數),哪些需要供外面的調取使用的,我們暴露到返回的對象中(模塊化實現的一種思想)
如下圖例子:
var nameSpace = (function () {
var n = 12
function fn () {}
return {
fn: fn
}
})
this:
- 給當前元素的某個事件綁定方法,當事件觸發方法執行的時候,方法中的this是當前元素操作的元素對象
- 普通函數執行,函數中的this取決於執行的主體,誰執行的,this就是誰(執行主體:方法執行,看方法名前面是否有“點”,有的話,點前面是誰this就是誰,沒有this是window)
function fn () {
console.log(1)
}
var obj = {fn:fn}
// 執行的是相同的方法,但是this指向不同
obj.fn(); // this=> obj
fn(); // this指向window
// 自執行函數,方法的this指向window
~function() {
// this => window
} ()
var n = 2;
var obj = {
n: 3,
fn:(function (n) {
n *= 2;
this.n += 2;
var n = 5;
return function(m) {
this.n *= 2;
console.log(m + (++n))
}
//自執行函數執行的時候,堆內存還沒有存儲完成鍵值對,和obj還沒有關係,此時obj=undefined,obj.n會報錯
})(n)
}
var fn = obj.fn
fn(3) // 9
obj.fn(3) // 10
console.log(n, obj.n) // 8 6
解析如下圖:<br />
<br />
5. 基於單例的模塊化開發
- 團隊協助開發的時候,會把產品按照功能板塊進行劃分,每個功能板塊都有專人負責開發
- 把各個版塊之間公用的部分進行提取封裝,後期在想實現這些功能,直接的調取即可
工廠模式(Factory Pattern)
工廠模式(Factory Pattern)
- 把實現相同功能的代碼進行‘封裝’,以此來實現‘批量生產’(後期想要實現這個功能,我們只需執行函數即可)
- ‘低耦合高內聚’:減少頁面中的冗餘代碼,提高代碼的重複使用率
function createPerson (name, age) {
var obj = {}
obj.name = name;
obj.age = age;
return obj
}
var p1 = createPerson('xxx', 25)
var p2 = createPerson('xxx', 25)
console.log()
擁抱面向對象
面向對象編程,我們需要掌握“對象、類、實例”的概念<br />對象:萬物皆對象<br />類: 對象的具體細分(按照功能特點進行分類:大類、小類)<br />實例:類中具體的一個事物(拿出類別中的具體一個實例進行研究,那麼當前類別下的其他實例也具備這些特點和特徵)<br />js中內置類<br />object 對象類 (基類)
Number數字類 String Boolean Null Undefined Array RegExp Function Date ...
HTMLCollection 每一個元素集合都是它的實例
NodeList
-
EventTarget
Node: Element:HTMLBodyElement HTMLDivElement<br /> WindowProperties: Window: window對象就是它的實例
基於基類,我們可以創建很多自己的類(自定義類)
構造函數(constructor)
1. 基於構造函數創建自定義類(constructor)
- 在普通函數執行的基礎上“new xxx()”,這樣就不是普通函數執行了,而是構造函數執行,當前函數名稱稱之“類名”,接收返回的函數結果是當前類的一個實例
- 自己創建的類名,最好第一個單詞首字母大寫
- 這種構造函數設計模式執行,主要用於組件、類庫、插件、框架等的封裝,平時編寫業務邏輯一般不用這樣處理
function Fn() {}
var f1 = new Fn() //Fn是類 f1是類的一個實例
var f2 = new Fn() // f2也是Fn的一個實例
// f1和f2是獨立的,互不影響
2. JS中創建值有兩種方式:
- 字面量方式
var obj = {}
- 構造函數模式
var obj = new Object()
不管哪一種方式創造出來的都是Object類的實例,而實例之間是獨立分開的,所以var xxx = {} 這種模式也是js中的單例模式.
3. 基本數據類型基於兩種不同的模式創建出來的值是不一樣的
- 基於字面量方式創建出來的值是基本類型值
- 基於構造函數創建出來的值是引用類型
var num1 = 12; // 數字類Number實例,數字類的特殊表達方式之一
var num2 = new Number(12); // 數字類的實例
console.log(typeof num1) // "number"
console.log(typeof num2) // "object"
4. 構造函數運行機制
<br />普通函數執行:
- 形成一個私有的作用域
- 行參賦值
- 變量提升
- 代碼執行
- 棧內存釋放問題
<br />
<br />構造函數執行:<br />既有普通函數執行的一面,也有構造函數執行的一面
function Fn(name, age) {
var n = 10;
this.name = name;
this.age = age + n;
}
var f1 = new Fn('xxx', 20);
var f2 = new Fn('aaa', 30)
console.log(f1=== f2); // false:兩個不同的實例(兩個不同的堆內存地址)
console.log(f1.age) //30
console.log(f2.name) // 'aaa'
console.log('name' in f1) // true name和age在兩個不同的實例都有存儲,但是都是每個實例自己的私有屬性
console.log(f1.n) // undefined 只有this.xxx =xxx 的才和實例有關係,n是私有作用域的一個私有變量而已
- 像普通函數執行一樣,形成一個私有作用域(棧內存)
行參賦值、變量提升,都是私有變量
- 【構造函數獨有操作】在js代碼自上而下執行之前,首先在當前形成的私有棧中創建一個對象(創建一個堆內存:暫時不存儲任何東西),並且讓函數中的執行主體(this)指向這個新的堆內存(this === 創建的對象)
- 代碼開始自上而下執行
- 【構造函數執行獨有】代碼執行完成,把之前創建的堆內存地址返回(瀏覽器默認返回)
5. 構造函數中的一些細節問題
- 構造函數執行,不寫return ,瀏覽器會默認返回創建的實例,如果自己寫了return
- return 是一個基本值,返回的結果依然是類的實例
- 直接return是結束代碼執行,不會覆蓋實例
- 如果返回的是引用值,則會把默認值返回的實例覆蓋,此時接收到結果就不再是當前類的實例了
所以構造函數執行的時候,儘量減少return使用,防止覆蓋實例<br />**
- 在構造函數執行的時候,如果不需要傳遞實參數,我們可以省略小括號,還是創建實例(和加小括號是沒有區別的)
- instanceof: 檢測某一個實例是否隸屬於這個類
- in:檢測當前對象是否存在某個屬性(不管當前這個屬性是對象的私有屬性還是公有屬性,只要有結果就是true)
- hasOwnProperty: 檢測當前屬性是否爲對象的私有屬性(不僅要有這個屬性,而且必須還是私有的纔可以)
原型鏈設計模式(prototype & proto)
1. 原型鏈機制
原型(prototype)、原型鏈(proto)<br />[函數]<br />普通函數、類(所有的類:內置類、自己創建的類)<br />[對象]<br />普通對象、數組、正則、Math<br />實例是對象類型的(除了基本類型的字面量創建的值)<br />prototype的值也是對象類型的<br />函數也是對象類型<br />...
- 所有的函數數據類型都是天生自帶一個屬性:prototype(原型),這個屬性的值是一個對象,瀏覽器會默認給它開闢一個堆內存
- 在瀏覽器給prototype開闢的堆內存中,有一個天生自帶的屬性:constructor,這個屬性存儲的值是當前函數本身
- 每一個對象都有一個proto的屬性,這個屬性指向當前實例所屬類的prototype
原型鏈:
它是一種基於proto向上查找的機制。當我們操作實例的某個屬性或者方法的時候,首先找自己空間中私有屬性或者方法
- 找到了,則結束查找,使用自己私有的即可
- 沒有找到,則基於proto找所屬類的prototype,如果沒找到,基於原型上的proto繼續,向上查找,一直找到Object.prototype的原型爲止,如果再沒有,操作的屬性或者方法不存在
function Fn() {
var n = 10;
this.AA = function () {
console.log('AA')
}
this.BB = function () {
console.log('BB')
}
}
Fn.prototype.AA = function () {
console.log('AA[公]')
};
var f1 = new Fn;
var f2 = new Fn
解析如下圖:<br />