JS的数据类型
八大类型
Number String Boolean Null Undefined Symbol BigInt Object
Object中又包含了数组、对象、函数等。
Symbol
Symbol是es6中的新的数据类型,它的特点是没有重复的数据,但因为它的构造函数不够完整,所以不能用new Symbol来创建数据,要用Symbol()创建数据。
它的值是独一无二的,所以可以用作对象的唯一标识。
具体使用
const s1 = Symbol()
const s2 = Symbol('cba') //我们也可以在创建Symbol值的时候传入一个描述description
const obj = {}
//写法一: 属性名赋值
obj[s1] = "abc"
obj[s2] = "cba"
console.log(obj) //{ [Symbol()]: 'abc', [Symbol(cba)]: 'cba' }
BigInt
BigInt也是ES6新出的一种数据类型,这种数据类型的特点就是数据涵盖的范围大,能够解决超出普通数据类型范围报错的问题。
注意:BigInt和Number之间不能进行混合操作
具体使用
const a = BigInt(111)
console.log(a) //111n,就是在数字后面加了n,就是BigInt类型了
null和undefined的区别
- null是指空对象,是指将一个变量赋值为了空对象
- undefined是指一个变量声明了,但还没有赋值,那么它的初始值就是undefined;如果一个函数没有返回值,那么默认的返回值也是undefined
两大类
- 其中前七种属于基本数据类型,也叫做简单数据类型;而最后一种数据类型属于引用数据类型,也叫做复杂数据类型。
- 基本数据类型和引用数据类型的区别在于:两者在内存中的存储方式是不一样的,因为前者的占用空间比较少,前者的数值是存放在栈中的;而后者的占用空间比较大,后者的数值存放在堆中,在栈中存放了指针,该指针指向堆中实体值的起始地址,当解释器寻找引用值时,会在栈中找到对应的指针,从而找到堆中对应的值。
- 因为这两者的区别,因而在对值进行拷贝时,效果是不同的,这就有了深拷贝和浅拷贝的概念。
深拷贝浅拷贝
所谓拷贝,就是将一个变量的值赋值给另一个变量,因为基本数据类型和引用数据类型在内存存储上的方式不同,所以在拷贝上也有比较大的区别。
- 对于基本数据类型来说,赋值就是在栈中新开一个空间,然后把原来的值存进去,因而是不存在深拷贝和浅拷贝的概念的。
- 但对于引用数据类型来说,如果是直接赋值,那么则是浅拷贝,则是在栈中新开一个空间,然后把原来的值的指针存进去,也就是说新的变量和旧的变量引用的都是堆中同一块实体值;如果是深拷贝,则是在栈中新开一个空间,堆中也会新开一个空间,然后把实体值放进堆中,然后将堆中新的值的指针存进栈中。如果在开发的时候不理清这个概念而直接赋值,可能会导致未知的bug发生,但你却毫无解决的头绪QAQ
下面进入正题,那么,深拷贝和浅拷贝的方法有哪些呢?
浅拷贝
- 直接用=赋值
深拷贝方法
- JSON.parse(JSON.stringify(obj))
- 数组的slice()方法
- 数组的concat()方法
- 手写一个递归拷贝函数
function clone(buf) {
var res;
if (buf instanceof Array) {
res = [];
for (let i = 0; i < buf.length; i++) {
res[i] = clone(buf[i]);
}
return res;
} else if (buf instanceof Object) {
res = {};
for (const i in buf) {
res[i] = clone(buf[i]);
}
return res;
} else {
return buf;
}
}
判断变量类型的方法(4种)
typeof(根据底层数据存储的二进制判断)
可以解决大多数类型的判断,但也有一些判断不出来
var num=1
console.log(typeof num); //"number"
var str="1"
console.log(typeof str); //"string"
var bool=true;
console.log(typeof bool); //"boolean"
var und=undefined
console.log(typeof und); //undefined
var n=null;
console.log(typeof null); //object !判断不出来
var sym = Symbol()
console.log(typeof sym); //symbol
var big = BigInt(11)
console.log(typeof big); //bigint
var obj={};
console.log(typeof obj); //object
var fun=function(){};
console.log(typeof fun); //function
var arr=[];
console.log(typeof arr); //object !判断不出来
console.log(typeof Math); //object !判断不出来
console.log(typeof new RegExp()); // object !判断不出来
instanceof(根据原型链判断)
对于基本数据类型的判断都是不生效的,一般用于引用数据类型的判断,它的原理是通过对象的原型链来匹配,就是去找instanceof左边的对象的原型链上是否有instanceof右边的类,如果有则返回true,否则返回false
var obj={};
console.log(obj instanceof Object); //true
var arr=[];
console.log(arr instanceof Array); //true
// 父类名字Parent
class Parent {
constructor(name, age) {
this.name = name
this.age = age
}
running () {
console.log(this.name + ' 在跑步~')
}
}
// 使用关键字创建子类Son继承父类
class Son extends Parent {
}
const son = new Son('Jee', 20)
console.log(son instanceof Parent); //true
Object.prototype.toString.call()
用顶级对象Object的toString方法来找,缺点是无法判断undefined类型
var n=null;
console.log(Object.prototype.toString.call(n)); //[object Null]
var bool=true;
console.log(Object.prototype.toString.call(bool)); //[object Boolean]
var num=1
console.log(Object.prototype.toString.call(num)); //[object Number]
var str="1"
console.log(Object.prototype.toString.call(str)); //[object String]
var obj={};
console.log(Object.prototype.toString.call(obj)); //[object Object]
var fun=function(){};
console.log(Object.prototype.toString.call(fun)); //[object Function]
var arr=[];
console.log(Object.prototype.toString.call(arr)); //[object Array]
console.log(Object.prototype.toString.call(Math)); //[object Math]
console.log(Object.prototype.toString.call(new RegExp())); // [object RegExp]
constructor(根据构造器判断)
对于基本数据类型的判断都是不生效的,一般用于引用数据类型的判断,当创建一个对象时js会在该对象的原型链prototype属性上添加构造器,该构造器同时又指向了自身
var arr = new Array().constructor
console.log(arr == Array) //true