JS数据类型相关的知识

128 阅读5分钟

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