前端知识点摘录

107 阅读3分钟

1. 什么是闭包?闭包的用途是什么?闭包的缺点是什么?

参考答案

  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] 也就是把重复的值都去掉,只保留不重复的值。

要求写出两个答案:

  1. 不使用 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],就会出错。

  2. 接下来使用 Set

    unique = (array) => {
        return [...new Set(array)] 
        // 或者 return Array.from(new Set(array))
    }
    

    方案二缺点:API 太新,旧浏览器不支持。

  3. 接下来使用 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 事件相关

  1. 什么是事件委托?
  2. 怎么阻止默认动作?
  3. 怎么阻止事件冒泡?
  • 事件委托:不监听元素 C 自身,而是监听其祖先元素 P,然后判断 e.target 是不是该元素 C(或该元素的子元素)
  • 阻止默认动作:e.preventDefault() 或者 return false
  • 阻止冒泡:e.stopPropagation()

5. 如何理解 JS 的继承?

  • 答出基于原型的继承
  • 答出基于 class 的继承
  1. 基于原型

    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 的了解

要点:

  1. Promise 的用途
  2. 如何创建一个 new Promise
  3. 如何使用 Promise.prototype.then
  4. 如何使用 Promise.all
  5. 如何使用 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就会解决或拒绝。