1. 什么是闭包?闭包的用途是什么?闭包的缺点是什么?
参考答案
-
关键点一:什么是闭包,需要回答「函数使用了外部的变量」这个点
关键点二:用途,需要回答「隐藏局部变量,暴露操作函数」,如果能举例说出下面代码更好const createAdd = ()=>{ let n = 0 return ()=>{ n += 1 console.log(n) } } const add = createAdd() add() // 1 add() // 2关键点三:缺点,需要回答「容易内存泄露」。注意,虽然闭包并不会造成内存泄露,真实原因是 JS 引擎的实现有问题,但网上已经以讹传讹了。所以面试时我们依然要答出这一点。
2. call、apply、bind 的用法分别是什么?
关键点一 :call 的用法要说出第一个参数是 this,后面的参数是 arguments 或其他参数
关键点二 :apply 的用法要说出第二个参数必须是数组,内含所有其他参数
关键点三 :bind 的用法要有两点
- fn.bind(x,y,z) 不会执行 fn,而是会返回一个新的函数
- 新的函数执行时,会调用 fn,调用形式为 fn.call(x, y, z),其中 x 是 this,y 和z 是其他参数
答:
-
call方法:可以指定该函数内部this的指向(即函数执行时所在的作用域),然后在所指定的作用域中,调用该函数。并且会立即执行该函数。call()方法可以传递两个参数。第一个参数是指定函数内部中this的指向(也就是函数执行时所在的作用域),第二个参数是函数调用时需要传递的参数。
-
apply方法:作用与call方法类似,也是改变this指向(函数执行时所在的作用域),然后在指定的作用域中,调用该函数。同时也会立即执行该函数。唯一的区别就是,它接收一个数组作为函数执行时的参数。
-
bind方法用于指定函数内部的this指向(执行时所在的作用域),然后返回一个新函数。bind方法并非立即执行一个函数,bind调用之后是返回原函数,需要再调用一次才行
function add(a,b){ console.log(a+b) } add.call(add, 5, 3); //8 add.apply(add, [5, 3]); //8 add.bind(add,5,3)();//8
3. 如何实现数组去重?
假设有数组 array = [1,5,2,3,4,2,3,1,3,4] 你要写一个函数 unique,使得 unique(array) 的值为 [1,5,2,3,4] 也就是把重复的值都去掉,只保留不重复的值。
要求写出两个答案:
-
不使用 Set,借鉴计数排序的原理
unique = (array) => { const hash = [] for(let i=0;i<array.length; i++){ hash[array[i]] = true } const result = [] for(let k in hash){ result.push(k) } return result }方案一缺点:只支持数字或者字符串数组,如果数组里面有对象,比如
array = [{number:1}, 2],就会出错。 -
接下来使用 Set
unique = (array) => { return [...new Set(array)] // 或者 return Array.from(new Set(array)) }方案二缺点:API 太新,旧浏览器不支持。
-
接下来使用 Map
unique = (array) => { let map = new Map(); let result = [] for (let i = 0; i < array.length; i++) { if(map.has(array[i])) { // 判断 map 中是否已有该 key continue } else { // 如果 map 中没有该 key,就加入 result 中 map.set(array[i], true); result.push(array[i]); } } return result; }方案三缺点:API 太新,旧浏览器不支持。
4. DOM 事件相关
- 什么是事件委托?
- 怎么阻止默认动作?
- 怎么阻止事件冒泡?
- 事件委托:不监听元素 C 自身,而是监听其祖先元素 P,然后判断 e.target 是不是该元素 C(或该元素的子元素)
- 阻止默认动作:e.preventDefault() 或者 return false
- 阻止冒泡:e.stopPropagation()
5. 如何理解 JS 的继承?
- 答出基于原型的继承
- 答出基于 class 的继承
-
基于原型
function Parent(name1){ this.name1 = name1 } Parent.prototype.pMethod = function(){ console.log(this.name1) } function Child(name2, name1){ Parent.call(this, name1) // 得分点 this.name2 = name2 } Child.prototype.__proto__ = Parent.prototype //上面这句代码的古板写法应该是下面三句 //const empty = function(){} //empty.prototype = Parent.prototype //Child.prototype = new empty() //古板写法额外加两分 Child.prototype.cMethod = function(){ console.log(this.name2) } //如果写成下面这种,就扣两分 //Child.prototype = { // cMethod: function(){ // console.log(this.name2) // } //}基于 class
class Parent{ constructor(name1){ this.name1 = name1 } pMethod(){ console.log(this.name1) } } class Child extends Parent{ constructor(name2, name1){ super(name1) // 得分点 this.name2 = name2 } cMethod(){ console.log(this.name2) } }
6. 数组排序
给出正整数数组 array = [2,1,5,3,8,4,9,5]
请写出一个函数 sort,使得 sort(array) 得到从小到大排好序的数组 [1,2,3,4,5,5,8,9]
新的数组可以是在 array 自身上改的,也可以是完全新开辟的内存。
不得使用 JS 内置的 sort API
- 选择
let array = [2, 1, 5, 3, 8, 4, 9, 5]
function sort(array) {
for (let i = 0; i < array.length; i++) {
let minIndex = i
for (let k = i + 1; k < array.length; k++) {
if (array[k] < array[minIndex]) {
minIndex = k
}
}
[array[i], array[minIndex]] = [array[minIndex], array[i]]
}
}
sort(array)
console.log(array)
- 冒泡
let array = [2, 1, 5, 3, 8, 4, 9, 5]
function sort(array) {
for (let i = 0; i < array.length - 1; i++) {
for (let j = 0; j < array.length - 1 - i; j++) {
if (array[j] > array[j + 1]) {
[array[j], array[j + 1]] = [array[j + 1], array[j]]
}
}
}
return array
}
sort(array)
console.log(array)
7. 对 Promise 的了解
要点:
- Promise 的用途
- 如何创建一个 new Promise
- 如何使用 Promise.prototype.then
- 如何使用 Promise.all
- 如何使用 Promise.race
-
要点1 Promise 用于避免回调地域,让代码看起来更同步
-
要点2
function fn(){ return new Promise((resolve, reject)=>{ 成功时调用 resolve(data) 失败时调用 reject(reason) }) } -
要点3:const promise1 = fn() // 得到 promise1 对象
fn().then(success, fail).then(success2, fail2).catch(fail3)
或者
promise1.then(success, fail).then(success2, fail2).catch(fail3)
均可 -
要点4:Promise.all([promise1, promise2]) 并行,等待所有 promise 成功。
如果都成功了,则 all 对应的 promise 也成功;如果有一个失败了,则 all 对应的 promise 失败。 -
要点5:Promise.race([promise1, promise2]),返回一个 promise,一旦数组中的某个promise解决或拒绝,返回的 promise就会解决或拒绝。