看文章前请先看这里!!第一次在CSDN发布自己的内容,排版不好请多包含!希望用两句话说明白的问题不多讲废话,努力做到写的都是干货,让每一个看的人不浪费时间,同时也让和我一样的小白能看懂!每一次写都是很用心的写!
今天复习一下有关数据类型的内容
在JavaScript中有两种数据类型,分为基本数据类型和引用数据类型:
基本数据类型中包括:String,Number,Undefined,Null,Boolean,Symbol
引用数据类型中包括:Object,Funtion,Array,Error,Set,Map等等…
两者主要区别在于:
基本数据类型存储的是值,引用数据类型中存储的是地址。当创建一个引用类型的时候,计算机会在内存中帮我们开辟一个空间存放,这个空间有一个地址。
常用判断数据类型的方法有四种:typeof,instanceof,constructor,Object.prototype.toString.call()
typeof:可以对基本数据类型(除Null)做出准确判断,对于引用类型(除Function)都无法做出准确判断,返回均为Object,因为所有对象的原型链最终都指向了Object。
typeof返回一个表示数据类型的字符串,返回结果包括了:number,boolean,string,object,function,undefined,symbol七种数据类型。
typeof null返回的是Object,typeof function返回 function
instanceof运算符用于检测构造函数的prototype属性是否出现于某个实例对象的原型链上。 ——MDN
代码如下(示例):
var str = '放牛大户'
console.log(str instanceof String) // false
var bool = true
console.log(bool instanceof Boolean) // false
var num = 123
console.log(num instanceof Boolean) // false
var nul = null
console.log(nul instanceof Object) // false
var und = undefined
console.log(und instanceof Object) // false
// 从上面的运行结果来看,基本数据类型是没办法检测出来的
// 但是通过构造函数创建的基本数据类型是可以检测出来的,看下面代码
var num = new Number(123)
console.log(num instanceof Number) // true
var str = new String('abc')
console.log(str instanceof String) // true
var boolean = new Boolean(true)
console.log(boolean instanceof Boolean) // true
// 剩下的自己试一下,通过构造函数创建的基本数据类型是可以检测出来的
// 对于引用类型也是可以检测出来的
var oDate = new Date();
console.log(oDate instanceof Date) // true
var json = {
};
console.log(json instanceof Object) // true
var arr = [];
console.log(arr instanceof Array) // true
var reg = /a/;
console.log(reg instanceof RegExp) // true
var fun = function(){
};
console.log(fun instanceof Function) // true
var error = new Error();
console.log(error instanceof Error) // true
这里有人说instanceof无法判断基本数据类型,根据定义我理解的是只要是通过构造函数创建的,无论是基本数据类型还是引用数据类型都是可以检测出的,欢迎打脸!
constructor:查看对象对应的构造函数
这种方式可以判断(除null和undefined之外)所有数据类型。因为undefined和null是无效对象,没有constructor存在。
代码如下(示例):
// 这里就不都一一列举啦!
var str = '放牛大户'
console.log(str.constructor == String) // true
var bool = true
console.log(boor.constructor ==Boolean) // true
var arr = [];
console.log(arr.constructor == Array) //true
var fun = function() {
};
console.log(fun.constructor == Function) //true
// 下面这两个会报错哦!
// var nul = null;
// console.log(nul.constructor == Object) //报错
//var und = undefined;
//console.log(und.constructor == Object) //报错
constructor是不保险的,因为constructor属性是可以被修改的,会导致检测出的结果不正确
function A() {
}
function B() {
}
// 这里我们声明两个构造函数
A.prototype.constructor = B
// 修改一下A构造函数的指向
console.log(A.constructor == A) // false
Object.prototype.toString.call():该方法是通过子类在内部借用Object中提供的toString()方法,默认返回其调用者的具体类型。
格式为[object xxx],xxx是具体的数据类型。
代码如下(示例):
var str = '放牛大户';
console.log(Object.prototype.toString.call(str));//[object String]
var bool = true;
console.log(Object.prototype.toString.call(bool))//[object Boolean]
var num = 123;
console.log(Object.prototype.toString.call(num));//[object Number]
var nul = null;
console.log(Object.prototype.toString.call(nul));//[object Null]
var und = undefined;
console.log(Object.prototype.toString.call(und));//[object Undefined]
var oDate = new Date();
console.log(Object.prototype.toString.call(oDate));//[object Date]
var json = {
};
console.log(Object.prototype.toString.call(json));//[object Object]
var arr = [];
console.log(Object.prototype.toString.call(arr));//[object Array]
var reg = /a/;
console.log(Object.prototype.toString.call(reg));//[object RegExp]
var fun = function(){
};
console.log(Object.prototype.toString.call(fun));//[object Function]
var error = new Error();
console.log(Object.prototype.toString.call(error));//[object Error]
我想上面那部分内容对你来说都是开胃菜了,铺垫完基本数据类型和引用数据类型,今天的最重要的部分要来了!深浅拷贝冲呀!!!你点目录跳到这里会不会看不到我这部分内容,我想和你互动一下
在介绍基本数据类型和引用数据类型的区别时说,基本数据类型是按值访问的,当变量复制基本类型后,这两个变量是完全独立的。即使修改第一个变量,也不会影响到第二个变量!!(不信你试一下?要不我写段代码吧)
代码如下(示例):
var str1 = 'a'
var str2 = str1
str2 = 'b'
console.log(str1) // a
console.log(str2) // b
但对于引用数据类型,当变量复制引用类型后,和基本类型一样的是都将变量值复制到新的变量上。但是它是一个指针,指向存储在堆内存中的对象,这里我上个图看一下。
这图好不容易找到的呢,没办法谁叫我不会画呢,先谢谢原博主了,因为我没经过人家同意用的!!
浅拷贝:创建一个新的对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。即默认拷贝构造函数只是对对象进行浅拷贝复制,只复制资源而不复制空间——百度百科
1.Object.assign(target,…sources):第一个参数是拷贝目标,剩下的参数是拷贝的源对象。返回值:拷贝目标
注意:
代码如下(示例):
const target = {
a: 1, b: 2 };
const source = {
b: 4, c: 5 };
const returnedTarget = Object.assign(target, source);
console.log(target);// expected output: Object { a: 1, b: 4, c: 5 }
console.log(returnedTarget);// expected output: Object { a: 1, b: 4, c: 5 }
Object.assign():这种方法实现了单层深拷贝,当对象只有一层属性是为深拷贝,对深层(对象中还有对象)还是浅拷贝
代码如下(示例):
let obj1 = {
a: 1,
b: {
c: {
d: 0 } }
};
let obj2 = Object.assign({
}, obj1)
let obj3 = JSON.parse(JSON.stringify(obj1)); // 这是深拷贝方法,在这里我们做一个对比
// 第一层都是深拷贝时,修改拷贝源对象也就是obj时,对其他两个对象并没有影响
obj1.a = 2;
console.log(obj1.a) //2
console.log(obj2.a) //1
console.log(obj3.a) //1
// 深层时为浅拷贝,再修改源对象时,对obj2产生了影响
obj1.b.c.d = 1;
console.log(obj1.b.c.d); //1
console.log(obj2.b.c.d); //1
console.log(obj3.b.c.d); //0
2.扩展运算符:利用扩展运算符可以在构造字面量对象时,进行克隆或属性拷贝。和Object.assign有着同样的问题,当对象只有一层是为深拷贝,如果对象中有对象的话为浅拷贝。
代码如下(示例):
var obj = {
a:1,b:{
c:1}}
var obj2 = {
...obj};
obj.a=2;
console.log(obj); //{a:2,b:{c:1}}
console.log(obj2); //{a:1,b:{c:1}}
obj.b.c = 2;
console.log(obj); //{a:2,b:{c:2}}
console.log(obj2); //{a:1,b:{c:2}}
深拷贝:将一个对象内存完整的拷贝一份出来,从内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象。
通过JSON.stringify() 和 JSON.parse()实现深拷贝
代码如下(示例):
var obj1 = {
a:1,
b:[1,2,3]
}
var str = JSON.stringify(obj1)
var obj2 = JSON.parse(str)
console.log(obj2) // {a:1,b:[1,2,3]}
obj1.a = 2
obbj1.b.push(4)
console.log(obj1) // {a:2,b:[1,2,3,4]}
console.log(obj2) // {a:1,b:[1,2,3]}
这里封装了一个deepClone函数。for in遍历传入参数的值,如果是引用类型,再次调用deepClone函数,并且传入第一次调用deepClone参数的值作为第二次调用deepClone的参数,如果不是引用类型直接复制。
代码如下(示例):
var obj1 = {
a:{
b:1
}
}
function deepClone(obj1){
// 在堆内存中创建一个新对象
var cloneObj = {
};
// 遍历参数的属性
for (var key in obj) {
// 判断属性类型是否为obj,如果是需要再次循环遍历该对象的属性
if(typeof obj[key] === 'object'){
cloneObj[key] = deepClone(obj[key])
}else{
cloneObj[key] = obj[key]
}
}
return cloneObj
}
今天所有的内容完事啦!如有帮助麻烦鼓励一下哦!