摘要:今天看一個妹子寫的的插件,好羞愧啊,比我小還比我厲害得多,氮素,得向厲害的的人學習呀。在文件里引用的話,這兩個就先跳過吧。在嚴格模式下通過傳遞給一個函數的值不會被強制轉換為一個對象。
今天看一個妹子寫的canvas的插件,好羞愧啊,比我小還比我厲害得多,氮素,得向厲害的的人學習呀。所以就拜讀了源碼,業務方面的東西我就不說了,我也沒仔細看,主要是被下面這一部分代碼吸引了。
_global = (function() { return this || (0, eval)("this"); }()); if (typeof module !== "undefined" && module.exports) { module.exports = CanvasStar; } else if (typeof define === "function" && define.amd) { define(function() { return CanvasStar; }); } else { !("CanvasStar" in _global) && (_global.CanvasStar = CanvasStar); }
細細琢磨了一會,看懂了if和else if判斷的用意。
在這之前先說明下CanvasStar是什么。代碼里有這樣一句。
function CanvasStar() {}
所以這個方法就是在代碼里執行這個canvas的入口,其他所有相關的內容都作為一個對象賦值給了他的原型對象。
再說回那兩個判斷,因為在es6之前,都用的是commonJS和AMD規范進行代碼加載,所以含義就在于當前的環境支不支持commonjs或者AMD規范。在HTML文件里引用的話,這兩個就先跳過吧。主要看這兩句。
//問題1 _global = (function() { return this || (0, eval)("this"); }()); //問題2 else{ !("CanvasStar" in _global) && (_global.CanvasStar = CanvasStar); }
我google了(0, eval)("this"),有篇文章是這么說的:
無論如何方式調用(0, eval)("this"),返回的都是全局對象
所以問題1其實就是在將全局環境(也就是window)賦值給一個變量。我console了this,按理說,這里的this指向的就應該是全局變量,為什么還要后面的代碼重新指向全局呢?
然后打算重新看一遍代碼的時候發現她在寫這個插件的時候用的是嚴格模式,所以這里的this只可能是underfined。我貼一下MDN對于嚴格模式下this的指向。
在嚴格模式下通過this傳遞給一個函數的值不會被強制轉換為一個對象。對一個普通的函數來說,this總會是一個對象:不管調用時this它本來就是一個對象;還是用布爾值,字符串或者數字調用函數時函數里面被封裝成對象的this;還是使用undefined或者null調用函數式this代表的全局對象(使用call, apply或者bind方法來指定一個確定的this)。這種自動轉化為對象的過程不僅是一種性能上的損耗,同時在瀏覽器中暴露出全局對象也會成為安全隱患,因為全局對象提供了訪問那些所謂安全的JavaScript環境必須限制的功能的途徑。所以對于一個開啟嚴格模式的函數,指定的this不再被封裝為對象,而且如果沒有指定this的話它值是undefined
很長是吧,簡短的說,在嚴格模式下,如果沒有給this指定值的話,它就是未定義的。所以在賦值的時候就跳過了這個this,返回了(0, eval)("this")。
這里說明一下eval,在我找資料的過程中,都提到它的兩種使用方式間接eval調用和直接eval調用,這兩種的調用方式的結果完全不同,一般我見到的都是直接eval調用,甚至于由于不提倡使用,所以eval幾乎很少出現。
等我在看多一點資料以后在寫一個eval相關的博文吧。但我可以先對這里面的逗號操作符做一點說明。
逗號操作符這是MDN上的解釋
逗號操作符 對它的每個操作數求值(從左到右),并返回最后一個操作數的值。
我就用幾個代碼說明一下
function func1() { let a = "我是第一個賦值方法" console.log("一號喵") return a } function func2() { let b = "我是第二個賦值方法" console.log("二號喵") return b } let c = (func1(), func2()) console.log(c)
猜猜這里有幾個console,分別是什么。
現在揭曉答案
//console.log結果 一號喵 二號喵 我是第二個賦值方法
所以根據定義來看,在對c賦值的過程中,從左至右依次執行了func1和func2兩個方法,但是在賦值的時候,只返回了最后的那個值,也就是func2里寫的return。
所以我們在看一下eval
(0, eval)
這里返回的也是eval,等同于這個
eval("this")
然而還是因為調用方式的不一樣,所以最后的結果不一樣,先按下不表了。
立即執行函數的公與私那再來看問題2就簡單明了多了,他就是在判斷全局是否存在CanvasStar這個方法,如果不存在,就在全局創建一個變量并將內部的方法賦值給他。
但這里就涉及一個問題,像是我,多帶帶寫js文件并引入使用的時候,都是直接調取方法使用,為什么這么麻煩啊,所以這里我也嘗試在HTML文件里直接調用CanvasStar(前提是把那些代碼注釋了)。
但很可惜,瀏覽器報錯:
Uncaught TypeError: CanvasStar is not a constructor
所以這里我就想說說共有方法和私有方法,代碼如下
//main.js (function() { let a = "猜猜我是什么類型" function sum() { console.log(a) } let log = function() { console.log(a) } })()
然后html文件里調用:
sum(); // Uncaught ReferenceError: sum is not defined log(); // Uncaught ReferenceError: log is not defined
我對main.js的文件做一丟丟修改
//main.js (function() { let a = "猜猜我是什么類型" log = function() { console.log(a) } function sum() { console.log(a) } })()
重新運行:
log(); // 猜猜我是什么類型 sum(); // Uncaught ReferenceError: sum is not defined
我第一次在js文件里寫了一個函數聲明和一個函數表達式,但是在外部都無法調用,第二次我把函數表達式賦值的變量聲明去掉之后,就能正常訪問了。
這個問題的關鍵在作用域,當我建立這個立即執行函數是,作用域鏈是這樣的:
全局作用域 |
---|
匿名函數 |
函數作用域 |
---|
變量a |
log函數 |
sun函數 |
而當匿名函數執行完之后,它本身的作用域就被銷毀了,從他的上一級,也就是全局作用域根本訪問不到任何東西,但如果在進行函數賦值時,賦值的變量并沒有經過var或者let生明,在這里log這個變量是被寫在全局作用域里面的,所以外部直接調用完全沒問題。
所以得出的一個結論是:講過let或者var生明的變量都是私有的,函數聲明一定是私有的方法。其他都是共有變量或者方法。另外,共有方法能訪問作用域里的私有變量,但是私有變量無法從外部直接獲取。
其實這也就是某種意義上的閉包啦。
另一種封裝方法要是只講上面的多沒意思啊,正好我最近在看underscore的源碼,我就想著看看人家的封裝方法是啥。
在規范判斷那一塊大同小異,就不說了,但是對于全局變量的賦值走的是一條完全不同的路。
(function() { let root = this; ............ ............. root._ = _ }.call(this))
這樣外部直接
_.方法名;
就可以使用了。
那在這里,underscore在執行這段匿名函數的時候,使用call將函數的this指向了全局變量,這里就是this,可能這句話比較繞,但事實就是這樣。如果實在理解不了,我舉個例子:
一艘船在海上航行,夜間,如果天空晴朗,指的是一般模式,那水手可以根據天上的星辰判斷方位,如果不幸烏云密布,就是嚴格模式,那就迷路啦,但恰好,轉過一個海灣,發現了一座著名的燈塔,重新給你指引了方向,這就是call重新指向當前作用域的this,也就是全局。
不知道我有沒有說清楚呀。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/88589.html
摘要:前端日報精選在中的元素種類及性能優化譯異步遞歸回調譯定位一個頁面阻塞問題的排查過程前端分享之的使用及單點登錄中文視頻如何用做好一個大型應用云際個實用技巧眾成翻譯年一定不要錯過的五本編程書籍年前端領域有哪些探索和實踐實現一個時光網掘金 2017-09-22 前端日報 精選 JavaScript 在 V8 中的元素種類及性能優化【譯】異步遞歸:回調、Promise、Async[譯]HTML...
摘要:月號,杭州和聯合主辦的第八期技術分享會,在公司如期舉行。張偉林,宋小菜資深前端開發工程師,年,霹靂迷,已手殘的紙牌魔術師,喜歡神奇的東西,技術棧從上向下不斷橫向縱向貫穿,目前在尋找前后端大一統思想的路上越走越偏。 showImg(https://segmentfault.com/img/bVbkWN4?w=3000&h=1686); 12 月 9 號,杭州 NodeParty 和 Ro...
摘要:普羅米修斯是誰在希臘神話中,是泰坦神族的神明之一,名字的意思是先見之明。普羅米修斯與智慧女神雅典娜共同創造了人類,普羅米修斯負責用泥土雕塑出人的形狀,雅典娜則為泥人灌注靈魂,并教會了人類很多知識。普羅米修斯是誰?From Wikipedia:在希臘神話中,是泰坦神族的神明之一,名字的意思是先見之明。普羅米修斯與智慧女神雅典娜共同創造了人類,普羅米修斯負責用泥土雕塑出人的形狀,雅典娜則為泥人灌...
摘要:目前插件已超過幾千種,由來自世界各地的開發者共同編寫驗證和完善。而對于開發者而言,直接使用這些插件將快速穩定架構系統,節約項目成本。也就是說,插件也是代碼,通過文件引入的方式植入即可。現在我們就完成了一個下拉菜單的插件。 插件(Plugin)也成為 jQuery 擴展(Extension),是一種遵循一定規范的應用程序接口編寫出來的程序。目前 jQuery 插件已超過幾千種,由來自世界...
摘要:所以我們選一個倉庫倉庫比較多,我這里選用,都行,根據需求自行選擇訪問端口,然后就沒有然后了功能沒有那么強大,不過占用資源少,速度快,我們穩定運行了幾年了。 kubernetes集群三步安裝 CI 概述 用一個可描述的配置定義整個工作流 程序員是很懶的動物,所以想各種辦法解決重復勞動的問題,如果你的工作流中還在重復一些事,那么可能就得想想如何優化了 持續集成就是可以幫助我們解決重復的代碼...
閱讀 642·2021-11-25 09:43
閱讀 1655·2021-11-18 10:02
閱讀 1033·2021-10-15 09:39
閱讀 1877·2021-10-12 10:18
閱讀 2115·2021-09-22 15:43
閱讀 756·2021-09-22 15:10
閱讀 2084·2019-08-30 15:53
閱讀 978·2019-08-30 13:00