--- tags: Note --- # JS 核心觀念 ## Javascript ### 基本型別 - primitive type 原始型態 - null - undefined - string - number - boolean - symbol(ES6) - Immutable - by value ### 物件型別 - 除了以上基本型別之外都是 object type - array - function - data - mutable - by reference - 例外 > 若是使用 object literal 的方式來建立物件,則會變成 by Value,新增了一個記憶體的位置。 ### by value、by reference、by sharing [JavaScript 是「傳值」或「傳址」?](https://ithelp.ithome.com.tw/articles/10191057) [談談 JavaScript 中 by reference 和 by value 的重要觀念](https://pjchender.blogspot.com/2016/03/javascriptby-referenceby-value.html) ### 如何知道型態 - typeof `console.log(typeof true)` - 但有些無法靠 typeof 得知 `console.log(typepf null)` -> object `console.log(typepf function)` -> function - 想判斷是不是陣列 `console.log(Array.isArray([]))` -- 較舊的瀏覽器沒有這個方法的話可以用 `console.log(Object.prototype.toString,call(null))` [object Array] ## 賦值 primitive type object type 順帶一提 - 賦值 `=` - 判別物件 `==` - 多了有無型態轉換 `=== ` (指向同一個記憶體位置時才成立) ## NaN Not a number - 也是數字的一種,但不是真的數字 - 不等於任何東西,甚至不等於自己 isNaN 可以查是不是,但較舊瀏覽器也是不支援 [JS Comparison Table](https://dorey.github.io/JavaScript-Equality-Table/) [isNaN()](https://developer.mozilla.org/zh-TW/docs/orphaned/Web/JavaScript/Reference/Global_Objects/isNaN#%E6%8F%8F%E8%BF%B0) ## ES6 ### 宣告方式 - let 宣告變數(與 var 差不多,但作用域僅限 block) - const 宣告常數(宣告完就不能改變) ## 作用域 scope 變數的生存範圍 - global variable 全域變數 scope chain inner scope -> test scope -> global scope ## Hoisting Hoisting 順序 function -> 參數 -> variable 直接給例 ``` console.log(age) var age = 100 輸出結果:undefined ``` 咦?照理來說,程式碼由上往下執行,不是應該 `age is not defined` 嗎?很奇怪吧,這就是 JS 中的 Hoisting,變數的宣告會被**提升**到最上面。 再來,以我目前的理解及實作,Hoisting 最重要的地方在於讓程式碼中 function 可以順利宣告及呼叫。至於變數宣告,倒是可以透過良好 coding 習慣解決的。 ## Execution context 執行環境 1. 單執行緒 2. 同步執行 3. 只會有一個 Global Execution 4. function Execution 沒有限制 5. 只要呼叫函式就會建立執行環境(call function -> Execution context),即使是自己呼叫自己 | Execution context (*current*) | | ----------------------------- | | Execution context (N+2) | | Execution context (N+1) | | Execution context (N) | | Global Execution context | function 的資訊都在 Execution context 裡,而每個 Execution context 裡都會有相對應的 variable object(暫稱 VO)。 > 首先,你可以把 VO 想像成就是一個 JavaScript 的物件就好。 >再來,VO 什麼時候會用到?你在存取值的時候會用到,例如說 var a = 10 這一句,之前有講過可以分成左右兩塊: > 1. var a:去 VO 裡面新增一個屬性叫做 a(如果沒有 a 這個屬性的話)並初始化成 undefined > 2. a = 10:先在 VO 裡面找到叫做 a 的屬性,找到之後設定為 10 > 更多關於 VO.... 請左轉至 [我知道你懂 hoisting,可是你了解到多深?](https://blog.huli.tw/2018/11/10/javascript-hoisting-and-tdz/) 深入了解,大概滑鼠往下滑 10 下就到了 [理解 Javascript 執行環境](https://andyyou.github.io/2015/04/18/what-is-the-execution-context-in-javascript/) ## Execution context more 每 call function 一次,會建立一個新的 EC,但每次 JS 內部調用一個 EC 都會有兩個階段 1. 建立階段 —— 當函式被呼叫但執行內部程式碼前 - 建立一個作用域鍊(scope chain) - 建立變數、function、參數 - 設定 this 的值 2. 執行階段 - 賦值、設定 function 的參考和解譯執行程式碼 所以如果我們把 EC 想像成一個物件的話,大概會像這樣 ``` executionContextObject = { scopeChain: { /* 變數物件 + 所有父代執行環境物件的變數物件*/}, variableObject: {/* 函式的參數/引數,內部的變數和函式*/ }, this: {} } ``` 直譯器 找 call function -> 執行 funciton 前建立執行環境(EC)-> 進入建立階段 -> ## Scope 作用域 變數活性區 - global - block(ES6) - function [湯姆克魯斯與唐家霸王槍——變數的作用域(Scope)](https://ithelp.ithome.com.tw/articles/10203387) ## clouser 閉包 [所有的函式都是閉包:談 JS 中的作用域與 Closure](https://blog.huli.tw/2018/12/08/javascript-closure/) ## 物件導向 ``` myWallet.add(1) ``` 以前可能是用 function call - class -> this ES6 之前JS還沒有物件導向方法 - setter getter - ES5 時期,透過 .prototype.getName() ### prototype 原型鍊 - `prototype` - `__proto__` - `constructor` - `Object.prototype` - `Function.prototype` - `new` ### 物件導向的繼承 Inheritance - `constrecture` - `super` ### this (記得先盡量搞懂物件導向) > - this 是 JavaScript 的一個關鍵字。 > - this 是 function 執行時,自動生成的一個內部物件。 > - 隨著 function 執行場合的不同,this 所指向的值,也會有所不同。 > - 在大多數的情況下, this 代表的就是呼叫 function 的物件 (Owner Object of the function)。 > —— [What’s THIS in JavaScript ?](https://kuro.tw/posts/2017/10/12/What-is-THIS-in-JavaScript-%E4%B8%8A/) > - 嚴格模式底下就都是undefined > - 非嚴格模式,瀏覽器底下是window > - 非嚴格模式,node.js 底下是global > —— [淺談 JavaScript 頭號難題 this:絕對不完整,但保證好懂](https://blog.huli.tw/2019/02/23/javascript-what-is-this/) ~~' use strict ' ;~~ ~~.call()~~ ~~.apply()~~ ``` function log() { console.log(this); } var a = { a: 1, log: log }; var b = { a: 2, log: log }; log(); // undefined a.log(); // a b.log.apply(a) // a ``` <!-- ### 強制綁定 this bind --> ## 怎麼理解繼承? ### 文章先嗑 [Javascript继承机制的设计思想](http://www.ruanyifeng.com/blog/2011/06/designing_ideas_of_inheritance_mechanism_in_javascript.html) [Javascript 面向对象编程(一):封装](https://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_encapsulation.html) [Javascript面向对象编程(二):构造函数的继承](https://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance.html) [Javascript面向对象编程(二):构造函数的继承](https://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance.html) ### 嗑完文章 一開始作者設計的時候其實認為不需要設計繼承機制,但 JS 裡面所有數據類型都是對象(object),所以最後還是引入了物件導向的 new 命令,但在 Java 或 C++ 裡使用 new 命令時都會調用「類(Class)」的構造函數,但可能礙於是要做出簡易的腳本語言不增加初學者負擔,於是簡化了設計,所以在 JS 裡的 new 命令後面跟得不是 Class 而是構造函數(constructor)。 ![](https://i.imgur.com/eSVP6BK.png) 但這樣會有一個缺點,就是無法共享屬性和方法造成滿大的資源浪費,因此作者決定為構造函數(constructor)設一個 prototype 屬性。 ### constructor > 为了解决从原型对象生成实例的问题,Javascript提供了一个构造函数(Constructor)模式。 >所谓"构造函数",其实就是一个普通函数,但是内部使用了this变量。对构造函数使用new运算符,就能生成实例,并且this变量会绑定在实例对象上。 ### prototype prototype 這個屬性包含了一個對象,所有想共享的屬性、方法都放在這個對象裡; 其他不需要的就放在剛提到的構造函數裡(constructor)。 ### 。。。持續理解中。。。 [該來理解 JavaScript 的原型鍊了](https://blog.huli.tw/2017/08/27/the-javascripts-prototype-chain/) ## this [Javascript 的 this 用法](https://www.ruanyifeng.com/blog/2010/04/using_this_keyword_in_javascript.html)