js变量类型:值类型和引用类型
值类型:number
,string
,boolean
,undefined
,symbol
var a = 100
var b = a
a = 200
console.log(b)
引用类型:object
,function
var a = {age:20}
var b = a
b.age = 21
console.log(a.age)
其中,值类型直接保存在栈内存中,值都有固定的大小,保存在栈空间,通过按值访问。引用类型保存在堆内存中的对象,值大小不固定,栈内存中存放的该对象的访问地址指向堆内存中的对象。(为什么引用类型这样存储呢?因为引用类型的值会有很多属性,值太大的话放到栈中不好管理,直接复制值的话,会导致复制过程太慢。)这种机制是基于内存空间和CPU计算的耗时来区分的。
因为存储方式不同,所以有了深拷贝
和浅拷贝
的问题
如果是值类型,数据发生复制行为时,系统会自动给新的变量开辟一个新的空间,赋一个新的值,这些变量都相互独立,相互不影响
let a = 20;
let b = a;
b = 30;
console.log(a); // 20
如果是引用类型,数据发生复制行为时,同样会开辟一个新的空间,赋一个新的值,但这个所赋的值,是一个地址指针,这个复制的指针和被复制的指针指向同一个值
let a = { x: 10, y: 20 }
let b = a;
b.x = 5;
console.log(a.x); // 5
这种情况下,怎么办呢?如何实现深拷贝
呢?
方法一:(反序列化)使用JSON.parse()和JSON.stringify()对对象进行深拷贝 (真正的进行对象的深拷贝),该方法会忽略function和undefined的字段,对date类型支持貌似也不友好。而且只能克隆原始对象自身的值,不能克隆它继承的值
方法二:es6的扩展运算符...
var a = ['a', 'b', 'c'];
var b = [...a];
b.push(2)
console.log(b) //["a", "b", "c", 2]
console.log(a) //["a", "b", "c"]
let obj = {
name:'huahua',
sex:'girl'
}
let obj1= {...obj} //或者 let {...obj1}= obj
obj1.name="qq"
console.log(obj1) //{name: "huahua", sex: "girl"}
console.log(obj) //{name: "qq", sex: "girl"}
方法三:递归
function deepClone (obj={}) {
// 判断传入的obj不为空并且是object类型
if (obj == null || typeof obj !== "object") return
let res
if (obj instanceof Array){
res=[]
} else {
res={}
}
for (let key in obj) {
// hasOwnProperty确保key是自身的属性而不是原型上的属性
if (obj.hasOwnProperty(key)) {
res[key] = deepClone (obj[key])
}
}
return res
}
实现数组深拷贝:
1.slice
var a = ['a', 'b', 'c'];
var b = a.slice(0);
b.push(2)
console.log(b) //["a", "b", "c", 2]
console.log(a) //["a", "b", "c"]
2.concat
var a = ['a', 'b', 'c'];
var b = a.concat();
b.push(2)
console.log(b) //["a", "b", "c", 2]
console.log(a) //["a", "b", "c"]
所有的引用类型都可以自由的设置属性
var obj = {}
obj.a = 100
var arr = [1,2,3]
arr.a = 100 //(3) [1, 2, 3, a: 100]
function fn() {}
fn.a = 100
typeof可以判断这些类型,如下
console.log(typeof 123); // =>number
console.log(typeof "abc"); // =>string
console.log(typeof true); // =>boolean
console.log(typeof undefined); // =>undefined
console.log(typeof Symbol()); // =>symbol
console.log(typeof {}); // =>object
console.log(typeof []); // =>object
console.log(typeof null); // =>object 因为 null 也是引用类型
console.log(typeof console.log); // =>function
值类型的判断用typeof
,引用类型的判断用instanceof
js中常见内置函数:
Object
Array
Boolean
Number
String
Function
Date
RegExp
Error
那么,JSON又是什么呢?
其实,JSON是一种数据格式。从js角度来回答的话,JSON是一个对象,有parse
和stringify
两个方法
JSON.stringify({a:10, b:20}) //"{"a":10,"b":20}"
JSON.parse('{"a":10,"b":20}') //{a: 10, b: 20}
变量计算
简单的变量计算,就是数字的加减乘除、字符串的拼接和替换,这个太简单了,这里不提了。但是 JS 在值类型的运算过程中,特别需要注意和利用强制类型转换这一特性,有以下场景:
- 字符串拼接
==
- 逻辑运算(
if
!
||
&&
)
var a = 100 + 10 // 110
var b = 100 + '10' // '10010'
100 == '100' // true
0 == '' // true
null == undefined // true
console.log(10 && 0) // 0
console.log('' || 'abc') // 'abc'
console.log(!window.abc) // true
// 判断一个变量会被当做 true 还是 false
var a = 100
console.log(!!a)
何时使用===
何时使用==
首先,==
会先试图类型转换,然后再比较,而===
不会类型转换,直接比较。如下所示:
1 == '1' // true
1 === '1' // false
0 == false // true
0 === false // false
null == undefined // true
null === undefined // false
日常开发中,以下变量会被转换为false
- 0
- NaN
- ''
- null
- undefined
- false 本身
除了以上几个,其他的都会被转换为true
。除了if
之外,!
||
&&
这三个运算符也会进行同样的转换,跟if
是一个道理。
日常开发中,都使用===
,有一种情况用==
,就是判断是否存在的时候
if (obj.a == null) {
// 这里相当于 obj.a === null || obj.a === undefined ,简写形式
}
网友评论