摘要:聲明設(shè)計模式系列是來自設(shè)計模式與開發(fā)這本書的讀書筆記,會結(jié)合自身的理解和一些項目經(jīng)驗做筆記,原書作者曾探前言什么是設(shè)計模式,設(shè)計模式就是在某種場合下對某個問題的一種解決方案。
前言聲明: 【JavaScript設(shè)計模式】 系列 是來自《JavaScript設(shè)計模式與開發(fā)》這本書的讀書筆記,會結(jié)合自身的理解和一些項目經(jīng)驗做筆記,原書作者 曾探
什么是設(shè)計模式,設(shè)計模式就是在某種場合下對某個問題的一種解決方案。說通俗一點就是給一段代碼起個名字而已,比如一個用玻璃做的能裝水的東西,給它起個名字叫水杯,
大家一提到水杯就知道什么對象,具有什么功能,這樣大家一想到要喝水就找個水杯這么個東西,滿足需求
JavaScript是一門典型的動態(tài)類型語言。記住這一特性很重要,比如js有個數(shù)組類型Array,要是一個對象,這個對象具有l(wèi)ength屬性,還擁有slic,splice方法,那也可以將這個對象當(dāng)做數(shù)組來用。這完全是可以的,因為語言是動態(tài)的,我們可以面向接口編程,而不是面向?qū)崿F(xiàn)編程。
2、多態(tài)也正因為js是動態(tài)類型語言,所以js本身具有多態(tài)的特性。
什么是多態(tài)呢:多態(tài)就是同一操作作用于不同對象,產(chǎn)生不同的結(jié)果
例子:
function fun(obj) { obj.log() } function Obj1() { } Obj1.prototype.log = function () { console.log("....Obj1......") } function Obj2() { } Obj2.prototype.log = function () { console.log("....Obj2......") } fun(new Obj1()) // ....Obj1...... fun(new Obj2()) // ....Obj2......
給函數(shù) fun 傳遞不同對象,能得到不同的結(jié)果
這要是在Java就要設(shè)計成子類繼承同一個父類,調(diào)用的時候向上轉(zhuǎn)型才能調(diào)用同一個父類方法得到不同結(jié)果,多麻煩呀
JavaScript是一門動態(tài)語言,既沒有檢查創(chuàng)建的對象類型,也沒有檢查傳遞的參數(shù)類型,所以實現(xiàn)
多態(tài)就變得尤為簡單,不必諸如向上轉(zhuǎn)型的技術(shù)來實現(xiàn)多態(tài)
JavaScript是沒有私有變量和共有變量或共有方法的,但它有個函數(shù)作用域,我們可以利用這一特性來滿足這一點
例子:
var fun2 = (function () { var _name = "my name is 田生" return { name: _name, pubFun: function () { console.log(".....pubFun.....") } } })() console.log(fun2.name) // my name is 田生 console.log(fun2.pubFun()) //.....pubFun.....4、JavaScript中的原型繼承
JavaScript的對象不是通過實例化得到的,而是通過克隆原型對象Object.prototype得到的。
所以經(jīng)常會預(yù)定一個面試題是,js 的 new 操作做了哪些工作?那你可以這樣回答,new 操作符是
執(zhí)行一個構(gòu)造函數(shù),函數(shù)里面克隆了 Object.prototype 對象,并把新對象附上屬性值返回出去。
例子:
function Obj() { this.name = "田生" } var o1 = new Obj() console.log(o1.name) // 田生 // 相當(dāng)于 function CloneObj() { var obj = new Object() // 從 `Object.prototype` 克隆一個新對象 obj.name = "田生" return obj } var o2 = CloneObj() console.log(o2.name) // 田生5、JavaScript中的原型璉
如果對象無法響應(yīng)某個請求時,它會把這個請求委托給它的構(gòu)造器的原型prototype去執(zhí)行
例子:
function Obj() { this.name = "田生" } var o1 = new Obj() console.log(o1.toString()) // [object Object] console.log(o1)
上面例子克隆了個新的 對象Obj ,新對象沒有 toString 方法,所以在調(diào)用 toString 方法時,這個請求就會委托給他的原型對象 Object 的 prototype去執(zhí)行
那你可能會疑惑,對象 Obj對象 是怎么和 Object 的 prototype對象掛上鉤的呢?
你可以試著在Chrome瀏覽器的開發(fā)者模式中輸入上面代碼,試著打印 console.log(o1)
會發(fā)現(xiàn) Obj 有個 proto 的屬性指向了 Object對象,這就是它們連接的紐帶
當(dāng)函數(shù)作為對象的方法調(diào)用時,this 指向改對象
例子:
var Obj = { name: "田生", fun: function () { console.log(this.name) // this 指向改 對象 } } Obj.fun() // 田生
當(dāng)函數(shù)不作為對象的屬性被調(diào)用時,也就是常說的普通方法,此時this指向全局對象
var name = "田生....2" function fun1() { console.log(this.name) // fun1 當(dāng)做普通函數(shù),this指向全局 function fun2() { console.log(this.name) // fun2 也當(dāng)做普通函數(shù),this指向全局 } fun2() // "田生....2" } fun1() // "田生....2"
fun2 函數(shù)的this為什么也指向全局呢?有必要再強調(diào)一下,當(dāng)函數(shù)不作為對象的屬性被調(diào)用時,也就是常說的普通方法,此時this指向全局對象!
當(dāng)然在 ES6 strict 模式下 this為undefined
首先要明確一點,JavaScript 的 Function 實際上是功能完整的對象。那對象就可以調(diào)用方法。
所以在看到下面的例子就不要疑惑:
function fun(para) { } fun.length fun.apply(null, ["田生"]) fun.call(null, "田生") fun.toString()
為什么一個函數(shù)有屬性呢,為什么一個函數(shù)居然可以調(diào)用另一個方法呢,因為JavaScript 的 Function 實際上是功能完整的對象啊,對象就有屬性和方法啊
沒啥區(qū)別,就接受參數(shù)的方式不一樣而已,apply 接受的第二個參數(shù)是集合,call接受的參數(shù)不固定用逗號隔開。
但可以說 call 是包裝在 apply 的語法糖,內(nèi)部實現(xiàn)也是將參數(shù)轉(zhuǎn)數(shù)組的形式,所以某種意義上講
apply的效率高一點。
改變this的指向:
function Obj() { this.name = "HI 田生~" function fun() { console.log(this.name) // undefined } fun() } new Obj()
上面小節(jié)也講了,fun 沒綁定到對象上,所以在這里被當(dāng)做普通函數(shù)使用,this指向全局對象,那咱們要
this.name正常輸出怎么辦:
// 方法一:傳統(tǒng)的 _this 傳遞 function Obj() { this.name = "HI 田生~" var _this = this function fun() { console.log(_this.name) // HI 田生~ } fun() } new Obj() // 方法二:借助 apply 或 call function Obj() { this.name = "HI 田生~" function fun() { console.log(this.name) // HI 田生~ } fun.apply(this) } new Obj()
哪種方法好用我就不多說了
借用其他對象方法
var arr = [] Array.prototype.push.apply(arr,[1, 2, 3]) console.log(arr) // [1, 2, 3]三、閉包和高階函數(shù) 1、閉包
閉包這個概論總是不好理解,你可以簡單的理解為 閉包就是能夠讀取其他函數(shù)內(nèi)部變量的函數(shù)
例子:
var func = function () { var a= 1 return function () { a++ console.log(a) } } var fun = func() fun() // 2 fun() // 3 fun() // 4
變量 a 是函數(shù) func 的局部變量,外部函數(shù)或?qū)ο鬅o法訪問,但 func 內(nèi)部的匿名函數(shù)能訪問,那就這個匿名函數(shù)就是一個閉包 ,將閉包返回出去,相當(dāng)于將訪問權(quán)給了外部環(huán)境,外部環(huán)境就可以訪問一個函數(shù)的
局部變量了。
上面第一小點順帶講了閉包能使外部環(huán)境訪問局部變量,是作用點之一。閉包還可以延續(xù)局部變量的壽命
例子:
// 方式1 var report = function (src) { var img = new Image() img.src = src } report("http://wwww.tiansheng.logo.png") // 方式2 var report = (function () { var img return function (src) { img = new Image() img.src = src } })() report("http://wwww.tiansheng.logo.png")
利用方式1有可能圖片還沒加載完數(shù)據(jù)就丟失了,因為 report 方法執(zhí)行完局部變量就銷毀了,而方法2
利用閉包的方式延長了變量的壽命
高階函數(shù)至少需要滿足以下條件之一:
函數(shù)可以作為參數(shù)傳遞
函數(shù)可以作為返回值輸出
我們經(jīng)常寫的帶有對調(diào)函數(shù)就是一個高階函數(shù)
例子:
/** * 高階函數(shù) * @param name * @param callBack */ function fun(name, callBack) { // do something ... callBack() }
函數(shù)作為返回值輸出,其實就是一種閉包的表現(xiàn)
下面一個單例模式的例子:
var getSingle = function (fn) { var ret; return function () { return ret || (ret = fn.apply(this, arguments)) } } var getScript = getSingle(function () { // ... }) var script1 = getScript() var script2 = getScript() console.log(script1 === script2) // true小結(jié):
本小結(jié)寫了 【面向?qū)ο蟮腏avaScript】、【this、call 和 apply】、 【閉包和高階函數(shù)】 ,為接下去的JavaScript 設(shè)計模式做鋪墊
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/88725.html
摘要:設(shè)計模式是以面向?qū)ο缶幊虨榛A(chǔ)的,的面向?qū)ο缶幊毯蛡鹘y(tǒng)的的面向?qū)ο缶幊逃行┎顒e,這讓我一開始接觸的時候感到十分痛苦,但是這只能靠自己慢慢積累慢慢思考。想繼續(xù)了解設(shè)計模式必須要先搞懂面向?qū)ο缶幊?,否則只會讓你自己更痛苦。 JavaScript 中的構(gòu)造函數(shù) 學(xué)習(xí)總結(jié)。知識只有分享才有存在的意義。 是時候替換你的 for 循環(huán)大法了~ 《小分享》JavaScript中數(shù)組的那些迭代方法~ ...
摘要:首先,需要來理清一些基礎(chǔ)的計算機編程概念編程哲學(xué)與設(shè)計模式計算機編程理念源自于對現(xiàn)實抽象的哲學(xué)思考,面向?qū)ο缶幊淌瞧湟环N思維方式,與它并駕齊驅(qū)的是另外兩種思路過程式和函數(shù)式編程。 JavaScript 中的原型機制一直以來都被眾多開發(fā)者(包括本人)低估甚至忽視了,這是因為絕大多數(shù)人沒有想要深刻理解這個機制的內(nèi)涵,以及越來越多的開發(fā)者缺乏計算機編程相關(guān)的基礎(chǔ)知識。對于這樣的開發(fā)者來說 J...
摘要:深入之繼承的多種方式和優(yōu)缺點深入系列第十五篇,講解各種繼承方式和優(yōu)缺點。對于解釋型語言例如來說,通過詞法分析語法分析語法樹,就可以開始解釋執(zhí)行了。 JavaScript深入之繼承的多種方式和優(yōu)缺點 JavaScript深入系列第十五篇,講解JavaScript各種繼承方式和優(yōu)缺點。 寫在前面 本文講解JavaScript各種繼承方式和優(yōu)缺點。 但是注意: 這篇文章更像是筆記,哎,再讓我...
摘要:函數(shù)式編程前端掘金引言面向?qū)ο缶幊桃恢币詠矶际侵械闹鲗?dǎo)范式。函數(shù)式編程是一種強調(diào)減少對程序外部狀態(tài)產(chǎn)生改變的方式。 JavaScript 函數(shù)式編程 - 前端 - 掘金引言 面向?qū)ο缶幊桃恢币詠矶际荍avaScript中的主導(dǎo)范式。JavaScript作為一門多范式編程語言,然而,近幾年,函數(shù)式編程越來越多得受到開發(fā)者的青睞。函數(shù)式編程是一種強調(diào)減少對程序外部狀態(tài)產(chǎn)生改變的方式。因此,...
摘要:閱讀小札一閱讀前自大學(xué)課上,就開始接觸設(shè)計模式,但對設(shè)計模式卻鮮有研究與實踐。第二部分是核心部分,由淺到深講解個設(shè)計模式。設(shè)計模式遵循的原則所有設(shè)計模式罪訓(xùn)的一條原則就是找出程序中變化的地方,并將變化封裝起來。 閱讀小札 · 閱讀前 自大學(xué)Java課上,就開始接觸設(shè)計模式,但對設(shè)計模式卻鮮有研究與實踐。最近向公司反映和游說技術(shù)提升,得以獲得公司提供購書機會,借此認真學(xué)習(xí)前端學(xué)習(xí)之路的...
摘要:是文檔的一種表示結(jié)構(gòu)。這些任務(wù)大部分都是基于它。這個實踐的重點是把你在前端練級攻略第部分中學(xué)到的一些東西和結(jié)合起來。一旦你進入框架部分,你將更好地理解并使用它們。到目前為止,你一直在使用進行操作。它是在前端系統(tǒng)像今天這樣復(fù)雜之前編寫的。 本文是 前端練級攻略 第二部分,第一部分請看下面: 前端練級攻略(第一部分) 在第二部分,我們將重點學(xué)習(xí) JavaScript 作為一種獨立的語言,如...
閱讀 3411·2023-04-25 20:37
閱讀 3152·2021-09-07 09:59
閱讀 1675·2019-08-29 12:43
閱讀 1195·2019-08-28 18:27
閱讀 489·2019-08-26 13:50
閱讀 2041·2019-08-26 10:33
閱讀 3602·2019-08-23 18:39
閱讀 2411·2019-08-23 18:09