JavaScript的数据类型分为基本类型和引用类型。
基本类型
基本类型包括undefined、null、string、number、boolean、(ES6中还有Symbol)
这些类型是存放在栈中的,数据大小确定,可按值访问,直接操作保存在变量中的实际值。
var a = 10;
var b = a;
b = 20;
console.log(a); // 10
console.log(b); // 20
复制时栈内存会开辟一个新内存来存放。按值传递,改变其中一个不会改变另一个,互相独立。
引用类型
引用类型就是Object(包括Array、RegExp、Date、function)
引用类型是存放在堆内存中的对象。
变量是保存在栈内存中的一个指针,这个指针保存的是堆内存中的引用地址,指向堆内存中的对象。
var obj1 = new Object();
var obj2 = obj1;
obj2.name = "名字";
console.log(obj1.name); //名字
按址传递,=只是将这个堆内存对象在栈内存中的地址复制了一份给obj2,但是它们指向了同一个堆内存对象,修改其中一个变量就是在修改另一个。
判断数据类型的方法
typeof
typeof可以得到以下几种类型:
number、string、boolean、object、function、undefined、symbol
typeof ''; // string 有效
typeof 1; // number 有效
typeof Symbol(); // symbol 有效
typeof true; //boolean 有效
typeof undefined; //undefined 有效
typeof null; //object 无效
typeof [] ; //object 无效
typeof new Function(); // function 有效
typeof new Date(); //object 无效
typeof new RegExp(); //object 无效
需要注意的是
typeof null; //object
而且除了function外无法具体区分其他的object
instanceof
用来判断A是否是B的实例,返回的是一个布尔值。
console.log([] instanceof Array); //true
console.log([] instanceof Object); //true
console.log(/^$/ instanceof RegExp); //true
需要注意的是
这种方式判断一个数组是否为数组或对象的结果都为true,所以可以用Array.isArray()来判断Array类型。
这种方式不可以用来检测基本类型
console.log(1 instanceof Number); //false
constructor
对象的constructor是指向其构造函数的。
console.log([].constructor === Array); //true
console.log([].constructor === Object); //false
console.log({}.constructor === Object); //true
console.log([].constructor === Object); //false
console.log(1.constructor === Number); //true
需要注意的是
null和undefined是没有constructor的,不能用这种方式判断。
toString()
这种方法是最万能的。
toString()是Object的原型方法,会返回当前对象的数据类型。通过call()使这个方法中的this指向需要检测的值。返回的格式为[object XX]
Object.prototype.toString.call('') ; // [object String]
Object.prototype.toString.call(1) ; // [object Number]
Object.prototype.toString.call(true) ; // [object Boolean]
Object.prototype.toString.call(Symbol()); //[object Symbol]
Object.prototype.toString.call(undefined) ; // [object Undefined]
Object.prototype.toString.call(null) ; // [object Null]
Object.prototype.toString.call(new Function()) ; // [object Function]
Object.prototype.toString.call(new Date()) ; // [object Date]
Object.prototype.toString.call([]) ; // [object Array]
Object.prototype.toString.call(new RegExp()) ; // [object RegExp]
Object.prototype.toString.call(new Error()) ; // [object Error]
Object.prototype.toString.call(document) ; // [object HTMLDocument]
Object.prototype.toString.call(window) ; //[object global] window 是全局对象 global 的引用
需要注意的是
toString()方法在每种类原型中都有,但是除了Object的原型,其他的都是把数据转换为字符串的意思。
浅拷贝
浅拷贝就是只复制指向某个对象的指针,而不复制对象本身,新旧对象共享同一块内存。
浅拷贝的实现方法
直接赋值
let a = 1;
let b = a;
b = 2;
console.log(a); //2
console.log(b); //2
Object.assign()
let obj = {name:'Carol', age:{child:12}}
let copy = Object.assign({},obj);
copy.name = 'Lee';
copy.age.child = 24;
console.log(obj);// {name:'Lee',age:{child:24}}
函数实现
function shallowClone (source){
if(!source || typeof source != 'object'){
throw new Error ('error');
}
var targetObj = source.constructor === Array ? [] : {};
for(var keys in source) {
if(source.hasOwnProperty(keys)){
targetObj[keys] = source[keys];
}
}
return targetObj;
}
深拷贝
复制并创建一个一模一样的对象,不共享内存,修改新对象,旧对象保持不变。
深拷贝的实现方式
函数实现
//使用循环遍历的方式实现数组、对象的深拷贝
function deepClone(obj) {
//判断拷贝的要进行深拷贝的是数组还是对象,是数组的话进行数组拷贝,对象的话进行对象拷贝
var objClone = Array.isArray(obj) ? [] : {};
//进行深拷贝的不能为空,并且是对象
if (obj && typeof obj === "object") {
for (key in obj) {
if (obj.hasOwnProperty(key)) {
if (obj[key] && typeof obj[key] === "object") {
objClone[key] = deepClone1(obj[key]);
} else {
objClone[key] = obj[key];
}
}
}
}
return objClone;
}
借用JSON的parse()和stringify()方法
//借用JSON对象的stringify把对象转为字符串,然后用parse转成新的对象
function deepClone(obj){
let _obj = JSON.stringify(obj),
let objClone = JSON.parse(_obj);
return objClone;
}
let a=[0,1,[2,3],4],
let b=deepClone(a);
a[0]=1;
a[2][0]=1;
console.log(a,b);