JavaScript变量类型

496 阅读5分钟

数据类型

对外的,面对编译器

基本数据类型(值类型)

包括

  • Undefined
  • Null
  • Boolean
  • String
  • Number
  • Symbol(ES6) 存放位置:内存中的栈区域。

值的不可变性,称这些类型的值为原始值。

基本数据类型的值是按值访问的,基本类型的值是不可变的。

比较:基本数据类型的比较是值的比较,只判断是否相等。

拷贝:都是值的复制,相互没有影响。

引用数据类型(对象类型)

包括

  • Object
  • Array
  • Function
    • RegExp
  • Date 存放位置:内存中的栈存放指向堆区域的指针,内容在堆区域中

值的可变性:引用类型的值是按引用访问的,引用类型的值是动态可变的

比较:引用类型的比较是引用地址的比较,判断是否指向同一对象。

拷贝:

  • 赋值:仅改变引用的指针,指向同一个对象,相互影响
  • 浅拷贝:拷贝一层,不对对象的子对象进行拷贝,对第一层的基本类型的修改互不影响,对于子对象会相互影响。
  • 深拷贝:对对象中的子对象进行递归拷贝,拷贝前后的两个对象互不影响。

undefined 和 null 的区别?

undefined:是一个没有设置值的变量。JavaScript特有的。没有返回值的函数返回为undefined,没有实参的形参也是undefined。

null:它是一个空对象指针。

null 和 undefined 的值相等,但类型不等:

typeof undefined             // undefined
typeof null                  // object
null === undefined           // false
null == undefined            // true

基本数据类型和引用类型的数据结构

基本数据类型:数据存于内存中的栈区域。

应用数据类型:内存中的栈存放指向堆区域的指针,内容在堆区域中。

赋值、浅拷贝和深拷贝

如果是基本数据类型,直接赋值,会拷贝其本身,不存在浅拷贝和深拷贝。

如果是引用类型:

  • 赋值:仅改变引用的指针,指向同一个对象,相互影响
  • 浅拷贝:拷贝一层,不对对象的子对象进行拷贝,对第一层的基本类型的修改互不影响,对于子对象会相互影响。
  • 深拷贝:对对象中的子对象进行递归拷贝,拷贝前后的两个对象互不影响。

赋值

let obj1 = {
    color: 'red',
    age: 20,
    address: {
        city: 'beijing',
    },
    arr: ['a', 'b', 'c']
};
//赋值
let obj2 = obj1;
obj1.age = 21;
obj1.address.city = "shanghai";
console.log(obj2.age);//21
console.log(obj2.address.city);//shanghai

浅拷贝

let obj1 = {
    color: 'red',
    age: 20,
    address: {
        city: 'beijing',
    },
    arr: ['a', 'b', 'c']
};
//浅拷贝
let obj3 = shallowCopy(obj1);
obj1.age = 21;
obj1.address.city = "shanghai";
console.log(obj3.age); //20
console.log(obj3.address.city); //shanghai

//自定义浅拷贝函数
function shallowCopy(obj) {
    if (typeof obj !== 'object' || obj == null) {
        return obj;
    }
    let result;
    if (obj instanceof Array) {
        result = [];
    } else {
        result = {};
    }
    for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
            result[key] = obj[key];
        }
    }
    return result;
}

深拷贝

let obj1 = {
    color: 'red',
    age: 20,
    address: {
        city: 'beijing',
    },
    arr: ['a', 'b', 'c']
};
//深拷贝
let obj4 = deepCopy(obj1);
obj1.age = 21;
obj1.address.city = "shanghai";
console.log(obj4.age);//20
console.log(obj4.address.city);//shanghai

//自定义深拷贝函数
function deepCopy(obj) {
    // obj 是 null 或者不是对象和数组,直接返回
    if (typeof obj !== 'object' || obj == null) {
        return obj;
    }
    // 初始化返回结果
    let result;
    if (obj instanceof Array) {
        result = [];
    } else {
        result = {};
    }
    for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
            result[key] = deepCopy(obj[key]);
        }
    }
    return result;
}

本地对象

对内的,供开发者使用

  • 包装类型对象 Boolean String Number

  • 引用类型 Array Function Date Object RegExp Error

  • 内置对象

在脚本程序初始化时被创建,不必实例化这两个对象。

Global Math

基本包装类型

在实际中每读取一个基本数据值的时候,后台就会创建一个对应的基本包装类型对象,从而让我们能够调用一些方法操作这些数据。

let s1 = "some text"; //值类型没有方法。
let s2 = s1.substring(2);
console.log(s1); //some text
console.log(s2); //me text

引用类型与基本包装类型的区别

它们的对象生命周期不同:

引用类型:使用new创建引用类型的实例,在执行数据流离开当前作用域时会一直存储在内存中。

基本包装类型:自动创建基本包装类型的对象,只执行一行代码的瞬间之后就会立即销毁。

这意味着在运行时为基本包装类型值添加属性和方法是无效的。

let s1 = 'some text';
s1.color = 'red';
s1.color // undefined

// 但是这样是可以的
let s1 = new String('some text');
s1.color = 'red';
s1.color // red

不建议显式的创建基本包装类型的对象,因为在很多时候会造成一些让人很迷惑的东西。

let b = new Boolean(false); //b 这个变量就是 Boolean 对象
let c = b && true;
console.log(c); // true
let str = 'hello'; // str 本质上是一个原始值,并不存在 prototype 属性
console.log(typeof str); // string
console.log(str instanceof String); // false
参考文章: https://segmentfault.com/a/11...

类型判断

typeof

相较于JS基本数据类型少null多function。

console.log(typeof null); //object
console.log(typeof undefined); //undefined
console.log(typeof 123); //number
console.log(typeof "123"); //string
console.log(typeof true); //boolean
console.log(typeof function a() {}); //function
console.log(typeof [1, 2, 3]); //object
console.log(typeof {a: "a"}); //object

instanceof

  • 确定原型指向关系。只适用于对象,因为值类型没有原型。
  • 不能判断一个对象实例具体属于哪种类型。
let a = [];
console.log(a instanceof Array);//true
console.log(a instanceof Object);//true

Object.prototype.toString.call()

  • Object 的原型方法,返回"[object type]",其中type是对象的类型。
  • toString()调用null返回[object, Null],undefined返回[object Undefined]。
  • 无法识别自定义的对象类型。
console.log(Object.prototype.toString.call(123)); //[object Number]
function optc(obj) {
    return Object.prototype.toString.call(obj).slice(8, -1);
}

console.log(optc(123)); //Number
console.log(optc('123')); //String
console.log(optc(true)); //Boolean
console.log(optc(undefined)); //Undefined
console.log(optc(null)); //Null
console.log(optc({})); //Object
console.log(optc([])); //Array
console.log(optc(function () {})); //Function
console.log(optc(/\d/)); //RegExp
console.log(optc(new Date())); //Date

constructor(构造函数)

利用构造函数判断数据类型。

  • 对象的构造函数名就是该数据类型。
  • 除Null和Undefined外,所有的数据类型都是/可以转化为对象,而如果是对象,就肯定有构造函数。
function A() {}

let a = new A();
console.log(a.constructor.toString()); //function A() {}

总结

准确判断数据类型包括自定义的对象类型

function dataType(data) {
    if (!data) { //判断null、undefined
        return Object.prototype.toString.call(data).slice(8, -1);
    } else {
        return data.constructor.toString().match(/function\s*([^(]*)/)[1];
    }
}
console.log(dataType(null)); //null
console.log(dataType(undefined)); //Undefined
console.log(dataType(123)); //Number
console.log(dataType([])); //Array

function Point(x, y) {}
console.log(dataType(new Point(1, 2))); //Point

最后:

上面都是自己整理好的!我就把资料贡献出来给有需要的人!顺便求一波关注。学习我们是认真的,拿大厂offer是势在必得的。想了解点击一下java交流群哦

[java交流群](想了解更多点一下哦)

原文链接:www.tuicool.com/articles/EV…