代码基本功测试

js的数据类型

前言

作为JavaScript的入门级知识点JS数据类型在整个JavaScript的学习过程中其实尤为重要

数据类型概念

数据类型大致分为两类来进行存储

  1. 基础类型存储在栈内存中。被引用或拷贝时,会创建一个完全相等的变量。基础数据类型有undefinednullBooleanStringNumberSymbolBigInt
  2. 引用类型存储在堆内存中。存储的是地址,多个引用指向同一个地址,这里会涉及一个“共享”的概念。引用数据类型有ArrayRegExpDateMathFunction

下面用几个例子助于理解

let a={
    name:'xlz',
    age:18
}
let b=a;
console.log(a.name);//第一个console 输出xlz
b.name='son';
console.log(a.name);//第二个console 输出son
console.log(b.name);//第三个console 输出son
复制代码

这里第一个输出xlz大家应该都可以理解,那么第二个第三个输出son原因就是a是一个对象存储在堆内存。a变量存储的是堆内存的地址,b=a是把a的内存地址引用过来,ab共享一个地址,所以b.name='son'修改的是这个地址的对象name属性因此输出都是son

数据类型检测

第一种判断方法:typeof 运算符返回一个字符串,表示操作数的类型。

typeof 1//number
typeof '1'//string
typeof undefined//undefined
typeof true//boolean
typeof Symbol()//symbol
typeof null//Object
typeof []//object
typeof {}//object
typeof console//object
typeof console.log//function
复制代码

typeof 只能检测基本数据类型 引用类型只能检测一个function其余的都是object

在 JavaScript 最初的实现中,JavaScript 中的值是由一个表示类型的标签和实际数据值表示的。对象的类型标签是 0。由于 null 代表的是空指针(大多数平台下值为 0x00),因此,null 的类型标签是 0,typeof null 也因此返回 "object"

第二种判断方法:instanceof

instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。

let Car=function(){}
let benz=new Car();
benz instanceof Car//true

let car=new String('Mercedes Benz')
car instanceof String//true

let str='Covid'
str instanceof String//false
复制代码

instanceof实现原理如下

function myInstanceof(left,right){
    //这里先用typeof来判断基本数据类型,如果是,直接返回false
    if(typeof left!=='object'||left===null)return false
    //getProtypeOf是Object对象自带的API,能够拿到参数的原型对象
    let proto=Object.getProtypeOf(left);
    //循环往下寻找,直到找到相同的原型对象
    while(true){
        if(proto===null)return false
        //找到相同原型对象,返回true
        if(proto===right.prototype)return true;
        proto=Object.getProtypeOf(proto)
    }
}
复制代码

可以再控制台验证一下是否ok

两种数据类型的差异

  1. instanceof可以准确的判断复杂引用类型,但是不能正确判断基本数据类型。
  2. typeof也存在弊端,它虽然可以判断基本数据类型(null除外)但是引用数据类型中,除了function类型以外,其他的也无法判断

第三种判断方法:Object.prototype.toString

Object.prototype.toString({})//'[object Object]'
Object.prototype.toString.call({})//同上结果'[object Object]'
Object.prototype.toString.call(1)//'[object Number]'
Object.prototype.toString.call('1')//'[object String]'
Object.prototype.toString.call(true)//'[object Boolean]'
Object.prototype.toString.call(function(){})//'[object Function]'
Object.prototype.toString.call(null)//'[object Null]'
Object.prototype.toString.call(undefined)//'[object Undefined]'
Object.prototype.toString.call(/123/g)//'[object RegExp]'
Object.prototype.toString.call(new Date())//'[object Date]'
Object.prototype.toString.call([])//'[object Array]'
Object.prototype.toString.call(document)//'[object HTMLDocument]'
Object.prototype.toString.call(window)//'[object Window]'
复制代码

这种方法可以检测基本数据类型以及引用类型甚至还可以区分window、document但是要注意的是Object.prototype.toString返回的是[object Xxx]类型第一个首字母是大写开头的

结合以上所学实现一个全局类型检测类型的方法

function getType(obj){
    let type=typeof obj;
    //先进行typeof判断,如果是基础数据类型,直接返回
    if(type!=='object'){
        return type
    }
    //对于typeof返回结果是object,在进行如下的判断,正则返回结果
    return Object.prototype.toString.call(obj).replace(/^\[object (\S+)\]$/,'$1')
}
//代码验证
getType([])//Array toString返回
getType('123')//string typeof返回
getType(window)//Window toString返回
getType(null)//Null toString返回
getType(undefined)//undefined typeof返回
getType(function(){})//function typeof返回
getType(/123/g)//RegExp toString返回
复制代码

数据类型转换

强制类型转换有Number()、parseInt()、parseFloat()、toString()、String()、Boolean()

Number()方法的强制转换规则:

  1. 布尔值 true和false 分别被转换为1和0
  2. 数字 返回自身
  3. null 返回0
  4. undefined 返回NaN
  5. 字符串:如果字符串只包含数字,则将其转换为十进制、如果字符串中包含有效的浮点格式,将其转换为浮点数值、如果是空字符串转换为0、如果不是以上格式字符串,均返回NaN
  6. SYmbol 抛出错误
  7. 对象,并且部署了[Symbol.toPrimitive] 那么调用此方法,否则调用对象的valueOf()方法
Number(true)//1
Number(false)//0
Number('0111')//111
Number(null)//0
Number('')//0
Number('1a')//NaN
Number(-0X11)//-17
Number(0X11)//17
复制代码

Boolean()方法的转换规则: 除了undefined、null、false、’‘、0、(包括+0,-0)、NaN转换出来是false其余都是true

parseInt()、parseFloat()、toString()、String()可以参照上面的方式自打印结果总结一下

在开发中头疼的不是强制类型转换而是隐式类型转换,隐式类型转换包括:

  1. 逻辑运算符 && || !
  2. 运算符+ - * /
  3. 关系操作符 > < <= >=
  4. 相等运算符 ==
  5. if/while条件

这次分析开发中比较常用的==与+的隐式规则

==隐式类型转换规则

  1. 如果类型相通无需进行转换
  2. 如果其中一个操作符是null或者是undefined那么另一个操作符必须为null或undefined才会返回true,否则都是false。
  3. 如果其中一个是Symbol类型那么返回false
  4. 两个操作符如果都为StringNumber类型那么就会将字符串转换为number
  5. 如果一个操作符是boolean那么转换成number
  6. 如果一个操作符值为Object且另一方为string、number或者symbol就会把object转为原始类型在进行判断
null==undefined//true 规则2
null==0 //false 规则2
''==null //false 规则2
''==0 //true 规则4 字符串隐式转换numbe在对比
'123'==123 //true 规则4 字符串隐式转换numbe在对比
0==false //true规则5 
1==true//true规则5 

var a={
    value:0,
    valueOf:function(){
        this.value++;
        return this.value
    }
}
console.log(a==1&&a==2&&a==3);//true 规则6 object隐式转换
//之前的面试题如果让 a==1&&a==2&&a==3 等式成立
//执行a==1会调用valueOf一次value++一次a==2也是调用valueOf value++一次
//执行过3遍之后,再重新执行a==3或者之前的数字就是false
复制代码

'+'的隐式类型转换规则

  1. '+'号操作符,不仅可以用作数字相加,还可以用字符串拼接 如果两个都是数字就进行加法运算、如果两个有一个是字符串那么就会是字符串拼接
  2. 如果其中有一个是字符串,另一个是undefined、null或布尔型则调用toStriing()方法进行字符串拼接。如果是纯对象、数组、正则等,则默认调用对象的转换方法会存在优先级,然后再进行拼接。
  3. 如果其中有一个是数字,另一个是undefined、null、布尔型和数字,则会转换成数字进行加法运算,对象的情况还是参考上一条规则
1+2 //3 常规情况
'1'+'2' //'12' 常规情况
//特殊情况
'1'+undefined //‘1undefined’ 规则2 undefined转换字符串
'1'+null //‘1null’ 规则2 null转换字符串
'1'+true //‘1true’ 规则2 true转换字符串
'1'+1n //‘11’ 比较特殊字符串和BigInt,BigInt转换为字符串

1+undefined //NaN 规则3 undefined转换数字相加NaN
1+null //‘1’ 规则3 null转换0
1+true //‘2’ 规则1 true转换1
1+1n //错误 不能把BigInt和Number类型混合相加1’+3 // '13'规则1 字符串拼接
复制代码

object的转换规则

  1. 如果部署了Symbol.toPrimitive方法优先调用再返回
  2. 调用valueOf,如果转换为基础类型则返回
  3. 调用toString(),如果转换为基础类型则返回
  4. 如果都没有返回基础类型会报错
var obj={
    value:1,
    valueOf(){
        return 2
    },
    toString(){
        return '3'
    },
    [Symbol.toPrimitive](){
        return 4
    }
}
console.log(obj+1)//输出5
//因为有Symbol.toPrimitive,就优先执行这个;如果Symbol.toPrimitive这段代码删掉,则执行valueOf打印为3,如果valueOf也去掉,则调用toStrig返回‘31’(字符串拼接)
复制代码

本文使用 文章同步助手 同步

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容