值类型与引用类型
值类型有Number,String,Boolean,Undefined, Symbol(es6)
引用类型有Object,Array,Function,Null
类型判断typeof能判断的类型
值类型都可以判断,但引用类型除function判断返回’function’外,其他都返回’object’。
这里function是特殊的引用类型,null也是(但是是早期遗留问题,反正知道它typeof是’object’就好
手写深拷贝
堆栈概念请百度。
随手画了一下,普通值变量在栈中存储的是值,这样互相也是赋予值,不存在深浅拷贝问题。但是引用类型变量在栈中存放的是堆中的值地址。譬如下面所示,a在栈中,存放堆中的值的地址,a就是C中指针的概念。如果这个引用类型中还有一个引用类型则也是指向一个堆地址的。这也就是为什么深拷贝需要递归了。
什么是浅拷贝?浅拷贝就是只传递了引用变量的地址,譬如将a的值给b,但你知道这个值实际是地址,那么b也指向了堆,b改变引用类型的属性会导致a的属性也改变(废话)
什么是深拷贝?当然就是a指向的这块地址,注意是块,在堆中开辟新空间,并放进去,从而达到深层次拷贝,不会互相影响的效果。
function deepClone(obj = {}) {
//接收到变量一定要注意判断类型,看是否是一个object,如果是object,
//还得看是不是null。这些情况都原样返回不存在深浅拷贝
if(typeof obj !== 'object' || obj == null) {
return obj
}
let result //开辟堆空间
if(obj instanceof Array) {
//通过instanceof判断是否为一个数组类型,是则给新开辟空间赋空数组
result = []
} else {
//不是数组类型,一律赋空对象
result = {}
}
for(let key in obj) {
if(obj.hasOwnProperty(key)) {
// 保证key不是从原型中获得的属性,这里使用递归,避免属性本身
// 也是引用类型,只有这样才是深拷贝
result[key] = deepClone(obj.key)
}
}
return result
}
let obj1 = {
name: "小明",
age: 16,
ismale: true,
address: {
city: 'Guiyang',
district: 'Baiyun'
}
}
let obj2 = deepClone(obj1)
obj2.address.city = 'Zunyi'
console.log(obj1.address.city) //Guiyang
//山美水美的贵州欢迎大家来旅游
😁
综上,深拷贝要注意三点
- 判断是否为引用类型,是引用类型则判断是否为null
- 判断开辟数组空间还是对象空间
- 使用Object.hasOwnproperty排除原型属性,并递归自己返回属性值。
变量计算(不知不觉的类型转换是个坑)
在JS的数据类型这一块,还需要注意遗留下来的各种各样类型转换的情况,因为在我们实际应用过程中,我们并不想发生类型转换。
字符串拼接
发生以下的类型转换是字符串的特性造成的。
const a = 100 + 10 //110
const b = 100 + '10' //'10010'
const c = true + 'true10'
==判断
100 == '100' //true
0 == '' //true
0 = false //true
false == '' //true
null == undefined //true
// == 在使用中总是会自动进行类型转换,这不是我们所期待的结果,所以除了==null的情况
//一律使用 ===
const obj = {x: 100}
if(obj.a == null) { }
//相当于
// if(obj.a === null || obj.a === undefined)
if语句与逻辑判断中的类型转换
truty vs falsy
如果一个值通过双非运算(!!value)可以被转换为 true,那么这个值就是所谓的 truthy,如果可以被转换为 false,那么这个值就是所谓的 falsy。
//以下为falsy变量,除此都是truthy变量
!!0 === false
!!NaN === false
!!'' === false
!!null === false
!!undefined === false
!!false === false
if语句中
逻辑判断
不是很懂这里的意思可以看逻辑运算符
(some true expression) && (expr) 计算expr返回expr的结果。
(some falsy expression) || (expr) 计算expr返回的结果。
(some falsy expression) && (expr) 短路计算的结果为假。
(some truthy expression) || (expr) 短路计算的结果为真。
(function() {return true})() && 1+3 //4
(function() {return false})() || 1+3 //4
(function() {return true})() || 1+3 //true
(function() {return false})() && 1+3 //false
//这样可以达到
var x = a || b || c
var x;
if(a){
x = a;
} else if(b){
x = b;
} else {
x = c;
}
x = a && b && c
var x = a;
if(a){
x = b;
if(b){
x = c;
}
}
的代码执行效果
综上,正确使用逻辑判断方式可以减少写if的代码量。
数据类型相关的面试题
typeof可以判断的基本类型?
何时使用==
何时使用===
手写深拷贝
这些面试题,你们这么聪明,肯定没问题。