美文网首页
JavaScript数据类型的分类、判断和转换

JavaScript数据类型的分类、判断和转换

作者: 刷题刷到手抽筋 | 来源:发表于2022-06-01 10:52 被阅读0次

    简介

    编程语言会有不同的数据类型,这是因为数据是对不同场景的实体的量化抽象,不同实体之间会有区别,另外,不同类型的数据的应用场景和操作也是不一样的。

    例如提示的话术就应该用字符串类型,可以拼接你好,我是${name}。而例如游戏得分应该用数值类型,可以进行加减等运算。

    数据类型

    JavaScript类型介绍

    数据类型分类

    ECMSScript有5种简单数据类型(也称为基本数据类型):Undefined、Null、Boolean、Number、String。还有一种复杂的数据类型——Object。
    —— 《JavaScript高级程序设计》

    根据《JavaScript高级程序设计》中说明,JavaScript有6种数据类型,Undefined、Null、Boolean、Number、String、Object。但实际上typeof null的值是"object",另外typeof function() {}的值是"function"。因此我们认为null并不是一个独立的类型,null是object类型是一个值,而function也是一个独立的类型。

    **js数据类型有6种:

    • number
    • string
    • boolean
    • object
    • function
    • undefined

    undefined类型的值只有一个,就是undefined。

    数值类型有两个特殊的值,NaN(not a number)和Infinity(无穷大)

    object类型又可以分为

    • plain object // 普通对象
    • Date // 日期
    • Array // 数组
    • RegExp // 正则

    其中number、string、boolean、undefined是值类型,function和object是引用类型。

    值类型和引用类型

    值类型和引用类型的区别是,值类型赋的变量直接存储数据,引用类型的变量存储数据的引用。

    let a = 1;
    let b = a;
    b = 2;
    
    console.log(a, b); // 1, 2
    
    let c = {attr: 'yes'};
    let d = c;
    d.attr = 'no';
    
    console.log(c.attr, d.attr); // no no
    
    function test(arg) {
      arg = 2;
    }
    
    let a = 1;
    // 相当于将a的值赋给test中的参数变量,参数改变并不会影响到a
    test(a);
    
    console.log(a); // 1
    
    function update(arg) {
      arg.attr = 2;
    }
    let b = {attr: 1};
    // 将b的引用赋给update的参数变量,参数变量改变引用指向的数据,也会影响到b
    update(b);
    
    console.log(b.attr); // 2
    

    包装类型

    基础类型的数据在使用时候,js引擎会先将之包装为对象,语句执行完对象被销毁。这个过程也被称为“装箱拆箱”。例如

    const arr = '1,2,3'.split(',');

    字符串先包装为String对象,然后对象执行相应方法,语句执行完后,包装对象就被销毁。

    再如(1).toString()将返回数据类型的包装对象转换成的字符串。

    注意:1.toString()会将"."解析为小数点,因此会报语法错误

    包装类型机制扩展了基本数据类型的能力,方便了日常开发。

    因为基础类型也有包装类型转为对象,因此除了Symbol都有构造函数。

    "1".constructor                 // 返回函数 String()  { [native code] }
    (1).constructor                 // 返回函数 Number()  { [native code] }
    false.constructor                  // 返回函数 Boolean() { [native code] }
    [1,2,3].constructor              // 返回函数 Array()   { [native code] }
    {}.constructor  // 返回函数 Object()  { [native code] }
    new Date().constructor             // 返回函数 Date()    { [native code] }
    function () {}.constructor         // 返回函数 Function(){ [native code] }
    

    null和undefined的区别

    本身都表示“没有”,但null表示引用类型的对象为空,undefined则表示变量未定义。

    在相等判断时候,null和undefined是相等的。

    但null和undefined在很多方面有区别。

    含义不同

    null表示对象空指针,undefined表示变量未定义。

    类型不同

    typeof null // 'object'
    typeof undefined // 'undefined'
    Number(null) // 0
    Number(undefined) // NaN
    

    应用场景不同

    null

    作为对象原型链的终点。

    undefined

    定义了变量,没有初始化,默认是undefined。

    函数不return,或者return后面没有值,则函数默认返回undefined。

    函数参数如果不传,默认是undefined。

    类型判断

    判断类型的方法

    typeof

    typeof用来查看字面量或者变量的数据类型

    typeof 1            // 'number'
    typeof '1'          // 'string'
    typeof false            // 'boolean'
    typeof {}           // 'object'
    typeof []           // 'object'
    typeof new Date()       // 'object'
    typeof (() => {})       // 'function'
    typeof undefined        // 'undefined'
    typeof Symbol(1)        // 'symbol'
    

    由结果可知typeof可以测试出numberstringbooleanSymbolundefinedfunction,而对于null数组对象,typeof均检测出为object,不能进一步判断它们的类型。

    instanceof

    instanceof可以判断一个对象的构造函数是否等于给定的值

    ({}) instanceof Object // true
    [] instanceof Array // true
    new Date() instanceof Date // true
    /123/g instanceof RegExp // true
    

    instanceof方法一般用于判断自定义构造函数实例。

    function Person() {}
    const p = new Person();
    p instanceof Person // true
    p instanceof Object // true
    

    The instanceof operator tests to see if the prototype property of a constructor appears anywhere in the prototype chain of an object. The return value is a boolean value.

    —— MDN

    instanceof原理是判断构造函数的原型prototype属性是否出现在对象的原型链上。

    需要注意的是,这里提到instanceof是判断对象的构造函数,不适用与非对象类型的变量,看MDN的例子:

    let literalString = 'This is a literal string';
    let stringObject  = new String('String created with constructor');
    
    literalString instanceof String;  // false, string literal is not a String
    stringObject  instanceof String;  // true
    

    constructor

    console.log(false.constructor === Boolean);// true
    
    console.log((1).constructor === Number);// true
    
    console.log(''.constructor === String);// true
    
    console.log([].constructor === Array);// true
    
    console.log(({}).constructor === Object);// true
    
    console.log((function test() {}).constructor === Function);// true
    
    console.log(Symbol('1').constructor === Symbol);// true
    

    注意:undefined和null没有contructor属性

    这里可以看到虽然数字1的构造函数是Number,但1是对象字面量,不是通过new创建的,因此使用instanceof判断为false。

    Object.prototype.toString

    Object是js中所有其他数据类型的父类。意思是所有的数据类型都继承了Object。但是无论是string还是array都是会重写这个tostring方法的。所以'1'.toString()Object.prototype.toString.call('1')的结果不同。

    Object.prototype.toString.call可以用来区分数组、null等引用类型。

    function Test(){};
    const t = new Test();
    
    Object.prototype.toString.call(1);  '[object Number]'
    
    Object.prototype.toString.call(NaN); '[object Number]'
    
    Object.prototype.toString.call('1'); '[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(Symbol());'[object Symbol]'
    
    Object.prototype.toString.call(foo);  '[object Function]'
    
    Object.prototype.toString.call([1,2,3]); '[object Array]'
    
    Object.prototype.toString.call({});'[object Object]'
    
    Object.prototype.toString.call(t);'[object Object]'
    

    注意自定义对象的判断只能得到"[object Object]"的结果。

    常见变量的类型判断

    判断一个变量是否是对象

    Object.prototype.toString.call(obj) ==='[object Object]'
    

    判断JavaScript对象是否为空对象

    // 方法1  注意该方法性能较差
    function isEmptyObject(obj) {
        return JSON.stringify(obj) === '{}';
    }
    
    // 方法2  因为for in只能枚举对象自身的属性,不能枚举原型属性,因此可以用来判断空对象
    function isEmptyObject(obj) {
      for (var key in obj) {
        return false;
      }
        return true;
    }
    
    // 方法3 Object.keys也是只能获取自身属性,不能获取原型属性
    function isEmptyObject(obj) {
        return Object.keys(obj).length === 0;
    }
    

    如何判断一个对象是否数组

    // ES6中增加的数组方法
    Array.isArray()
    
    // 使用constructor判断
    function isArray(arr) {
        return arr.constructor.toString().indexOf("Array") > -1;
    }
    
    function isArray(arr) {
      return arr.constructor === Array;
    }
    
    // 用instanceof判断
    function isArray(arr) { 
      return arr instanceof Array; 
    }
    

    判断NaN

    isNaN()用来判断一个变量是否为NaN

    isNaN(NaN); // true
    

    或者利用NaN和自己不相等的特性

    typeof num === 'number' && num !== num
    

    类型转换

    为什么要做类型转换

    js是弱类型的语言,声明变量时候未指定变量类型,因此在很多场景下需要做类型转换。

    js和其他端交互(如服务端、native、DOM(如input的value是字符串,需要转换为数字))时候,其他端对数据类型可能有要求

    不同类型数据之间可能要进行运算

    某些场景支持的数据类型固定(如if的condition需要是bool),这时候需要进行类型转换。

    类型转换分为显式转换(包装类型函数、parseInt )和自动转换(隐式转换)。

    转换为字符串类型

    使用toString方法或者String()效果相同

    (1).toSting();  // '1'
    String(1);  // '1'
    

    null和undefined没有toString方法,其他的类型都有。null 和undefined转换字符串可以用String(null)或者'' + null

    转换为数值类型

    parseInt和parseFloat对字符串解析会将字符串前面符合数字规则的部分解析成数字,如果开头就不是数字则返回NaN

    parseInt(123);      // 123
    parseInt('123');    // 123
    parseInt('123a');   // 123
    parseInt('a123');   // NaN
    parseInt('123.123');    // 123
    parseFloat('123.123');  // 123.123
    

    解析数组,解析第一个元素。其他情况都返回NaN。

    parseInt([]);       // NaN
    parseInt([1]);      // 1 
    parseInt([1, 2]); // 1
    parseInt(['1']);    // 1
    parseInt(['a']);    // NaN
    

    类型转换规则

    常见变量转换表

    原始值 转为数字 转为字符串 转为布尔
    false 0 "false" false
    true 1 "true" true
    0 0 "0" false
    1 1 "1" true
    "0" 0 "0" true
    "000" 0 "000" true
    "1" 1 "1" true
    NaN NaN "NaN" false
    Infinity Infinity "Infinity" true
    -Infinity -Infinity "-Infinity" true
    "" 0 "" false
    "20" 20 "20" true
    "a" NaN "a" true
    [] 0 "" true
    [10,20] NaN "10,20" true
    function(){} NaN "function(){}" true
    { } NaN "[object Object]" true
    null 0 "null" false
    undefined NaN "undefined" false

    对象转原始类型

    • 如果有Symbol.toPrimitive()方法,优先调用再返回
    • 调用valueOf(),如果转换为原始类型,则返回
    • 调用toString(),如果转换为原始类型,则返回
    • 没有Symbol.toPrimitive/valueOf/toString的情况
      • 转布尔值
        • null转为false
        • 非null转为true
      • 转数字NaN
      • 转字符串'[object Object]'
    // Symbol.toPrimitive
    var obj = {
      [Symbol.toPrimitive] () {
        return 3;
      },
      valueOf () {
        return 2;
      },
      toString () {
        return 1;
      }
    }
    console.log(obj) // 3
    
    // valueOf
    var obj = {
      valueOf () {
        return 2;
      },
      toString () {
        return 1;
      }
    }
    console.log(obj) // 2
    
    // toString
    var obj = {
      toString () {
        return 1;
      }
    }
    console.log(obj) // 1
    
    // 默认
    var obj = {
    }
    console.log(!!{}); // true
    console.log(obj + '') // "[object Object]"
    console.log(+obj); // NaN
    

    数组转为原始类型

    • 转成bool永远是true
    • 转成字符串,用逗号将各个元素连接起来
    • 转成数值,先转成字符串,再将字符串转成数值类型

    另一个例子:

    如何让if (a == 1 && a == 2)返回true

    var a = {
    value: 0,
      valueOf: function() {
        this.value++;
        return this.value;
      }
    };
    console.log(a == 1 && a == 2);//true
    

    隐式转换

    在一些场景中,不同类型的变量会放在一起处理,这时候js引擎会做隐式转换转,转换为相同的类型后再处理。还有些情况下对变量的类型有要求,而变量如果不符合要求就会进行隐式转换(如if语句要求是bool值,如果是非bool值,会先转换为bool再处理)。\

    隐式转换场景

    1. 算术运算
    2. 单目运算符+
    3. if条件表达式转换为布尔
    4. !运算符转为布尔
    5. ==比较
    6. 比较运算符>、<、≥、≤

    转换规则

    • 双目+号

      • 如果两个操作数都是数值,执行常规的加法计算
      • 如果两个操作数是数值或者布尔,则都转为数值进行计算
      • 如果有至少一个操作数是字符串,则都转成两个字符串拼接
      • 如果有一个操作数是对象,则将这个对象调用toString()转为字符串进行计算
    • -*/号都转换成数字。注意NaN和任何变量运算结果为NaN

    • if转换为bool。

    • !转换为bool。

    • 单目+会转为数字,转换失败时候会转为NaN。

    • ===如果类型不同返回false,如果类型相同则比较值是否相同,注意引用类型对象之和自身相等。

    • == 转换规则

    -   如果是类型相同,直接进行===比较
    -   如果类型不同,要进行转换再比较
    
        • 如果有一个操作数是布尔,则在比较前先将其转为数值(true -> 1; false -> 0)
        • 数值和字符串比较,比较前先将字符串转为数字
        • 如果一个是对象,另一个不是,则先调用对象的valueOf方法,用得到的基本类型值按照前面的规则比较。
        • null和undefined相等
        • 比较之前,null和undefined不转换为其他任何值(所以null只与自己和undefined==,而且null只和自己===;undefined也是一样)
        • 如果有一个是NaN,则相等返回false,不等返回false
        • 如果两个都是对象,则如果它们是同一个对象返回true,否则返回false
    • 比较运算符> < >= <=转换规则
      • 如果两个操作数都是数值,直接比较
      • 如果只有一个是数值,将另一个操作数转为数值,然后比较
      • 如果两个操作数都是字符串,则按字典比较
      • 如果有一个是bool,则将这个转为数值再比较
      • 如果有一个操作数是对象,则调用它的valueOf()获取原始值,若没有valueOf()方法,则调用toString()方法得到字符串,然后按照之前的规则进行比较。\

    练习题

    1 + '1'         // '11'
    1 + + '1'       // 2
    1 + 1 + '1'     // '21'
    1 + '1' + 1     // '111'
    1 + 'a'         // '1a'      
    1 + +'a'        // NaN
    1 - '1'         // 0
    
    !![]    // true
    !!''    // false
    !!{}    // true
    
    if ([]) {console.log('bingo')}      // 'bingo'
    if ('') {console.log('bingo')}      //
    if ('0') {console.log('bingo')}     // 'bingo'
    if ('{}') {console.log('bingo')}    // 'bingo'
    
    NaN == ''           // false
    NaN == 0            // false
    NaN == 'NaN'    // false
    
    1 == '1'    // true
    0 == '0'    // true
    0 == ''     // true
    
    true == '1' // true
    true == 'true'  // false
    true == '0' // false
    
    [] == true  // false
    [] == ![]       // true (首先这个表达式等同于[] == false,然后布尔转为数字:[] == 0,然后对象要转为字符串再比较,即:'' == 0,这样是一个字符串和一个数值比较,要先将字符串转为数字,即:0 == 0)
    [] == '0'   // false
    [] == ''    // true
    ({}) == '[object Object]'    // true
    ({}) == 0    // false
    ({}) == NaN      // false
    true > '0'      // true
    '1.2.3' < '1.2.4'   // true
    [2] > 1         // true
    [2, 1] > 1      // false
    

    参考文章

    灵题库
    前端知识点汇总

    相关文章

      网友评论

          本文标题:JavaScript数据类型的分类、判断和转换

          本文链接:https://www.haomeiwen.com/subject/qnvpurtx.html