聲明:慕課網《前端JavaScript面試技巧》的筆記,僅用於查閱複習,不得用於商業用途。html
基礎知識前端
JS APInode
開發環境jquery
運行環境面試
關於面試ajax
關於基礎算法
先從幾道面試題提及json
typeof
能獲得的哪些類型?===
什麼時候使用==
?window.onload
和DOMContentLoaded
的區別?<a>
標籤,點擊的時候彈出來對應的序號模塊加載器
,實現相似require.js
的基本功能隨機排序
思考數組
看到的是什麼
?永遠也看不完
的題海?如何搞定全部面試題瀏覽器
上一節思考問題的結論
看到的是什麼
? -> 考點
永遠也看不完
的題海? -> 不變應萬變
題目到知識再到題目
題目考察的知識點
typeof
能獲得的哪些類型?JS變量類型
===
什麼時候使用==
?強制類型轉換
window.onload
和DOMContentLoaded
的區別?瀏覽器渲染過程
<a>
標籤,點擊的時候彈出來對應的序號做用域
模塊加載器
,實現相似require.js
的基本功能JS模塊化
隨機排序
JS基礎算法
變量類型和計算
題目
知識點
變量類型
值類型
let a = 100
let b = a
a = 200
console.log(b) // 100
複製代碼
引用類型
let a = { age: 20 }
let b = a
b.age = 21
console.log(a.age) // 21
複製代碼
typeof運算符
typeof undefined // "undefined"
typeof 'abc' // "string"
typeof 123 // "number"
typeof true // "boolean"
typeof {} // "object"
typeof [] // "object"
typeof null // "object"
typeof console.log // "function"
複製代碼
變量計算 - 強制類型轉換
字符串拼接
let a = 100 + 10 // 110
let b = 100 + '10' // "10010"
複製代碼
==運算符
100 == '100' // true
0 == '' // true
null == undefined // true
複製代碼
if語句
let a = true
if (a) {
// ...
}
let b = 100
if (b) {
// ...
}
let c = ''
if (c) {
// ...
}
複製代碼
邏輯運算符
console.log(10 && 0) // 0
console.log('' || 'abc') // "abc"
console.log(!window.abc) // true
// 判斷一個變量會被當作true仍是false
let a = 100
console.log(!!a) // true
複製代碼
解答
JS中使用typeof能獲得的類型
symbol
let sym = Symbol('commet')
console.log(typeof sym) // "symbol"
複製代碼
什麼時候使用===什麼時候使用==
if (obj.a == null) {
// 這裏至關於obj.a === null || obj.a === undefined,簡寫形式
// 這是jquery源碼中推薦的寫法
}
複製代碼
JS中的內置函數
String
Number
Boolean
Object
Array
Function
Data
RegExp
Error
複製代碼
JS按存儲方式區分變量類型
如何理解JSON
JSON.stringify({ a: 10, b: 20 )
JSON.parse('{"a":10,"b":20}')
複製代碼
if (...) {}中false的狀況:false 0 NaN null undefined
內置對象有:JSON、Math
let s = Symbol()
typeof s // "symbol"
let s1 = Symbol()
s === s1 // false
let s2 = Symbol('s2s2')
console.log(s2) // Symbol(s2s2)
let s3 = s2
console.log(s3 === s2) // true
let sym1 = Symbol('111')
let sym2 = Symbol('222')
let obj = { [sym1]: 'hello world' }
obj[sym2] = 123
console.log(obj) // { Symbol(111): "hello world", Symbol(222): 123 }
console.log(obj[sym1]) // "hello world"
console.log(obj[sym2]) // 123
複製代碼
原型和原型鏈
題目
數組類型
知識點
構造函數
function Foo(name, age) {
this.name = name
this.age = age
this.class = 'class-1'
// return this // 默認有這一行
}
let f = new Foo('lilei', 18)
// let f2 = new Foo('hanmeimei', 17) // 建立多個對象
複製代碼
構造函數-擴展
判斷一個變量是否爲「數組」:變量 instanceof Array
原型規則和示例
原型規則
是學習原型鏈
的基礎5條原型規則
__proto__
(隱式原型)屬性,屬性值是一個普通的對象prototype
(顯示原型)屬性,屬性值也是一個普通的對象__proto__
屬性值指向它的構造函數的prototype
屬性值__proto__
(即它的構造函數的prototype
)中尋找let obj = {}
obj.a = 100
let arr = []
arr.a = 100
function fn() {}
fn.a = 100
console.log(obj.__proto__)
console.log(arr.__proto__)
console.log(fn.__proto__)
console.log(fn.prototype)
console.log(obj.__proto__ === Object.prototype)
複製代碼
// 構造函數
function Foo(name, age) {
this.name = name
}
Foo.prototype.alertName = function() {
alert(this.name)
}
// 建立實例
let f = new Foo('lilei')
f.printName = function() {
console.log(this.name)
}
// 測試
f.printName()
f.alertName()
複製代碼
for (let item in f) {
// 高級瀏覽器已經在 for in 中屏蔽了來自原型的屬性
// 可是這裏建議你們仍是加上這個判斷,保證程序的健壯性
if (f.hasOwnProperty(item)) {
console.log(item)
}
}
複製代碼
// 構造函數
function Foo(name, age) {
this.name = name
}
Foo.prototype.alertName = function() {
alert(this.name)
}
// 建立實例
let f = new Foo('lilei')
f.printName = function() {
console.log(this.name)
}
// 測試
f.printName()
f.alertName()
f.toString() // 要去f.__proto__.__proto__中查找
複製代碼
原型鏈
instanceof
引用類型
屬於哪一個構造函數
的方法解題
如何準確判斷一個變量是數組類型
let arr = []
arr instanceof Array // true
typeof arr // object,typeof是沒法判斷是不是數組的
複製代碼
寫一個原型鏈繼承的例子
// 動物
function Animal() {
this.eat = function() {
console.log('animal eat')
}
}
// 狗
function Dog() {
this.bark = function() {
console.log('dog bark')
}
}
Dog.prototype = new Animal()
// 哈士奇
let hashiqi = new Dog()
// 接下來代碼演示時,會推薦更加貼近實戰的原型繼承示例
複製代碼
描述new一個對象的過程
function Foo(name, age) {
this.name = name
this.age = age
this.class = 'class-1'
// return this // 默認有這一行
}
let f = new Foo('lilei', 18)
// let f2 = new Foo('hanmeimei', 18) // 建立多個對象
複製代碼
zepto(或其餘框架)源碼中如何使用原型鏈
寫一個封裝DOM查詢的例子
function Elem(id) {
this.elem = document.getElementById(id)
}
Elem.prototype.html = function(val) {
let elem = this.elem
if (val) {
elem.innerHTML = val
return this // 爲了鏈式操做
} else {
return elem.innerHTML
}
}
Elem.prototype.on = function(type, fn) {
let elem = this.elem
elem.addEventListener(type, fn)
}
let div1 = new Elem('div1')
// console.log(div1.html())
div1.html('<p>hello imooc</p>').on('click', function() {
alert('clicked')
})
複製代碼
做用域和閉包
題目
<a>
標籤,點擊的時候彈出來對應的序號知識點
執行上下文
console.log(a) // undefined
var a = 100
fn('lilei') // "lilei" 20
function fn(name) {
age = 20
console.log(name, age)
var age
}
複製代碼
<script>
或者一個函數PS:注意「函數聲明」和「函數表達式」的區別
this
var a = {
name: 'A',
fn: function() {
console.log(this.name)
}
}
a.fn() // this === a
a.fn.call({ name: 'B' }) // this爲{ name: 'B' }
var fn1 = a.fn
fn1() // this === window
複製代碼
this
// 構造函數
function Foo(name) {
this.name = name
}
let f = new Foo('lilei')
f.name // "lilei"
複製代碼
// 做爲一個對象的屬性
let obj = {
name: 'A',
printName: function() {
console.log(this.name)
}
}
obj.printName() // "A"
複製代碼
// 普通函數
function fn() {
console.log(this)
}
fn() // window
複製代碼
// call apply bind
function fn1(name, age) {
console.log(name)
console.log(this)
}
fn1.call({ x: 1 }, 'lilei', 20) // "lilei" {x: 1}
fn1.apply({ x: 200 }, ['lilei', 20]) // "lilei" {x: 200}
let fn2 = function(name, age) {
console.log(name)
console.log(this)
}.bind({x: 300})
fn2('lilei', 20) // "lilei" {x: 300}
複製代碼
做用域
// 無塊級做用域
if (true) {
var name = 'lilei'
}
console.log(name) // "lilei"
// 函數和全局做用域
var a = 100
function fn() {
var a = 200
console.log('fn', a)
}
console.log('global', a) // "global 100"
fn() // "fn 200"
複製代碼
做用域鏈
var a = 100
function fn() {
var b = 200
// 當前做用域沒有定義的變量,即「自由變量」
console.log(a)
console.log(b)
}
fn()
複製代碼
var a = 100
function F1() {
var b = 200
function F2() {
var c = 300
console.log(a) // a 是自由變量
console.log(b) // b 是自由變量
console.log(c)
}
F2()
}
F1()
複製代碼
// js 沒有塊級做用域
// ES6 有塊級做用域
複製代碼
閉包
function F1() {
var a = 100
// 返回一個函數(函數做爲返回值)
return function() {
console.log(a)
}
}
// f1 獲得一個函數
var f1 = F1()
var a = 200
f1() // 100
複製代碼
閉包的使用場景
// 閉包 1,函數做爲返回值
function F1() {
var a = 100
return function() {
console.log(a) // a 自由變量,向父做用域去尋找 ——函數**定義**時的父做用域
}
}
var f1 = F1()
var a = 200
f1() // 100
複製代碼
// 閉包 2,函數做爲參數傳遞
function F1() {
var a = 100
return function() {
console.log(a)
}
}
var f1 = F1()
function F2(fn) {
var a = 300
fn()
}
F2(f1) // 100
複製代碼
解題
<a>
標籤,點擊的時候彈出來對應的序號說一下對變量提高的理解
說明this幾種不一樣的使用場景
建立10個<a>
標籤 點擊的時候彈出來對應的序號
// 這是一個錯誤的寫法!!!
var i, a
for (i = 0; i < 10; i++) {
a = document.createElement('a')
a.innerHTML = i + '<br>'
a.addEventListener('click', function(e) {
e.preventDefault()
alert(i) // 自由變量,要去父做用域獲取值
})
document.body.appendChild(a)
}
複製代碼
// 這是正確的寫法!!!
var i
for (i = 0; i < 100; i++) {
(function(i) {
var a = document.createElement('a')
a.innerHTML = i + '<br>'
a.addEventListener('click', function(e) {
e.preventDefault()
alert(i)
})
document.body.appendChild(a)
})(i)
}
複製代碼
如何理解做用域
實際開發中閉包的應用
// 閉包實際應用中主要用於封裝變量,收斂權限
function isFirstLoad() {
var _list = []
return function(id) {
if (_list.indexOf(id) >= 0) {
return false
} else {
_list.push(id)
return true
}
}
}
// 使用
var firstLoad = isFirstLoad()
firstLoad(10) // true
firstLoad(10) // false
firstLoad(20) // true
// 你在isFirstLoad函數外,根本不可能修改掉_list的值
複製代碼
異步和單線程
題目
知識點
什麼是異步
console.log(100)
setTimeout(function() {
console.log(200)
}, 1000)
console.log(300)
複製代碼
同步阻塞後續程序代碼執行,異步不會阻塞程序的的運行。
對比同步
console.log(100)
alert(200) // 1秒鐘以後手動點擊確認
console.log(300)
複製代碼
什麼時候須要異步
前端使用異步的場景
<img>
加載ajax請求代碼示例
console.log('start')
$.get('./data1.json', function(data1) {
console.log(data1)
})
console.log('end')
複製代碼
<img>
加載示例
console.log('start')
var img = document.createElement('img')
img.onload = function() {
console.log('loaded')
}
img.src = '/xxx.png'
console.log('end')
複製代碼
事件綁定示例
console.log('start')
document.getElementById('btn1').addEventListener('click', function() {
alert('clicked')
})
console.log('edn')
複製代碼
異步和單線程
console.log(100)
setTimeout(function() {
console.log(200)
})
console.log(300)
複製代碼
console.log('start')
$.get('./data1.json', function(data1) {
console.log(data1)
})
console.log('end')
複製代碼
console.log('start')
document.getElementById('btn1').addEventListener('click', function() {
alert('clicked')
})
console.log('edn')
複製代碼
同步和異步的區別是什麼
一個關於setTimeout的筆試題
console.log(1)
setTimeout(function() {
console.log(2)
}, 0)
console.log(3)
setTimeout(function() {
console.log(4)
}, 1000)
console.log(5)
複製代碼
前端使用異步的場景有哪些
重點總結
其餘知識
題目
知識點
日期
Date.now() // 獲取當前時間毫秒數
var dt = new Date()
dt.getTime() // 獲取毫秒數
dt.getFullYear() // 年
dt.getMonth() // 月(0-11)
dt.getDate() // 日(0-31)
dt.getHours() // 小時(0-23)
dt.getMinutes() // 分鐘(0-59)
dt.getSeconds() // 秒(0-59)
複製代碼
Math
數組API
forEach
var arr = [1, 2, 3]
arr.forEach(function(item, index) {
// 遍歷數組的全部元素
console.log(index, item)
})
複製代碼
every
var arr = [1, 2, 3]
var result = arr.every(function(item, index) {
// 用來判斷全部的數組元素,都知足條件
if (item < 4) {
return true
}
})
console.log(result)
複製代碼
some
var arr = [1, 2, 3]
var result = arr.every(function(item, index) {
// 用來判斷只要有一個數組元素,知足條件
if (item < 2) {
return true
}
})
console.log(result)
複製代碼
sort
var arr = [1, 4, 2, 3, 5]
var arr2 = arr.sort(function(a, b) {
// 從小到大排序
return a - b
// 從大到小排序
return b - a
})
console.log(arr2)
複製代碼
map
var arr = [1, 2, 3, 4]
var arr2 = arr.map(function(item, index) {
// 將元素從新組裝,並返回
return '<b>' + item + '</b>'
})
console.log(arr2)
複製代碼
filter
var arr = [1, 2, 3]
var arr2 = arr.filter(function(item, index) {
// 經過某一個條件過濾數組
if (item >= 2) {
feturn true
}
})
console.log(arr2)
複製代碼
對象API
var obj = {
x: 100,
y: 200,
z: 300
}
var key
for (key in obj) {
// 注意這裏的 hasOwnProperty,在講原型鏈的時候講過了
if (obj.hasOwnProperty(key)) {
console.log(key, obj[key])
}
}
複製代碼
解答
獲取2017-06-10格式的日期
function formatDate(dt) {
if (!dt) {
dt = new Date()
}
var year = dt.getFullYear()
var month = dt.getMonth() + 1
var date = dt.getDate()
return year + '-' + month.toString().padStart(2, '0') + '-' + date.toString().padStart(2, '0')
}
formatDate(new Date())
複製代碼
獲取隨機數,要求是長度一致的字符串格式
var random = Math.random()
random = random + '0000000000'
random = random.slice(0, 10)
console.log(random)
複製代碼
寫一個能遍歷對象和數組的通用forEach函數
function forEach(obj, fn) {
var key
if (obj instanceof Array) {
obj.forEach(function(item, index) {
fn(index, item)
})
} else {
for (key in obj) {
fn(key, obj[key])
}
}
}
var arr = [1, 2, 3]
// 注意,這裏參數的順序換了,爲了和對象的遍歷格式一致
forEach(arr, function(index, item) {
console.log(index, item)
})
var obj = { x: 100, y: 200 }
forEach(obj, function(key, value) {
console.log(key, value)
})
複製代碼
重點總結
從基礎只是到JS-Web-API
回顧JS基礎知識
JS-Web-API
W3C標準中關於JS的規定有:
頁面彈框是window.alert(123),瀏覽器須要作:
獲取元素document.getElementById(id),瀏覽器須要:
可是W3C標準沒有規定任何JS基礎相關的東西
全面考慮,JS內置的全局函數和對象有哪些?
總結
常說的JS(瀏覽器執行的JS)包含兩部分:
DOM操做(Document Object Model)
題目:
知識點:
DOM的本質
<?xml version="1.0" encoding="utf-8"?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body> <other> <a></a> <b></b> </other> </note> 複製代碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div>
<p>this is p</p>
</div>
</body>
</html>
複製代碼
DOM本質:瀏覽器拿到html代碼後,DOM把html代碼結構化成瀏覽器可識別以及js可識別的東西。
html代碼就是一個字符串,可是瀏覽器已經把字符串結構化成樹形結構了。
DOM能夠理解爲:
DOM節點操做
獲取DOM節點
var div1 = document.getElementById('div1') // 元素
var divList = document.getElementsByTagName('div') // 集合
console.log(divList.length)
console.log(divList[0])
var containerList = document.getElementsByClassName('.container') // 集合
var pList = document.querySelectorAll('p') // 集合
複製代碼
Property
var pList = document.querySelectorAll('p')
var p = pList[0]
console.log(p.style.width) // 獲取樣式
p.style.width = '100px' // 修改樣式
console.log(p.className) // 獲取class
p.className = 'p1' // 修改class
// 獲取nodeName 和 nodeType
console.log(p.nodeName)
console.log(p.nodeType)
複製代碼
Attribute
var pList = document.querySelectorAll('p')
var p = pList[0]
p.getAttribute('data-name')
p.setAttribute('data-name', 'imooc')
p.getAttribute('style')
p.setAttribute('style', 'font-size: 30px;')
複製代碼