2020 秋招知识点总结 -- ( JS篇 ) 🏆 掘金技术征文|双节特别篇

3,118 阅读4分钟

前言

Hello 大家好,这是一篇近期关于面试总结的文章,目前是在校大四学生,文章形式主要以问题和答案的方式展现,可能会有不全面的的地方,希望大家批评指正,一方面是记录自己的知识点,另一方面是分享出来给需要的小伙伴!!!

所有的知识点都慢慢整理到 Github 快来给我Star呀😊~

因为近期一直在忙着找实习和毕业的事情,没有时间整理出来。希望大家看完能够重温一下基础。


1. var、let 及 const 区别

  • 函数提升优先于变量提升,函数提升会把整个函数放到顶部,而变量提升只是把声明方到顶部

  • var 存在提升,可以在声明之前使用 值为 undefined。let、const 不可以是因为会形成暂时性死区

  • letconst 作用基本一致,前者不允许在同一个作用域重复声明同一个变量,后者声明一个基本类型的时候为常量,不可修改;声明对象可以修改

2. 说一下内置类型

  • JS 中有其中内置类型,可以分为两大类型:基本类型()和对象()
  • 基本类型有六种:nullundefinedbooleannumberstringsymbol
  • 对象( Object )是引用类型,在使用过程会涉及到浅拷贝和深拷贝的问题

typeof 对于基本类型,除了null 都可以正常显示

typeof 1 // 'number'
typeof '1' // 'string'
typeof undefined // 'undefined'
typeof true // 'boolean'
typeof Symbol() // 'symbol'
--------------------------------------------
typeof []  // 'object'
typeof {}  // 'object'

3. 实现 instanceof 原理

instanceof 可以正确判断对象类型,判断方式以原型链的方式查找

function myInstanceof(left,right){
  let prototype = right.prototype;
  left = left.__proto__;
  while(true){
    if(left === null || left === undefined)
      return false
    if(prototype === left)
      return true
    left = left.__proto__
  }
}

4. 原型及原型链

  • 每个函数都有自己的 prototype
  • 每个对象都有 __proto__属性,指向了创建该对象的构造函数的原型。其实这个属性指向了 prototype,所以使用 _proto_ 来访问
  • 对象可以通过__proto__ 来寻找不属于该对象的属性,__proto__ 将对象连接起来组成了原型链

5. this指向

改变this指向可以通过 call、apply、bind. 传参形式分别是 参数队列,数组,函数

箭头函数其实没有this,这个函数中的 this 只取决于他外面的第一个不是箭头函数的函数的 this

function foo() {
	console.log(this.a)
}
var a = 1
foo()

var obj = {
	a: 2,
	foo: foo
}
obj.foo()

// 以上两者情况 `this` 只依赖于调用函数前的对象,优先级是第二个情况大于第一个情况

// 以下情况是优先级最高的,`this` 只会绑定在 `c` 上,不会被任何方式修改 `this` 指向
var c = new foo()
c.a = 3
console.log(c.a)

// 还有种就是利用 call,apply,bind 改变 this,这个优先级仅次于 new

6. 说一下new的原理

  • 生成一个新的对象
  • 链接到原型上
  • 绑定 this
  • 返回一个新的对象
// 实现 new 
function create(Con, ...args){
  let obj = {} //生成新对象
  obj.__proto__ = Con.prototype //链接原型
  let res = Con.apply(obj,args)
  return res instanceof Object ? res : obj //确保返回的是对象
}

7. 闭包

闭包的定义很简单:函数 A 返回了一个函数 B,并且函数 B 中使用了函数 A 的变量,函数 B 就被称为闭包。

function A() {
  let a = 1
  function B() {
      console.log(a)
  }
  return B
}

经典面试题

for ( var i=1; i<=5; i++) {
	setTimeout( function timer() { // setTimeout是异步 进入队列等待同步任务执行结束
		console.log( i );
	}, i*1000 );
}
// 第一种解决方法  闭包
for (var i = 1; i <= 5; i++) {
  (function(j) {
    setTimeout(function timer() {
      console.log(j);
    }, j * 1000);
  })(i);
}
// 第二种解决方法 let 形成块级作用域
for ( let i=1; i<=5; i++) {
	setTimeout( function timer() { 
		console.log( i );
	}, i*1000 );
} 
// 相当于 
{ // 形成块级作用域
  let i = 0
  {
    let is = i
    setTimeout( function timer() {
        console.log( i );
    }, i*1000 );
  }
  i++
  {
    let ii = i
  }
  i++
  {
    let ii = i
  }
  ...
}

8. 深浅拷贝

  • 浅拷贝

第一种可以通过 Object.assign来实现,第二种可以通过扩展运算符 ( ... )

let a = {
  age:21
}
let b = Object.assign({},a) // 等同于 let b = {...a}
a.age = 18
console.log(b.age) // 1
  • 深拷贝

深拷贝主要解决引用地址相同的问题

// 第一种可以通过 JSON.parse(JSON.stringify(object))
// 该方法有局限性 不能解决嵌套的引用对象
let a = {
    age: 18,
    name:{
      first:'wysoka'
    }
}
let b = JSON.parse(JSON.stringify(a))
a.name.first = 'web'
console.log(b.name.first) // wysoka

// 第二种方法 自定义方法
function deepcopy(obj){
  let res = obj instanceof Array ? [] : {}
  for(const [k,v] of Object.entries(obj)){
    res[k] = typeof v == 'object' ? copy(v) : v
  }
  return res;
}

9. 防抖、节流

防抖:在一段时间内把最后一次的操作为准,在规定时间内,重复操作重新计时

// 通俗易懂版
function debounce(fn,time){
  var t = null;
  return function(){
    clearTimeout(t);
    t = setTimeout(fn,time);
  }
}

节流:好比国企单位到点就下班,在规定的时间内,到时间就输出,在浏览器当中的刷新频率60HZ相当于起到节流的作用

// 通俗易懂版
function throttle(callback,duration){
  var lasttime = 0;
  return function(){
    var now = new Date().getTime();
    if(now - lasttime > 1000){
      callback();
      lasttime = now;
    }
  }
}

10. 数组去重的几种方法

  • 利用 ES6 去重
function unique(arr){
  return Array.from(new Set(arr)) // 等同于 [...new Set(arr)]
}
  • 两层 for 循环
for (let i=0, len=arr.length; i<len; i++) {
    for (let j=i+1; j<len; j++) {
       if (arr[i] == arr[j]) {
         arr.splice(j, 1);
         len--;
         j--;
       }
     }
  }
  • indexOf / includes
function removal(a,b){
  let arr = a.concat(b);
  return arr.filter((item,index)=>{
    //return arr.indexOf(item) === index
    //return arr.includes(item)
  })
}

11. 事件触发分为三个阶段

  • 捕获阶段、处于目标阶段、冒泡阶段
  • 冒泡型事件:当你使用事件冒泡时,子级元素先触发,父级元素后触发 stopPropagation()
  • 捕获型事件:当你使用事件捕获时,父级元素先触发,子级元素后触发 preventDefault()
  • DOM事件流:同时支持两种事件模型:捕获型事件和冒泡型事件

🏆 掘金技术征文|双节特别篇