高效準備前端技術(shù)一面:JS 基礎(chǔ)知識面試題(一)
变量类型
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 ,因为他们指向相同的对象。但是,复制的对象中,ttt1 和 ttt2 分别指向了两个对象。拷贝的对象没有保持和原对象一样的结构。因此,JSON 实现深拷贝不能处理指向相同引用的情况,相同的引用会被重复拷贝
共同學(xué)習(xí),寫下你的評論
評論加載中...
作者其他優(yōu)質(zhì)文章