RZ-Huang
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # JavaScript 底層機制與相關執行原理 ###### tags: `javascript`、`advanced`、`concept` ## Hoisting ``` console.log(a) var a = 1 ``` 當我們輸入這樣的程式碼所得的結果會是 `undefined`,很合理,因為變數`a` 還沒被附值。 而上面這段程式碼因為 hoisting 提升的作用,其實和下面的程式碼是一樣的: ``` var a console.log(a) a = 1 ``` 這也就是為什麼結果會是 `undefined`,而不是顯示「a is not defined」的錯誤訊息。 我們再以 function 來看: ``` test() function test() { console.log('123') } ``` 結果會是 `123`的字串,也就是說在呼叫函式時還沒跑到函式的那一行就有函式的作用,只因為 hoisting 的關係,所以不管 function 被放到哪裡都可以被呼叫。 另外下面這種方式也是賦值的一種,因此不能看做 function 的 hoisting: ``` test() var test = function () { console.log('123') } ``` 可以把它看作: ``` var test test() test = function () { console.log('123') } ``` 因為在第一行的時候 `test`還沒被賦值,因此為`undefined`,所以`test()`的結果會是`test is not a function`。 ### hoisting 的順序 下面這個例子的結果是 `undefined` 的原因是在 `test` function 裡面,因為宣告了 `var a = 5`,導致說 `var a` 做了一個 hoisting 的動作,再加上作用域的關係,因此接收到的`a` 值是 `undefined`,而不是全域變數的`10`。 ``` var a = 10 function test() { console.log(a) // undefined var a = 5 } test() ``` 上面的例子可以看成這樣: ``` var a = 10 function test() { var a console.log(a) a = 5 } test() ``` 而因為每個變數如果在被宣告的時候沒有賦值,預設值是`undefined`,所以結果才是`undefined`。 今天如果是放入 function: ``` var a = 10 function test() { console.log(a) // [Function: a] function a(){ } } test() ``` 結果會是抓到 function a,表示 function 也變數提升了。 那如果`var`和`function` 同時出現: ``` function test() { console.log(a) // [Function: a] var a = 10 function a() { } } test() ``` 結果也是抓到 function a,表示說 function 比變數宣告佔有優先權。 那如果是重複出現的 function: ``` function test() { console.log(a) // ya a() function a() { console.log("hello") } function a() { console.log("ya") } } test() ``` 則會顯示最後的 function 結果,表示後面的 function 會覆蓋掉前面一樣名稱的 function 結果。 如果同時傳參數與`var`宣告: ``` function test(a) { console.log(a) // 123 var a = 456 } test(123) ``` 結果則是引數傳進來的值,因此參數會優先於`var`的變數宣告,表示說這邊的變數提升:`var a`實則沒什麼作用,會被忽略。 這邊的`var`變數提升被忽略的理由是: 當今天變數已經被前面宣告過了(這個例子是參數已經宣告過變數)的話,那麼接下來所有純粹的`var a`的變數宣告都會被無視,像下面的例子: ``` function test() { var a = 123 var a var a console.log(a) // 123 } test() ``` 結果只有`var a = 123` 這行被採納,下面兩行的`var a`在這邊沒有作用產生。 但原本那個例子的順序如果換一下就會被`var`的值(後來新增的值)覆蓋: ``` function test(a) { var a = 456 console.log(a) // 456 } test(123) ``` 那如果傳參數的同時,存在 function: ``` function test(a) { console.log(a) // [Function: a] function a() { } } test(123) ``` 結果會是抓到 function,表示 function 的提升順序優於參數。 #### 總結上面我們可以知道 hoisting 順序為: 1. function 2. argument 3. var 而 Hoisting 底層的運作實際上與 Execution Context 有關,詳情請見參考資料。 #### 參考資料: [我知道你懂 hoisting,可是你了解到多深?](https://github.com/aszx87410/blog/issues/34) ## Closure 直接看範例: ``` function createCounter() { var count = 0 return function () { count++ return count } } var counter = createCounter() console.log(counter()) console.log(counter()) ``` Closure 主要目的是為了不讓變數值被外面其他的變數或是因重複命名而影響到,所以利用 function 的 Closure 特性把所有涵蓋的變數值給包起來。 如果不包起來則會是這樣: ``` var count = 0 function counter() { count++ return count } console.log(counter()) console.log(counter()) ``` 雖然一樣可以運作,但是在 `counter()` function 外面的 `count`變數值可能就會被更改到或者是因重複命名而有所影響 再舉一個運用閉包特性的例子: ``` function vol(dim) { console.log('calculated!') return dim * dim * dim } function cache(func) { let obj = {} return function (dim) { if(obj[dim]) { return obj[dim] } obj[dim] = func(dim) return obj[dim] } } const cacheVol = cache(vol) console.log(cacheVol(5)) // calculated! 125 console.log(cacheVol(5)) // 125 console.log(cacheVol(5)) // 125 ``` 藉由閉包,也就是 cache function 回傳的 function,這個 function 可以判定是否已經計算過這個值了,如果已經計算過了,那就直接輸出結果,而不是再回到`vol` function 重新計算,因此在上面`console.log()`的結果會發現只有第一次進到`vol` function 計算數值,後面再呼叫 `cacheVol` 傳回來的值實際上都是已經儲存在`cache` function 的 `obj`物件裡面,只是單純從物件裡面取出值來而已。而這樣的好處有幫助程式執行運算的速度,假如`vol` function 今天是個裡面佈滿複雜的運算才有辦法得出結果的話,每次我們要拿到`vol` function 的結果就得需要經過這道複雜的運算才有辦法拿到。我們藉由閉包的特性,使用`cache`function 傳入 function 參數進去(這邊即為`vol`),變成我們可以靈活運用這個輸入進來的 function ,可以決定我們何時使用它,有一種工具包裡面的其中一項工具的概念,需要用到的時候就拿出來,不需要的時候就簡便處理,**而且就算不需要的時候這個工具一直都放在裡面,這也是閉包的特性,執行過的 function 卻依然存在。** #### 參考資料: [所有的函式都是閉包:談 JS 中的作用域與 Closure ](https://github.com/aszx87410/blog/issues/35) ## Prototype ``` function Person(name) { this.name = name this.getName = function () { return this.name } } let nick = new Person('nick') let mike = new Person('mike') console.log(nick.getName === mike.getName) ``` 上面`console.log`的結果為 `False`,因為兩次呼叫物件的記憶體是不同的。 但是如果我們使用`prototype`的話,兩次呼叫就會是一樣的,結果會是`True`,程式碼如下: ``` function Person(name) { this.name = name } Person.prototype.getName = function () { return this.name } let nick = new Person('nick') let mike = new Person('mike') console.log(nick.getName === mike.getName) ``` 那麼為什麼會一樣?因為`nick.getName === Person.prototype.getName`,或是`mike.getName === Person.prototype.getName`,也就是說都會是相等的。 實務上會先去尋找 `Person` 這個 instance 有沒有`getName`的方法,假如沒有,它就會往`prototype`當中去尋找,那它為什麼會有這個特性?因為其實在每個 instance 被建立的時候,javascript 的底層都會偷偷建立一個叫做`Person.__proto__`的方法,而這個方法等於`Person.prototype`。 那如果在`Person.__proto__`找不到`getName`的方法的話,那又會繼續往下找,也就是`Person.__proto__.__proto__`,而這個方法等於`Person.prototype.__proto__`,也等於`Object.prototype` 也就是說 protoype 的尋找順序為: 1. `nick` 2. `nick.__proto__`(= `Person.protoype`) 3. `nick.__proto__.__proto__` ( = `Person.prototype.__proto__` = `Object.prototype`) 4. `nick.__proto__.__proto__.__proto__`(這層即為底層,顯示出來的結果為 null) 這種一層一層一直尋找底層有沒有相符的物件的機制,叫做「原型鏈(prototype chain)」。 而 ES5 以前因為沒有`class`的語法,所以是以`prototype`的方式取代`class`的`method`設定(如上方例子的`Person.prototype.getName = function() {}`),更深入探討,其實 ES6 之後新增的`class`語法它的底層運作其實就是`prototype`機制。 #### 延伸閱讀 [該來理解 JavaScript 的原型鍊了](https://github.com/aszx87410/blog/issues/18) --------- ## 程式執行原理 ### Call Stack 以 Stack 資料結構為原理的程式執行方式。 比如: ``` function a() { b() } function b() { c() } function c() { console.log('123') } ``` 這段程式碼會先 call `function a`,再來 call `function b`,再來 call `function c`,接著`console.log('123')`。 以 stack 來看,就是這樣的順序進入 call stack: a->b->c->console.log('123');然後再以這樣的順序離開 call stack:console.log('123')->c->b->a。 ### 執行環境(Execution Context:EC) 在 Javascript 的程式碼執行順序,可能不是一行一行執行的,而是由編譯→執行這兩個順序來完成,否則 hoisting 的機制沒辦法做解釋。雖然 javascript 常被稱作「直譯語言」,可是並不是說它所有的機制都是直譯的,這邊我們要介紹的這個機制就是其中之一由編譯→執行這兩個動作所運作,有關於執行環境(EC)的機制。 以上面的 call stack 為例,其實每個 function 的 stack 都有單獨的執行環境,可以看做有 EC of function a、EC of function b、EC of function C,另外還有個 global EC 處理非函數的執行環境,像是變數之類的。 可以把 EC 想像為 Javascript 的物件,每個 EC 當中有這樣子的結構: ``` { Variable Object, scopeChain, this } ``` 詳細的結構: ``` EC: { VO: { arguments: { }, a: 1, b: 2, }, scopeChain: [], this } ``` `arguments` 為 function 的參數,`scopeChain` 就像是 prototype chain 那種結構,如果找不到,那就一層一層往上找的結構。(`this`這邊先跳過,之後有機會補)

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully