本文目录
- JS的基本类型
 - 特殊数值和数字
 - 原生函数
 - 强制类型转换
 - 运算符
 - try finally
 - 类型判断及其原理和使用场景
 
JS的基本类型
- string
 - number
 - boolean
 - object
 - undefined
 - null
 - symbol
 
特殊数值和数字
- undefined可以作为表示符(能进行赋值),而null不可以,他们既是基本类型也可以作为值
 - 判断NaN自身既可以用Number.isNaN也可以用自相等(NaN是JS中唯一一个自身不相等的值),不要用window.isNaN。
 
       let a = 2 / 'foo';
       let b = NaN;
       let c = 'foo';
       console.log(window.isNaN(c)) //true
       console.log(Number.isNaN(c)) // false
       console.log(Number.isNaN(b)) // true
       console.log(b === b ? false : true) //true
       console.log(Object.prototype.toString.call(b) === '[object Number]') //true
原生函数
常用的原生函数:
- String()
 - Number()
 - Boolean()
 - Object()
 - Date()
 - Array()
 - Error()
 - Function
 - RegExp()
 - Symbol()
 
封装对象:
概念: 通过构造函数封装了基本值的对象称为封装对象。
封装对象包装: 指JS自动将基本数值包装成一个封装对象以便使用一些属性和方法。
        let a = '123';
        console.log(a.length) //3
如果想自己对基本数值进行包装可以用Object()(不带关键词new)
由于浏览器引擎自身的优化,没必要的情况不用使用封装对象,有时候还会踩坑。
比如:
let a = new Boolean(false)
console.log(!a === false)//true
强制类型转换
抽象值操作,即对字符串,数字,布尔值之间的类型转换:
1. toString:
常用方法:
- "" + value
 - String(value)
 - value.toString
 - JSON.strinify(value)
ps: 前两种可以处理null,undefined这些值,而第三种不可以,至于第四种通过JSON进行字符串化只能是安全的JSON值(除了undefined,function,symbol和循环引用的对象),在对象中会将其忽略,在数组中返回null 
规则:
- null转"null"
 - undefined 转“undefined”
 - true 转 "true"
 - false转 "false"
 - 数字用通用规则,其中极大值和极小值用指数形式
 - 普通对象除非自定义不然用内部属性[[Class]]的值(通过Ojbect.prototype.toString.call(xxx)获取)
 
let obj = {
    a: undefined,
    b: function(){},
    c: Symbol(123)
}
let arr = [undefined, function(){}, Symbol(123)]
console.log(JSON.stringify(obj))//{}
console.log(JSON.stringify(arr))//[null, null, null]
2. toNumber
常用方法:
- Number(value)
 - +value
 - parseInt系列
 
规则:
- true转1
 - false 转0
 - undefined 转NaN
 - null 转为0
 - 对象(包括数组)先通过[Symbol.toPrimitive]转,没有则通过valueOf,还没有,就使用toString方法)转换成基本类型值,然后这个这个基本类型值如果不是数字类型就按照上面说的4种方法转换,是就按照数字通用规则转换。
 
let a = {
    valueOf: () => 1
}
let b = {
    toString: () => 2
}
let arr1 = [1,2]
arr1.valueOf = () => 123
console.log(Number(a))//1
console.log(Number(b))//2
console.log(Number(arr1))//123
3. toBoolean:
常用方法:
- Boolean(value)
 - !!
 
规则:
js中所有可以强制转换为false的值就是假值,总共有以下几种:
- undefined
 - -0, +0, NaN
 - ""
 - null
 
ps: 除了假值以外的值就是真值
运算符
||和三元运算符
三元运算符在条件成立的时候会多运算一边,而 || 不会,比如:
let index = 0;
function f1() {
    index++;
    console.log(index)
    return true
}
f1() ? f1(): fasle//1 2
f1() || false//3
try finally
try finally 语法中finally会在结果返回之前执行
function f1() {
    try {
        return 'f1的结果'
    }
    finally {
        console.log(123)
    }
}
console.log(f1())//123 f1的结果
类型判断及其原理和使用场景
常用的方法:
- typeof
 - instanceof
 - constructor
 - Object.prototype.toString.call
 
【typeof】
返回结果有8种:
- ‘string’
 - ‘number’
 - ‘undefined’
 - ‘function’
 - ‘boolean’
 - ‘object’
 - 'symbol'
 - 'bigint'
 
typeof 只有1种情况下会报错:
在const,let这些关键字申明的变量上面使用(‘暂存死区’)
console.log(typeof a);
let a;
实现原理:
js 在底层存储变量的时候,会在变量的机器码的低位1-3位存储其类型信息👉
000:对象
010:浮点数
100:字符串
110:布尔
1:整数
but, 对于 undefined 和 null 来说,这两个值的信息存储是有点特殊的。
null:所有机器码均为0
undefined:用 −2^30 整数来表示
【instanceof】
instanceof的实现原理就是通过右边的值是否存在左边的原型链上实现的。用代码就是这样表示:
let myInstanceof = function(value, type) {
    const right = type.prototype;
    let left = value.__proto__;
    while(true) {
        if(left === null) {
            return false
        }else if(left === right){
            return true
        }else {}
        left = left.__proto__;
    }
}
console.log(myInstanceof([], Array))
看几个有趣的例子:
function Foo() {
}
Object instanceof Object // true
Function instanceof Function // true
Function instanceof Object // true
Foo instanceof Foo // false
Foo instanceof Object // true
Foo instanceof Function // true
这里记住这样一条父子链:
Object.prototype(爷爷) => Function.prototype(爸爸) => Object和Function(儿砸)
所有具体对象默认的proto和函数默认的proto都分别指向Object.prototype和Function.prototype
当然除了原生的类型,你也可以通过Symbol.hasInstance自定义instance的行为
class obj {
    static [Symbol.hasInstance](instance) {
        return true
    }
}
console.log('scsdfd' instanceof obj)//true
constructor
返回创建实例对象的 Object构造函数的引用。注意,此属性的值是对函数本身的引用,而不是一个包含函数名称的字符串.
Object.prototype.toString.call
对类型判断比较完善。
PS:
根据目前我掌握的情况来看,如果目标对象上存在Symbol.toStringTag属性,则将Symbol.toStringTag的值作为结果的一部分返回,否则继续从其原型上找到其类型返回。
let arr1 = [1,2,45];
let arr2 = []
arr1[Symbol.toStringTag] = '6666'
console.log(Object.prototype.toString.call(arr1))//[object 6666]
console.log(Object.prototype.toString.call(arr2))//[object Array]
参考
https://www.jianshu.com/p/c463eca929c2