正如標題所說,這是我第三次翻開紅寶書也就是《 JavaScript 高級程序設計第三版》,不得不說,雖然書有一些年份,不少知識點也不適合現代的前端開發,可是對於想要掌握 JavaScript 基礎的前端新手,亦或是像我同樣想找回曾經遺忘在記憶角落的那些碎片知識,這本書依舊很是的適合,不愧被成爲 "JavaScript 聖經"javascript
本文是讀書筆記,之因此又一次選擇讀這本書還有一個理由,以前都是記的紙質筆記,此次想把它做爲電子版,也算是對以前知識的整理前端
本文篇幅較長,目的是做爲個人電子版學習筆記,我會盡量去其糟粕,取其精華,同時我會添加一些書上未記載但很重要的知識點補充
java
上篇在這裏數組
JavaScript 不容許直接訪問內存中的位置也就是說不能直接操做對象的內存空間函數
JS 只能經過指針(保存在棧中的變量)去操做堆內存中的引用類型的值即對象,若是給變量賦值另外一個保存引用類型的值的變量,實際上只是建立了一個新指針,指向同一個堆內存中的對象post
let obj = {}
let o = obj
obj.a = "123"
console.log(obj) // {a:"123"}
console.log(o)// {a:"123"}
複製代碼
在上一章末尾也提到過,這就會致使經過其中一個變量修改引用類型的值時,會反映到全部指向它的變量學習
而若是是基本類型的值,則會直接建立一個新的副本,意味着二者不會相互影響ui
當了解了這個知識點就能夠知道爲何 JavaScript 會有深拷貝和淺拷貝這 2 個概念了,二者都是做用與引用類型spa
擴展運算符和 JSON.stringify 是比較常見的拷貝函數,前者用於淺拷貝,後者用於深拷貝prototype
let arr = [1,2,3]
let shallowArr = [...arr]
let deepArr = JSON.parse(JSON.stringify(arr))
複製代碼
更多關於拷貝的知識點能夠看我另外一篇博客對象深拷貝和淺拷貝
typeof 操做符能夠很簡單的肯定變量是不是基本類型,可是對於引用類型會始終返回 'object' 或 'function'
對於進一步知道變量是哪一種引用類型,須要使用 instanceof
操做符
let arr = []
console.log(typeof arr) // 'object'
console.log(arr instanceof Array) // true 表示它是一個數組的引用類型
複製代碼
對於基本類型的變量使用 instanceof 會返回 false
let str = 'abc'
console.log(str instanceof String) // false
複製代碼
注意這裏 String 並非 string,它是一個字符串的包裝類型,一樣也是引用類型,因爲是基本類型,因此即便是字符串的包裝類型,也會返回 false
可是 instanceof 也有缺陷
let arr = []
console.log(arr instanceof Object) // true
複製代碼
這裏返回 true,這樣就沒法判斷 arr 變量是數組類型仍是對象類型,致使這樣的緣由是數組類型是繼承自對象類型,因此 instanceof 沒法判斷變量是由子類實例化仍是由父類實例化的,因此又有了第三種解決方案 Object.prototype.toString
,它能夠解決 instanceof 沒法判斷子類和父類的問題
let arr = []
console.log(Object.prototype.toString.call(arr)) // "[object Array]"
複製代碼
理想老是美好的,現實老是骨感的,雖然 Object.prototype.toString 解決了具體是那種引用類型的問題,可是又引入了另一個問題
它沒法判斷是基本類型仍是基本包裝類型
let str = 'abc'
let objStr = new String("abc")
console.log(Object.prototype.toString.call(str)) // "[object String]"
console.log(Object.prototype.toString.call(objStr)) // "[object String]"
複製代碼
能夠看到,基本類型和基本包裝類型始終都返回 "[object String]" ,這樣仍沒法區分具體的類型,可是咱們能夠將它和 typeof 結合
const isType = variable => {
let type = typeof variable
if(type === 'object' || type === 'function'){
return Object.prototype.toString.call(variable).match( /\[object (\w+)]/)[1]
}else{
return type
}
}
console.log(isType('123')) // 'string'
console.log(isType(new String('123'))) // 'String'
複製代碼
執行環境有時候也被稱做上下文,每一個函數都有本身的執行環境,執行函數時,會將執行的函數推入全局惟一的環境棧,同時建立變量對象的一個做用域鏈,做用域是一套規定 JS 引擎如何查找變量的規則,它是一種嵌套的結構,層層遞進,造成了鏈
因爲在 innerFunc 中並無變量 a,JS 引擎就會沿着做用域鏈,找到保存在 func 中的變量 a (若是 func 中仍沒有,則會去全局做用域中尋找,再沒有則返回 undefined)
也有一種說法是在建立函數的同時會建立該函數的做用域鏈,在執行函數時,複製當前函數的做用域鏈,並將當前函數的活動對象放入做用域鏈的最前端,咱們來看上述代碼的打印結果
能夠看到在打印 innerFunc 的時候,innerFunc 尚未執行,此時它的內部已經有 2 個做用域造成的做用域鏈了,而在運行時纔將名爲 innerFunc 函數的做用域 (local) 放到做用域鏈的最前端
目前的 JavaScript 有 3 種環境
有 3 種做用域
塊級做用域通俗來講就是花括號中的代碼,在 ES6 以前 JavaScript 沒有塊級做用域,那時只能使用 var 來聲明變量,會有變量提高的效果 (將聲明變量的行爲,提高到當前環境建立時執行)
if(false) {
var color = "blue"
}
console.log('color' in window) // true
複製代碼
即便不進入 if 語句也會在 window 上建立一個 color 屬性,由於在全局環境建立時,就已經建立 color 變量了,而後再執行代碼
而 ES6 後,使用 let/const
能夠將其包裹的花括號成爲塊級做用域,而且使用 let/const 聲明的變量不會有變量提高
if(false) {
let color = "blue"
var otherColor = "red"
}
console.log('color' in window) // false
console.log('otherColor' in window) // true
複製代碼
《JavaScript 高級程序設計第三版》
《你不知道的JavaScript》