前端必須掌握的JavaScript基礎知識
做為前端三劍客的JavaScript,可以說是重中之重了,是前端開發必不可缺的基礎,因為有了JavaScript,才使靜態的頁面產生了一些動態的效果,你對JavaScript瞭解有多少?本文整理了個人學習中一些Javascript基礎知識,以便查漏補缺。
1. 說一下你瞭解的主要瀏覽器及其核心
2. js中資料型別分為幾種,都有哪些
-
簡單資料型別:
number
、string
、Boolean
、null
、undefined
、symbol
-
複雜資料型別:
object
、array
、function
注意: 簡單資料型別是沒有屬性和方法的且簡單資料型別的值不可改變,儲存複製的是值本身,儲存在棧記憶體;引用資料儲存與複製的是一個地址,改變其中一個另一個也會改變
3. 棧記憶體與堆記憶體的瞭解
- 棧記憶體 棧記憶體儲存的都是一些比較簡單的資料和堆記憶體的地址,舉個例子
圖中可以看出當改變了第一個num的值,num1的值不會因為num的值改變而改變,也再次印證了簡單資料型別儲存複製的是值本身
- 堆記憶體 堆記憶體儲存的是一些比較複雜的資料,資料儲存在堆記憶體,資料的地址儲存在棧記憶體裡面,舉個例子
圖中可以看出當改變了obj的name屬性,obj1的name屬性也跟著改變了,原因是 引用型別複製的是引用地址,obj和obj1指向的是堆記憶體中同一塊空間,無論改變obj還是obj1 其實都是改變的同一個資料
3. typeof返回值有哪些
number
string
、Boolean
、 undefined
、 object
、 function
-
typeof typeof 返回 string
-
typeof null 、 typeof 物件 、 typeof 陣列 都返回object
-
返回false的情況:
0
""
null
false
NaN
undefined
不成立的表示式
4. 如何檢測一個物件是不是陣列
- 第一種方法:
instanceof
運算子用來測試一個物件在其原型鏈中是否存在一個建構函式的 prototype 屬性。
分析過程:
圖中可知 arr是Array構造出來的例項,arr.__proto__
Array.prototype
,由此得知 arr物件的原型鏈上有Array
建構函式的prototype屬性。而arr.constructor
指向了構造它的建構函式,因為arr例項沒有constructor
屬性,就去原型鏈找,原型鏈上有constructor
,由此得知 arr.constructor === Array
注意: 但是此方法有漏洞,用此方法判斷不一定準確,因為我們可以改變一個物件的this指向,這裡就不做過多敘述了
- 第二種方法:
Object.prototype.toString
借用Object
原型上的方法來實現檢測陣列
分析過程:
toString
方法是Object原型上的方法,像function
,Array
作為Object的例項,重寫了toString的方法。而我們通過原型鏈的知識可以知道,我們在呼叫toString方法時,並不能直接呼叫Object原型上的toString方法,呼叫的是重寫後的方法。所以,我們想得到物件具體型別的話,應該使用call借調Object原型上的toString方法,這點MDN文件也有說明
- 第三種方法:
Array.isArray
此方法接收一個引數,用於確定傳遞的值是否是一個 Array
分析過程:
此方法為ES5新增的方法,可以直接判斷引數是不是一個數組型別,MDN文件說明
5. 自增自減運算子和邏輯運算子
++
運算子: 寫到後面叫做後自增,寫到前面叫做先自增
let a = 10
let b = ++a + a++
console.log(a) // 12
console.log(b) // 22
//分析: ++a 是a先加1賦值給自己,此時a是11,再加上11,所以b等於11 + 11 = 22,最後a++,a變成了12
let a = 5
let b = a++ + ++a + a++
console.log(b) // 19
console.log(a) // 8
let a = 10
let b = a-- + ++a
console.log(b) // 20
console.log(a) // 10
-
--
運算子: 和自增運算子同,就不多說了 -
邏輯運算子
-
&&
: 假前真後,全真才為真 有一個假就是假 -
||
: 真前假後,全假才為假 有一個真就是真 -
!
: 取反 轉換為布林值
-
6. 氣泡排序
-
初級版本
- 讓陣列中每個值都兩兩進行比較一趟的結果,最大的數會在陣列的最後面
let arr = [23, 46, 45, 39, 66, 82] for (let i = 0; i < arr.length - 1; i++) { if (arr[i] > arr[i + 1]) { let temp = arr[i] arr[i] = arr[i + 1] arr[i + 1] = temp } } console.log(arr) //分析:陣列從arr[0]兩兩和後面數相比,一共比五次。所以讓length - 1,讓i最大取值到4就可以了。當i取值到4的時候 arr[4]和arr[5]相比,也就是arr.length - 2 和 arr.length - 1相比
- 讓兩兩比較的結果多次執行,就會一次一次的把最大的數往後排,於是外面套一個for迴圈控制比多少趟
for (j = 0; j < arr.length - 1; j++) { for (let i = 0; i < arr.length - 1; i++) { if (arr[i] > arr[i + 1]) { let temp = arr[i] arr[i] = arr[i + 1] arr[i + 1] = temp } } }
-
高階版本
//第0趟 比較5次 多比了0次 //第1趟 比較4次 多比了1次 找到了1個最大的數 //第2趟 比較3次 多比了2次 找到了2個最大的數 //思路:遍歷第一圈的時候,兩兩相比 一共比了5次,第二圈的時候由於已經找到了1個最大的數,此圈少比一次就可以了。但是for迴圈此時還是走了5圈,所以此時是多比了一次的 ,以此類推 let arr = [23, 46, 45, 39, 66, 82] for (j = 0; j < arr.length - 1; j++) { for (let i = 0; i < arr.length - 1 - j; i++) { // 讓length再減j if (arr[i] > arr[i + 1]) { let temp = arr[i] arr[i] = arr[i + 1] arr[i + 1] = temp } } }
-
終極版本 如果在排序過程中,發現數組已經排好序了,後面的次數就沒必要排了
- 假設成立法
//判斷陣列中的成績是否都及格了 let arr = [80,100,90,65,54] //第一種思路: for (let i = 0; i < arr.length; i++) { if (arr[i] >= 60) { console.log('都及格了') }else { console.log('不及格') } } //第二種思路:一旦找到小於60的 就代表並不是都及格了 for (let i = 0; i < arr.length; i++) { if (arr[i] < 60) { console.log('並未都及格') }
思路:排序過程中,假設陣列是有順序的那麼就不用再次排序了。也就是說只要找到後一項比前一項大,那麼假設就不成立
for (let i = 0; i < arr.length; i++) { if (arr[i] > arr[i + 1]) { console.log('假設失敗') }
- 優化氣泡排序
let arr = [23, 46, 45, 39, 66, 82] for (j = 0; j < arr.length - 1; j++) { let flag = true for (let i = 0; i < arr.length - 1 - j; i++) { if (arr[i] > arr[i + 1]) { flag = false let temp = arr[i] arr[i] = arr[i + 1] arr[i + 1] = temp } else if (flag == true){ break } } }
7. 簡述下淺拷貝與深拷貝
- 淺拷貝: 拷貝的是物件的一層屬性,如果物件裡面還有物件,則只會拷貝地址,修改其中一個會相互影響,適合拷貝簡單資料型別
let obj = {
name: 'zs',
age: 18,
money: 1000
}
function Copy(obj) {
let newObj = {}
for (let k in obj) {
newObj[k] = obj[k]
}
return newObj
}
console.log(Copy(obj))
- 深拷貝: 拷貝物件的多層物件,如果物件裡面還有物件,使用遞迴的方式去實現
let obj = {
name: 'zs',
age: 18,
money: 1000,
smoke: {
brand: 'suyan',
num: 20
}
}
function Copy(obj) {
let newObj = {}
for (let k in obj) {
newObj[k] = typeof obj[k] === 'object'? Copy(obj[k]) : obj[k]
}
return newObj
}
console.log(Copy(obj)) // 修改obj不會影響到newObj
8. 說一下你對原型和原型鏈的理解
函式都有prototype
屬性,這個屬性是一個物件,我們稱之為原型物件;每一個物件都有__proto__
屬性,該屬性指向了原型物件,原型物件也是物件,也有__proto__
屬性,這樣一層一層形成了鏈式結構,我們稱之為原型鏈
9. 閉包的理解
相互巢狀關係的兩個函式,當內部函式引用外部函式的變數的時候就形成了閉包,閉包將會導致原有的作用域鏈不釋放,造成記憶體洩露。有些地方說內部函式被儲存到外部的時候形成閉包其實是不具體的,儲存到外部只是為了方便呼叫內部的這個函式,而函式巢狀的原因則是因為需要區域性變數,如果是全域性變數就達不到閉包的目的了
-
閉包的優點: 形成私有空間,避免全域性汙染;持久化記憶體,儲存資料
-
閉包的缺點: 持久化記憶體導致的記憶體洩露,解決辦法 儘量避免函式的巢狀;執行完的變數賦值為null,讓垃圾回收機制回收釋放記憶體
經典案例:點選li獲取下標
<ul>
<li>111</li>
<li>222</li>
<li>333</li>
<li>444</li>
<li>555</li>
</ul>
var lis = document.querySelectorAll('li')
for (var i = 0; i < lis.length; i++) {
(function (j) {
lis[j].onclick = function () {
console.log(j)
}
})(i)
}
10. call、apply、bind方法的區別
-
call和apply方法都可以呼叫函式,方法內的第一個引數可以修改this指向
-
call方法可以有多個引數,除了第一個引數標識this指向,其他引數作為函式的實參傳遞給函式; apply方法最多有兩個引數,第一個引數標識this指向,第二個引數是一個數組或者偽陣列,數組裡面的每一項作為函式的實參傳遞給函式
-
bind方法不能自動呼叫函式,它會建立一個副本函式,並且繫結新函式的this指向bind返回的新函式
11. 偽陣列有哪些
-
函式引數列表 arguments
-
DOM 物件列表 和 childNodes 子節點列表
-
jquery物件 比如$("div")
12. 偽陣列和真陣列有什麼區別,偽陣列如何轉換為真陣列呢
區別
-
偽陣列其實是一個物件,真陣列是Array
-
偽陣列擁有length屬性,但長度不可以改變,真陣列長度是可以改變的
-
偽陣列不具備真陣列的方法,比如 push 、 slice等等
轉換
- call借調陣列方法
- ES6新語法 Array.from方法從一個類似陣列或可迭代物件建立一個新的,淺拷貝的陣列例項
- ES6新語法 擴充套件運算子
這裡有個注意的點,使用自己定義的偽陣列的時候,擴充套件運算子無法轉換成真陣列,百度了下才知道自己定義的偽陣列由於缺少遍歷器Iterator會報錯
13. 瞭解過陣列的降維(扁平化)嗎
-
借調陣列原型上的concat方法
let arr = [1,2,3,[4,5]] Array.prototype.concat.apply([], arr)
-
使用陣列的concat方法和擴充套件運算子
let arr = [1,2,3,[4,5]] [].concat(...arr)
注意: 以上兩種方法只能實現一層巢狀,如果是多層的巢狀就用下面兩個方法
-
利用Array.some方法判斷陣列中是否還存在陣列,如果存在用展開運算子配合concat連線陣列
let arr = [1,2,3,[4,[5,6]]] while (arr.some(item => Array.isArray(item))) { arr = [].concat(...arr); } console.log(arr);
-
ES6中的flat函式實現陣列的扁平化
let arr = [1,2,3,[4,[5,6]]] arr.flat( Infinity ) //flat方法的infinity屬性,可以實現多層陣列的降維
14. var
const
let
有哪些不同
-
var宣告的變數存在變數提升,let const無
-
var可以重複宣告同名變數, let const 不可以,會報錯 has already been declared
-
let const 宣告變數有塊級作用域,var沒有
-
const定義的變數是常量不能修改,但是如果是物件或者陣列可以修改屬性,增加屬性
15. this指向問題
-
函式呼叫模式, this指向window
-
建構函式呼叫模式, this指向新建立的例項物件
-
方法呼叫模式, this指向呼叫方法的物件
-
上下文呼叫模式, call和apply方法中, this指向方法內的第一個引數;bind方法中, bind建立的新函式的this繫結為bind方法中新的函式
-
在事件處理函式中,this指向觸發事件的當前元素
-
定時器中,this指向window
-
箭頭函式中沒有this指向問題,它的this和外層作用域的this保持一致
-
匿名函式中的this總是指向window
16. 你是如何理解面向物件的,它和麵向過程有什麼區別
-
面向物件是一種軟體開發的思想,就是把程式看作一個物件,將屬性和方法封裝中,以提高程式碼的靈活性、複用性、可擴充套件性。面向物件有三大特性:
封裝
繼承
多型
。封裝指的是把屬性或者方法儲存在物件中的能力,繼承指的是由另一個類得來的屬性和方法的能力,多型指的是編寫能以多種方法執行的函式或方法的能力。面向物件開發優點是易維護
易擴充套件
降低工作量,縮短開發週期
,缺點是效能低 -
面向過程是一種以過程為中心的程式設計思想,就是把解決問題分為一個一個的步驟,先幹什麼後幹什麼,然後用函式把這些步驟一步一步實現,使用的時候一個一個依次呼叫就可以了。面向過程的優點就是效能比面向物件高,因為類呼叫時需要例項化,開銷比較大,比較消耗資源;比如微控制器、嵌入式開發、 Linux/Unix等一般採用面向過程開發,效能是最重要的因素,缺點就是沒有面向物件那樣易維護、易擴充套件、易複用
17. 陣列去重的方法
//第一種方法
const arr = [1,2,3,3,4,5,5,5,7]
const newArr = []
arr.forEach(item =>{
if(!newArr.includes(item)) {
newArr.push(item)
}
})
console.log(newArr)
//第二種方法 es6新增一個set方法 set有一個特徵,內部的值不允許重複
const arr = [1,2,3,3,4,5,5,5,7]
const set = new Set(arr)
const newArr = [...set] // ... 展開運算子 可以展開陣列或者物件
最後
為了讓大家快速精通JavaScript,在這裡免費分享給大家一份Javascript學習指南。
Javascript學習指南文件涵蓋了javascript 語言核心、詞法結構 、型別、值和變數 、表示式和運算子 、語句、物件 、陣列 、函式 、類和模組 、 正則表示式的模式匹配、 javascript的子集和擴充套件 、伺服器端javascript /客戶端javascript 、web瀏覽器中的javascript 、window物件 、指令碼化文件、指令碼化css 、事件處理等22章知識點。內容豐富又詳細,拿下網際網路一線公司offfer的小夥伴都在看。
每個知識點都有左側導航書籤頁,看的時候十分方便,由於內容較多,下面列舉的部分內容和圖片。
物件
- 建立物件
- 屬性的查詢和設定
- 刪除屬性
- 檢測屬性
- 列舉屬性
- 屬性getter和setter
- 屬性的特性
陣列
- 建立陣列
- 陣列元素的讀和寫
- 稀疏陣列
- 陣列長度
- 陣列元素的新增和刪除
- 陣列遍歷
- 多維陣列
函式
- 函式定義
- 函式呼叫
- 函式的實參和形參
- 作為值的函式
- 作為名稱空間的函式
- 閉包
- 函式屬性、方法和建構函式
類和模組
- 類和原型
- 類和建構函式
- javascript中java式的類繼承
- 類的擴充
- 類和型別
- javascript中的面向物件技術
- 子類
正則表示式的模式匹配
- 正則表示式的定義
- 用於模式匹配的string方法
- regexp物件
javascript的子集和擴充套件
- javascript的子集
- 常量和區域性變數
- 解構賦值
- 迭代
- 函式簡寫
- 多catch 從句
- e4x: ecmascript for xml
web瀏覽器中的javascript
- 客戶端javascript
- 在html裡嵌入javascript
- javascript程式的執行
- 相容性和互用性
- 可訪問性
- 安全性
- 客戶端框架
window物件
- 計時器
- 瀏覽器定位和導航
- 瀏覽歷史
- 瀏覽器和螢幕資訊
- 對話方塊
- 錯誤處理
- 作為window物件屬性的文件元素
如果你有其他語言的程式設計經歷,這份文件會有助你瞭解JavaScript是一門高階的、動態的、弱型別的程式語言,非常適合面向物件和函式式的程式設計風格。
我在這裡將這份完整版的JS學習指南電子版文件提供出來,感興趣的朋友都可以找我拿一份學習!(純免費的一個分享,希望能給大家帶來實質性的幫助)
快速入手通道:【點選這領取Javascript學習指南電子版】
你的支援,我的動力;祝各位前程似錦,offer不斷!!!