1,Js数据类型分为基本数据类型和引用数据类型
基本数据类型:number string undefined null boolean symbol 存放在栈中
引用数据类型:object array function 值存储在堆中
基本数据类型有固定大小和值,所以存在栈中,
引用数据类型不确定大小,会把指针存在栈中,指向堆内存中的地址
2,判断数据类型的方法
下面是几种常用的方法:
- typeof(),用来判断基本数据类型,判断引用数据类型时,但是判断不出来array与object的区别
用法:
typeof '123' // string
typeof 1 // number
typeof true // boolean
var a = "1234"
let arr =[1,2,3,4,5,{name:123}]
console.log(typeof(a))
console.log(typeof(arr));
- Instanceof,就可以区分出来对象和数据,主要的目的是用来检测引用类型
无法判断基本数据类型
用法:
console.log(toString.call(123)); //[object Number]
console.log(toString.call('123')); //[object String]
console.log(toString.call(undefined)); //[object Undefined]
//返回的是布尔值 true/false
var arr = [1, 2, 3]
var obj = {
name: "张三"
}
console.log(arr instanceof Object);
let data=[1,2,3,4,5,{name:123}]
console.log(data instanceof Array);
- Constructor,浏览器会在prototype原型上添加一个constructor属性,也就是prototype对象上的属性, 指向构造函数。根据实例对象去寻找属性,找不到就去原型链上找,实例对象也是能使用constructor属性的。
用法:
let data=[1,2,3,4,5,{name:123}]
console.log(data.constuctor == Object);
//返回的也是布尔类型
注意:不能用于判断 undefined 与 null 因为它们没有构造函数
- object.prototype.toString.call(),是判断数据类型最准确的方法
用法:
var arr = [1, 2, 3]
console.log(Object.prototype.toString.call(arr))
Object.prototype.toString.call([]) ; // [object Array]
Object.prototype.toString.call(new RegExp()) ; // [object RegExp]
Object.prototype.toString.call(new Error()) ; // [object Error]
toString是Object原型对象上的一个方法,该方法默认返回其调用者的具体类型,所有对象的原型链最终都指向了Object。
- jquery中的$.type()方法,能够返回更准确的对象类型,使用$.type 将更加方便。
用法:
jQuery.type(true) === "boolean"
jQuery.type(3) === "number"
jQuery.type("test") === "string"
3,深拷贝与浅拷贝的区别
我们上面说完 js 的数据类型了,现在我们就来了解一下数据深拷贝与浅拷贝
当拷贝的数据类型都是基本数据类型时,直接复制就行了,所以一般不会有什么区别
但是当拷贝的对象变为引用数据类型时就会出现区别
浅拷贝
浅拷贝是会将对象的每个属性进行依次复制,但是当对象的属性值是引用类型时,实质复制的是其引用,当引用指向的值改变时也会跟着变化。复制基本类型的属性;引用类型的属性复制,复制栈中的变量 和 变量指向堆内存中的对象的指针,不复制堆内存中的对象。
例如:
let arr =[1,2,3,4,5,{name:123}]
let newarr = arr
arr[3]="李白"
console.log(arr, newarr)
//会发现两个数据里面的值都改变了,
//所以浅拷贝只是复制了指针,而没有另外开辟空间来复制属性值
深拷贝
拷贝对象的具体内容,内存地址是自主分配的,拷贝结束之后俩个对象虽然存的值是一样的,但是内存地址不一样,俩个对象页互相不影响,互不干涉。复制基本类型的属性;引用类型的属性复制,复制栈中的变量 和 变量指向堆内存中的对象的指针和堆内存中的对象 深拷贝复制变量值,对非基本类型的变量,递归至基本类型变量后在复制, 深拷贝的对象与原来的对象是互不影响的。
使用深拷贝的方法有:for…in、扩展运算符、递归
用法:
let arr =[1,2,3,4,5,{name:123}]
//扩展运算符:
let newarr = [...arr]
arr[arr.length-1].name="李白"
//这时候我们发现数据同样会改变, 所以一般会另一种方法
//将对非基本类型的变量,改变成基本类型变量后在复制:
let newarr = JSON.parse(JSON.stringify(arr))
//使用递归:
Object.prototype.clone= function (data){
if(typeof(data)=='object'){
// 判断data的数据类型来创建sum的类型
let sum = data instanceof Array?[]:{}
// console.log(sum);
for(var i in data){
// console.log(data[i]);
sum[i]=typeof(data[i])=='object'?clone(data[i]):data[i]
}
return sum
}else{
return data
}
}
let num = clone(arr)
console.log(num);
4,构造函数与原型的区别
首先创建一个构造函数,并用它new一个实例对象,在没有原型时每个实例对象调用构造函数中的方法时都要开辟新的内存----->每个实例调用的方法不是同一个方法。
在构造方法中(任何函数具有一个prototype属性)有一个prototype属性,这个属性指向一个原型对象---->对象里面默认有constructor属性,指向prototype对象所在函数
这个对象的所有属性和方法,都会被构造函数的实例继承。通过构造函数得到的实例对象内部有一个__proto__指针指向构造函数的 prototype。 proto---->非标准属性
1、任何函数都具有一个 prototype 属性,该属性是一个对象
2、构造函数的 prototype 对象默认都有一个 constructor 属性,指向 prototype 对象所在函数
3、通过构造函数得到的实例对象内部会包含一个指向构造函数的 prototype 对象的指针 proto
4、所有实例都直接或间接继承了原型对象的成员
原型概念:
JavaScript 的所有对象中都包含了一个 [proto] 内部属性,这个属性所对应的就是自身的原型
JavaScript 的函数对象,除了原型 [proto] 之外,还有 prototype 属性,
当函数对象作为构造函数创建实例时,该 prototype 属性值将被作为实例对象的原型 [proto]