天天看點

你真的學會JavaScript了嗎?

你真的學會JavaScript了嗎?

請聽題,請在評論區或在心中給出以下代碼的執行結果:

寫好答案了嗎?要公布答案了哦

1 2 NaN 678tianlangstudio 1NaN

如果你的答案跟上面的任意一個比對上了,那恭喜你! 可以一起往下面看了,因為這是一份全錯的答案。

想起上高中時有次英語老師拿了張考卷對着答案講了半天,然後對我們說:

這是B卷看成A卷的答案了,我們從頭講。

從此我就再不相信什麼答案了,甚至遇到做不出的題我都懷疑是不是題出錯了!慢慢的養成了獨立思考的習慣,不知是好是壞。感謝老師苦心一片,至今教誨良言時猶在耳:

JavaScript是動态類型語言,也就是說在代碼編寫時不需要聲明指定其類型,變量類型在代碼運作時才确定.

沒有方法、不可變

包括:

undefined

null

boolean

number

string

(symbol)

對象(包括數組)

函數

可以使用<code>typeof</code>判斷資料類型:

<code>需要注意:</code>

<code>typeof null</code> 傳回<code>object</code> 曆史原因相容原來的版本

<code>typeof arr</code> 傳回 <code>object</code> 數組也是對象

<code>typeof function testFun() {}</code> 傳回 <code>function</code>

資料從一個類型轉換到另一個類型

強制就是你得自己編寫代碼轉換資料類型,隐式的就是有執行引擎幫你轉換.

<code>==</code> 會把兩邊的資料轉換為同一種類型再比較是否相等,也就是忽略資料類型,比如:

<code>===</code> 先判斷資料類型,資料類型不一樣就直接false, 不為其類焉問其值, 比如:

false

+0, -0, NaN

"" //空字元串

<code>注意:</code>

<code>'false'</code> -&gt; true

此處省略10000字

太多,因為除了上面的都是^-^

基本資料類型都是不可變的. 複雜資料類型可變并且使用索引操作

基本資料類型值傳遞,複雜資料類型使用引用傳遞(做為函數、方法參數時)

非基本資料類型都有關聯屬性和方法,比如:

Array.prototype.push() String.prototype.toUpperCase()

​ <code>注意:</code>

​ <code>String</code>是複雜類型,<code>'tianlang'</code>這個是基本資料類型,有些時候它們行為一樣,這是因為有自動轉化,專業俗語<code>自動裝箱</code>. 例如:

基本資料類型對應的裝箱複雜類型:

String() Number() Boolean() Object() (Symbol())

Java裡也有這個概念,但JavaScript除了名字跟Java沒半點關系.

每個對象都持有一個原型的引用

跟對象關系越近的原型上定義的屬性或方法優先級越高

作用域就是變量生效的範圍

使用<code>var</code>定義的變量有效範圍是從定義開始到所在函數結束. 使用<code>const</code>,<code>let</code> 定義的變量有效範圍是從定義開始到所在塊結束.

​ 這個需要先說下程式執行過程:

執行引擎讀取整個程式腳步

解析判斷是否有文法錯誤,如果有錯誤報錯退出執行

把函數儲存到記憶體中

聲明使用var定義的變量(注意:隻有聲明沒有初始化指派)

.......

這就是為什麼,我們可以先調用一個函數後對這個函數進行定義,可以先使用一個使用var定義的變量,後面才使用var定義變量而不會報錯。因為再執行時把函數定義的代碼和var定義提升了.注意看3,4.

可以把全局對象想象成一顆大樹,在程式中定義的變量也好函數也好其實都挂在一個全局對象上。

在浏覽器運作環境中,全局對象是<code>window</code> 在Node.js運作環境中,全局對象是<code>global</code>

咋一看,不知道是做什麼的,再一看還是不能從名字看出這貨具體是做什麼的.看下定義:

小蒙怡情大蒙傷身,還是看下代碼,回頭看我們前面提到的測試題1:

輸出的結果是:

3

意不意外?

要一次性了解這個可能有點難,我們先來個簡單的:

看了上面的例子是不是對這貨為什麼叫<code>閉包</code>有了些許的感悟。因為<code>ES6</code>前隻能使用<code>var</code>定義變量,而這貨定義的變量作用域本來就比較寬還有定義提升就更容易造成變量的作用域污染了.

什麼是變量的作用域污染呢?

你定義了個變量name叫張三, 你的同僚或者你在其它地方無意識的又定義了name叫李四,後來就變成了你以為的張三不知道怎麼就變成了李四了.

為了定義新變量name叫李四時不影響原來的張三,于是我們可以把李四關起來定義,關起來也就是封<code>閉</code>起來。就像上面的示範代碼,隻有在函數中定義的函數<code>sayHello</code>才能通路到函數中定義的變量<code>message</code>,message對外部是不可見的,也就不會影響外部原來定義的變量.

上例中使用sayHello時還需要先調用makeHelloFunction建立,如果每次都這樣豈不是挺麻煩的?

我們可以使用立即執行函數定義方式,就是來個小括号,後面的小括号裡還能傳遞參數.就項這個樣子:

到此是不是還不知道為啥子測試1裡輸出的是3,3,3而不是0,1,2? 沒關系,可以先讓它輸出0,1,2.

這下明白了吧,可以運作下這段代碼看下效果,如果還是不明白也可以加群讨論.

那什麼時候, 人分三流九等,士農工商。但是人生而平等嘛,怎麼展現平等呢?基本的權利大家應該都有吧.就像函數,雖然長得跟普通對象啊數字啊不一樣,但是收到的待遇卻是差不多地。可以定義變量把一個函數指派給它,也可以把函數做為另一個函數的參數使用,這個就厲害了,可以實作很多進階的功能.也稱這種參數是函數的函數為<code>高階函數</code>.

JavaScript是單線程同步執行的語言.

如果一個函數執行的時間比較長就會引起頁面的卡頓,比如在運作個這樣的函數,再去點選頁面裡的按鈕你會發現沒得反應了:

但是有些函數是可以異步執行的,比如:

setTimeout()

XMLHttpRequest(), jQuery.ajax(), fetch()

調用資料庫

是不是很好奇JavaScript怎麼即是同步單線程的語言又支援異步呢?這主要是内部維護了一個任務隊列,如果關于這塊您有什麼想法也可以給加群給大家分享.

​ 原來處理異步代碼的方式是添加回調函數,異步代碼執行完成後會觸發回調函數。比如這樣:

異步函數多了,我們需要一層一層的嵌套回調函數,就成了回調黑洞,這樣的代碼讀起來麻煩,維護起來也麻煩,一不小心就不知道哪裡少敲了個括号. 于是就引入了Promise程式設計模型,減少回調嵌套,就像這個樣子:

是不是清爽了很多?

後來ES2017又新增了async/await關鍵字用于支援異步程式設計,就像這樣:

是不是跟Rust Async有點像? 學語言嘛,這也是為什麼我總是勸新同學要學一門語言學通再學其它的。語言嘛總有相通之處,雖不能一通百通但也是有大量可複用之處的.

初接觸Javascript會覺得<code>this</code>真是飄忽不定,特别是在事件處理時使用到<code>this</code>,常常搞不清它<code>這個</code>糾結指的是<code>那個</code>;

這裡總結幾條規則:

函數中的<code>this</code>指向函數的調用時所在對象,如:

obj.fun();// fun中的this指向boj

如果沒有對象那在嚴格模式下<code>this</code>就指向全局對象<code>windows</code>或者<code>global</code>

可以使用<code>bind</code>,<code>call</code>, <code>apply</code>顯示綁定<code>this</code>到某個對象.

該煮飯了,有時間再單獨寫篇<code>this</code> ,歡迎關注

繼續閱讀