手记

高效准备前端技术一面:JS 基础知识面试题(一)

变量类型

typeof 和 instanceof 的区别?

typeof 对于string,boolean,number,undefined,function,symbol等类型可正确判断

对于null,array,object判断结果均为 object

特殊的对于 null,null 不是一个对象,尽管 typeof null 输出的是 object,这是一个历史遗留问题,JS最初为了性能使用低位存储变量的 类型信息 ,000 开头代表是对象,null 表示为全零,所以将它错误的判断为 object

instanceof 代码形式为*object instanceof constructor***object 是否是 constructor 的实例****),该操作符用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上(可用于判断引用类型)

何时使用 === 何时使用 ==

除了 == null 之外 其它地方一律用===

const obj = { a: 2 }
if (obj.b == null) {
  // 相当于 if(obj.b===null||obj.b===undefined)
  console.log('b')
}

原始值和引用值的区别

内存的分配不同

  • 原始值存储在栈中
  • 引用值存储在堆中,栈中存储的变量,是指向堆中的引用地址

访问机制不同

  • 原始值是按值访问
  • 引用值按引用访问,JavaScript 不允许直接访问保存在堆内存中的对象,在访问一个对象时,首先得到的是这个对象在堆内存中的地址,然后再按照这个地址去获得这个对象的值

复制变量时不同

  • 原始值:a=b;是将 b 中保存的原始值的副本赋值给新变量 a,a 和 b 完全独立,互不影响
  • 引用值:a=b;将 b 保存的对象内存的引用地址赋值给了新变量 a;a 和 b 指向了同一个堆内存地址,其中一个值发生了改变,另一个也会改变

比较变量时不同

  • 原始值:==比较值是否相等(先进行类型转换再确定操作数是否相等引自 js 高级程序设计(第四版) P71),===不仅比较值是否相等,还会比较数据类型是否相同

  • 引用数据类型:不管是 == 还是 === ,都是比较内存地址是否相同,即比较是否都指向同一个对象

参数传递的不同

函数传参都是按值传递(栈中的存储的内容):原始值,拷贝的是值;引用值,拷贝的是引用地址

手写深拷贝

仅仅是解决了深复制的关键问题,还需要针对不同的数据类型进行完善,lodash的深拷贝针对不同的数据类型进行了处理

function deepClone(obj = {}) {
  if (typeof obj !== 'object' || obj == null) {
    return obj
  }
  //    初始化返回结果
  let result
  if (obj instanceof Array) {
    // 判断为数组
    result = []
  } else {
    result = {}
  }
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      // 保证key不是原型的属性 for...in的问题
      result[key] = deepClone(obj[key])
    }
  }
  // 返回结果
  return result
}
function deepCopy(target) {
  let copyed_objs = [] //此数组解决了循环引用和相同引用的问题,它存放已经递归到的目标对象
  function _deepCopy(target) {
    if (typeof target !== 'object' || !target) {
      return target
    }
    for (let i = 0; i < copyed_objs.length; i++) {
      if (copyed_objs[i].target === target) copyed_objs[i].copyTarget
    }
    let obj = {}
    if (Array.isArray(target)) obj = [] //处理target是数组的情况
    copyed_objs.push({ target: target, copyTarget: obj })
    Object.keys(target).forEach(key => {
      obj[key] = _deepCopy(target[key])
    })
    return obj
  }
  return _deepCopy(target)
}

JSON.sringify 和 JSON.parse 方法拷贝的缺陷

这是 JS 实现深拷贝最简单的方法了,原理就是先将对象转换为字符串,再通过 JSON.parse 重新建立一个对象。 但是这种方法的局限也很多:

  • 不能复制 function、正则、Symbol
  • 循环引用(当对象 1 中的某个属性指向对象 2,对象 2 中的某个属性指向对象 1 就会出现循环引用)报错
  • 相同的引用会被重复拷贝
let obj = { asd: 'asd' }
let obj2 = { name: 'aaaaa' }
obj.ttt1 = obj2
obj.ttt2 = obj2
let cp = JSON.parse(JSON.stringify(obj))
obj.ttt1.name = 'change'
cp.ttt1.name = 'change'
console.log(obj, cp)

对于上面的代码,原对象改变 ttt1.name 也会改变 ttt2.name ,因为他们指向相同的对象。但是,复制的对象中,ttt1ttt2 分别指向了两个对象。拷贝的对象没有保持和原对象一样的结构。因此,JSON 实现深拷贝不能处理指向相同引用的情况,相同的引用会被重复拷贝

0人推荐
随时随地看视频
慕课网APP