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>
posted @ 2019-09-22 15:07  ---空白---  阅读(358)  评论(0编辑  收藏  举报