一、typeof运算符能判断哪些类型
knowledge point:
1、识别所以值类型
let a typeof a //undefined
const str = 'abc' typeof str //string
const n = 100 typeof n //number
const b = true typeof b //boolean
const s = Symbol('s') typeof s //symbol
2、识别函数
typeof console.log //'function'
typeof function(){} //'function'
3、判断是否是引用类型(不可再细分,不知道是对象还是数组什么的)
typeof null //'object'
typeof ['a,'b'] //'object'
typeof {x:100} //'object'
二、何时使用=何时使用
knowledge point:
==会让左右两边尽可能的相等
answer:
只有在判断是否为null之外,其他的地方都用=
if(obj.a == null){}
//相当于:
//if(obj.a === null || obj.a === undefined)
三、值类型和引用类型的区别
knowledge point:
要明白值类型与引用类型的堆栈模型的区别
值类型:
let a = 100;
let b = a;
a = 200;
console.log(b);//100
常见的值类型:
let a //undefined 不可用const , const声明变量必须赋值
const str = 'abc' //string
const n = 100 //number
const b = true //boolean
const s = Symbol('s') //Symbol 类型,凡是属性名属于 Symbol 类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。
引用类型:(给a赋值一个对象,b再赋值a,之后b的改变a也会改变)
let a = { age :20 };
let b = a;
b.age = 21;
console.log(a.age);//21
常见的引用类型:
const obj = {x:100} //对象
const arr = ['a','b','c'] //数组
const n = null //null类型,特殊引用类型,指针指向空地址
function fn() {} //特殊引用类型,但不用于存储数据,所以没有“拷贝、复制函数”这一说法,可以单独拿出来当一个函数类型
different:
值类型:存储在栈中,无论是局部还是全局变量,当a改变时只改变了a的value而不会改变b的value
栈
key | value |
---|---|
a | 100 |
b | 100 |
引用类型:存储在栈(从下往上排列)中、堆(从上往下落)中,当b.age改变时,改变的是堆中的value{age:21},所以a也会改变
栈
key | value |
---|---|
a | 内存地址1 |
b | 内存地址1 |
堆
key | value |
---|---|
内存地址1 | {age:20} |
answer:
四、手写深拷贝
knowledge point:
深拷贝针对的是:对象或者数组
拷贝成功后,value值会发生变化,即指的堆中的地址不在是一个了
different:
answer:
const obj1 ={
age : 20,
name : 'xxx',
address : {
city : 'beijing'
},
arr : ['a','b','c']
}
const obj2 = deepClone(obj1)
const obj3 = obj1;
obj2.address.city = 'shenzhen'
obj2.arr[0] = 'a1'
console.log(obj1.address.city) //beijing
console.log(obj1.arr[0]) //a
obj3.arr[0] = 'a3'
console.log(obj1.arr[0]) //a3
/**
*深拷贝
*@param {Object} obj 要拷贝的对象
*/
function deepClone(obj = {}){
if(typeof obj !== 'object' ||obj == null){
//obj 不是null,或者不是数组和对象,直接返回
return obj
}
//初始化返回结果
let result
if (obj instanceof Array){
//判断obj是不是数组,用instanceof
result = []
}else{
result ={}
}
for (let key in obj){
//用foreach遍历
//保证key不是原型的属性
if(obj.hasOwnProperty(key)){
//递归调用
result[key] = deepClone(obj[key])
/*
整个for完就得到result ={age:20,name : 'xxx',address : { city : 'beijing'},arr : ['a','b','c']}
*/
}
}
return {}
}
上述递归是为了防止address里面的内容啊,即深层的东西没有办法复制到
当深拷贝成功后,则obj2 和 obj1 在栈中的value值已经不是同一个了,所以当obj2改变内容时,obj1不会发生变化
但是obj3和obj1是指的同一个对象,所以,当一个发生改变另一个也会发生改变
五、类型转换
knowledge point:
1. 字符串拼接
只要有字符串,则就是字符串拼接,而不是加法,除非把字符串强制转换成数字parseInt()
const a = 100 + 10 //110
const b = 100 + '10' //'10010'
const bb = 100 + parseInt('10') //110
const c = true + '10' //'true10'
2. ==
会发生类型转换,会让两者尽量转换成相等的,**++所以只有一个地方使用:判断是否为null, == null++**
其他地方都用===
100 == '100' //true
0 == '' //true
0 == false //true
false == '' //true
null == undefined //true
const obj = { x:100}
if(obj.a == null){}
//相当于:
//if(obj.a === null || obj.a === undefined)
3. if语句
此处也会发生类型转换
const n = 100
n //100
!n //false
!!n //true
const b = 0
b //0
!b //true
!!b //false
以下是falsely变量,除此之外都是truly变量
!!0 === false
!!NaN === false
!!'' === false
!!null === false
!!undefined === false
!!false === false
4.逻辑运算
console.log(10 && 0) //0
console.log(0 && 10) //0
//上面两者都返回0,是因为当碰到10时是true的,所以就会接下去判断0,而0是false则直接返回;而第二个在判断0的时候就是false了,直接返回,不再继续判断下去了
console.log(''||'abc') //'abc'
console.log('abc'||'') //'abc'
console.log(!window.abc) //true