JavaScript 数据类型
1.基本类型
- 字符串,数字,布尔类型都是基本类型,他们的值存放在栈区,值是静态的且相互独立的。
// 字符串类型
var a = 'hello'
var b = a
console.log(a,b) // hello hello
a = 'xxx' // 修改a的值不会影响b
console.log(a,b) // xxx hello
// 数字类型
var a = 10
var b = a
console.log(a,b) // 10 10
a = 20 // 修改a的值不会影响b
console.log(a,b) // 20 10
// 函数传参
var a = 10
function revise(n){
n = n*2 //修改函数内参数的值不会影响到外面的参数
console.log(n)
}
revise(a) // 20
console.log(a) // 10
<script>
var obj = {
n:30,
m:40
};
a = obj.n; //从对象中取值
console.log(a); //30
obj.n = 50; //修改对象的属性值
console.log(a); //30 不受影响
var arr = [1,2,3];
var b = arr[1]; //从数组中取值
console.log(b); //2
arr[1] = 20;
console.log(b); //2 不受影响
</script>
2.引用类型
- 数组和对象都属于引用类型:他们的值实际上是一个指针,指向(引用)一个数组或者对象,把数组和对象赋值给别人相当于把指针地址传递给别人,即2人共享一个数据,此时修改任意一个变量,另一个变量就会受到影响。
var a = [1,2,3];
var b = a;
console.log(a,b); // [1, 2, 3] [1, 2, 3]
a[0] = 9; // 通过a修改数组的第一个元素,b也会受到影响
console.log(a[0], b[0]); // 9 9
var p = {name: '亚索',age: 20};
var p2 = p;
p.name = '托儿索';
console.log(p.name, p2.name); // 托儿索 托儿索
- 函数传参:函数参数传递的是数组或者元素的指针,在函数内部操作形参实际上操作的就是实参本身
var a = [1,2,3]
function revise(arr){
arr[0] = arr[0] * 5
console.log(arr[0])
}
revise(a) // 5
console.log(a[0]) // 5
var p = {name: '亚索',age: 20}
function revise(obj){
obj.name = '托儿索'
console.log(obj.name)
}
revise(p) // 托儿索
console.log(p.name) // 托儿索
3.个人扩展
- 一个数据在进行赋值时,如果他的值属于简单数据类型,就属于静态赋值,这个数据是独享的,例如:
//对变量赋值
<script>
var obj = {
n:10,
}
var a = 20
var b = obj.n //数据来源于对象属性
var c = a //数据来源于简单数据类型-数字类型
console.log(b,c) //10,20
//修改数据源
obj.n = 1
a = 2
console.log(b,c) //10,20 不受影响
</script>
//对属性赋值
<script>
var obj = {
n:10,
}
var a = 20
var obj2 = {}
obj2.b = obj.n //数据来源于对象属性
obj2.c = a //数据来源于简单数据类型-数字类型
console.log(obj2.b,obj2.c) //10,20
//修改数据源
obj.n = 1
a = 2
console.log(obj2.b,obj2.c) //10,20 不受影响
</script>
- 一个数据在进行赋值时,如果他的值属于引用数据类型,就属于动态赋值,这个数据是共享的,例如:
<script>
//数据源
var person = {
age:20
}
//赋值操作
var person2 = person
var life = {}
life.person = person
//修改数据源
person.age = 30
//打印结果 数值随之改变
console.log(person2) //{age: 30}
console.log(life.person) //{age: 30}
</script>
4.动态取值
- 数据可以代理的形式管理,这个时候他的值是动态的,通俗的说,就是通过方法动态计算而来,例如MVVM数据代理。
<script>
//将data中的所有属性挂在到vm中
var data = {
name:'kyo',
age:20
}
function MVVM(data){
this._data = data //这里属于动态赋值,因为data是引用类型
//遍历所有的属性
Object.keys(data).forEach(key => {
//为vm添加与key相同属性,且配置相应的属性描述符
Object.defineProperty(this,key,{
//this为vm实例
configurable: false,//可重新定义
enumerable: true,//可枚举
get(){
return this._data[key]
},
set (newVlue) {
this._data[key] = newVlue
}
})
})
}
var vm = new MVVM(data)
console.log(vm.name,vm.age) //kyo 20
//修改数据源
data.name = 'joe'
data.age = 24
//通过数据代理,vm.name/vm.age与全局变量data进行了关联,能相互影响
console.log(vm.name,vm.age) //joe 24 数据受到影响
</script>
- 说到MVVM,就少不了Vue,在vue中配置data时,以下写法是错误的:(vue进行数据代理时,需要对原data进行缓存处理,当遍历其中的字段时,就让其指向原data的同名字段,当执行到vm.b = data.b = this.a,因为this代表window,并不是代表原data,所以无法得到预想的值,即vm.b = data.b = this.a = window.a = undefined)
<script>
var vm = new Vue({
el:'#app',
data:{
a:1,
b:this.a
},
mounted(){
console.log(this.b) //undefined
}
})
console.log(vm.b) //undefined
</script>
5.数据类型的判断
-
控制台直接打印数据时黑色的是字符串,蓝色的是数字或者布尔值,灰色的是null或者undefined
-
typeof将数据类型当作字符串返回,这种方法简单直接,但是 null/数组/对象 输出的结果都是object,无法区分
<script>
console.log(typeof "hello world") // string
console.log(typeof 123) // number
console.log(typeof true) // boolean
console.log(typeof null) // object
console.log(typeof undefined) // undefined
console.log(typeof []) // object
console.log(typeof {}) // object
console.log(typeof fn) // function
function fn(){}
</script>
- instanceof 判断一个变量是否是某个对象的实例:不止检查父类,检查所有祖先类(只能用于对象,不适用原始类型的值)
//数组类是对象类的子类
console.log(Array instanceof Object) // true
//数组及是数组实例,也是对象实例
console.log([] instanceof Array) // true
console.log([] instanceof Object) // true
//对象不是数组产生的实例
console.log({} instanceof Array) // false
console.log({} instanceof Object) // true
//只能用于对象,不适用原始类型的值
console.log("hello" instanceof String) //false
- constructor属性返回他的构造函数
console.log({}.constructor.toString()) //function Object() { [native code] }
console.log([].constructor.toString()) // function Array() { [native code] }
- toString() 判断数据类型(每个数据类型都重写了toString方法,所以使用call强制调用Object上面的toString来输出结果)
Object.prototype.toString.call(2) // "[object Number]"
Object.prototype.toString.call('') // "[object String]"
Object.prototype.toString.call(true) // "[object Boolean]"
Object.prototype.toString.call(undefined) // "[object Undefined]"
Object.prototype.toString.call(null) // "[object Null]"
Object.prototype.toString.call(Math) // "[object Math]"
Object.prototype.toString.call({}) // "[object Object]"
Object.prototype.toString.call([]) // "[object Array]"
- Array.isArray(要判断的数组)来判断是否为数组
//传入一个数组
console.log(Array.isArray([])) //true
//传入一个对象
console.log(Array.isArray({})) //false
- 封装一个判断数据类型的函数
<script>
function dataType(val){
var type = (typeof val).toLowerCase()
// 判断typeof是否输出'object'
if(type !== 'object'){
// 不是的话直接返回结果
return type
}
// 判断数据是否为null
if(val === null){
return null
}
// 区分数组与对象
if(val instanceof Array){
return 'array'
}else if(val instanceof Object){
return 'object'
}
}
console.log(dataType('hello world')) // string
console.log(dataType(123)) // number
console.log(dataType(true)) // boolean
console.log(dataType(null)) // null
console.log(dataType(undefined)) // undefined
console.log(dataType([])) // array
console.log(dataType({})) // object
console.log(dataType(fn)) // function
function fn(){}
</script>
6.数据类型转换
- 对象,数组转字符串 JSON.stringify(val)
var person = {name: 'kyo'}
console.log(JSON.stringify(person)) //'{"name":"kyo"}'
console.log(person.toString()) //'[object Object]'
var arr = [1, 2, 3, {name: 'kyo'}]
console.log(JSON.stringify(arr)) //[1,2,3,{"name":"kyo"}]
console.log(arr.toString()) //1,2,3,[object Object]
- JSON字符串转对象或数组 JSON.parse(val),这个方法作用与JSON.stringify(val) 相反
<script>
var arrStr = "[1, 2, 3, 4]"
var personStr = '{"name": "kyo"}'
var arr = JSON.parse(arrStr)
var person = JSON.parse(personStr)
console.log(arr) // [1, 2, 3, 4]
console.log(person) // {name: "kyo"}
</script>
- 字符串强制转换成数字
方法名 | 说明 |
---|---|
Number(val) | 将参数转换10进制后返回,转换失败直接返回NaN |
parseInt(val) | 将参数转换10进制后返回,整型,对参数字符逐个转换,遇到非数字字符则终止转换,可以指定参数的进制类型,默认10进制 |
parseFloat(val) | 将参数转换10进制后返回,浮点型,转换规则同parseInt |
isNaN(val) | 检查其参数是否是非数字值NaN,返回true/false |
isFinite(val) | 返回一个布尔值,表示某个值是否为正常的数值,除了Infinity、-Infinity、NaN和undefined这几个值会返回false,isFinite对于其他的数值都会返回true |
console.log(Number('12')) //12
console.log(Number('02')) //2
console.log(Number('12a')) //NaN
console.log(Number(true)) //1
console.log(Number(false)) //0
console.log(Number(null)) //0
console.log(Number('')) //0
console.log(Number(undefined)) //NaN
console.log('12.2') //12.2
console.log('OxF') //15
console.log(parseInt('12')) //12
console.log(parseInt('12a')) //12
console.log(parseInt('1a2')) //1
console.log(parseInt('a12')) //NaN
console.log(parseInt(true)) //NaN
console.log(parseInt(false)) //NaN
console.log(parseInt('')) //NaN
console.log(parseInt(null)) //NaN
console.log(parseInt(undefined)) //NaN
console.log(parseInt("12.2")) //12 忽略小数点
console.log(parseInt("12.8")) //12 忽略小数点
//以16进制形式解析字符串
console.log(parseInt('10',16)) //16
console.log(parseFloat("12.2")) //12.2
<script>
console.log(parseInt(null)) //NaN
var result = isNaN(parseInt(null))
console.log(result) //true
</script>
- 数字转字符串 每三位加逗号
var num = 1234567
console.log(num.toLocaleString()) //1,234,567
- 运算时的自动转换:对于减乘除:要计算的数据一律转换为数字类型(使用Number()规则转换),不能转为数字类型的就为NaN,一旦有一个数据是NaN,则结果必然是 NaN
console.log('4' * '2') //8
console.log('4' * '2a') //NaN '2a'转换为/NaN
console.log('4' * '2.2') //8.8
console.log('4' * '2.2a') //NaN '2.2a'转换为/NaN
console.log('4' * null) //0
console.log('4' * '') //0
console.log('4' * true) //4
console.log('4' * false) //0
console.log('4' * undefined) //NaN
- "+"运算符:如果有一个是字符串类型,则其余数据转化为字符串类型进行拼接
console.log('4' + '2') //'42'
console.log('4' + 2) //'42'
console.log('4' + null) //4null
console.log('4' + true) //4true
console.log('4' + false) //4false
console.log('4' + undefined) //4undefined
- "+"运算符:如果参与运算的没有字符串,则全部转为数字类型在做加法运算
console.log(4 + null) //4
console.log(4 + true) //5
console.log(4 + false) //4
console.log(4 + undefined) //NaN
console.log(true + false) //1
console.log(true + true) //2
console.log(false + false) //0
console.log(null + null) //0
console.log(undefined + undefined) //NaN
7.浅拷贝和深拷贝
- 浅拷贝就是对数组,对象这种引种类型的数据进行赋值时,将另一个数组或者对象的指针地址赋值给他,最终他们指向同一个数据,数据一旦修改就会影响到他们,例如
<script>
var obj = {a:1, b:2}
var obj2 = obj
console.log(obj2) //{a:1, b:2}
obj.a = 10
console.log(obj2) //{a:10, b:2}
</script>
- 深拷贝就是将数组或者对象中所有的元素/属性赋值给一个新的对象,且不影响当前数据,并把这个新的对象返回给左边的变量,他有2种方式:
//使用扩展操作符进对象进行解构
<script>
var obj = {a:1, b:2}
var obj2 ={...obj}
console.log(obj2) //{a:1, b:2}
obj.a = 10
console.log(obj2) //{a:1, b:2}
</script>
//使用JSON的相关方法将数组或对象转换为json字符串,再转换回去
<script>
var obj = {a:1, b:2}
var obj2 = JSON.parse(JSON.stringify(obj))
console.log(obj2) //{a:1, b:2}
obj.a = 10
console.log(obj2) //{a:1, b:2}
</script>