基础进阶(持续更新)

进阶

1、JS基础

1.js数据类型

在这里插入图片描述
js一共八种数据类型,其中7中基本数据类型:String、Number、Null、undefined、Boolean、Symbol(es6新增标识独一无二的)、BigInt(es10新增)。一种引用数据类型Object(包含普通对象-Object,数组对象-Array,正则对象-RegExp,日期对象-Date,数学函数-Math,函数对象-Function)

其中,前 7 种类型为基础类型,最后 1 种(Object)为引用类型,也是需要重点关注的,因为它在日常工作中是使用得最频繁,也是需要关注最多技术细节的数据类型

在这里,重点了解下面两点,因为各种 JavaScript 的数据类型最后都会在初始化之后放在不同的内存中,因此上面的数据类型大致可以分成两类来进行存储:

  • 原始数据类型:基本数据类型存储在栈内存,被引用或者拷贝时,会创建出一个完全相等的变量;占据空间小,大小固定,属于被频繁使用数据,所以放入栈中存储。
  • 引用数据类型:引用数据类型存储在堆内存,存储的是地址,多个引用指向统一地址,相当于共享;占据空间大,大小不固定;引用数据类型在栈中存储了指针,该指针在堆中指向该实体的起始地址,当解释器寻找引用值时,会先检索在栈中的地址,取到地址后在堆中获取实体。

2.JavaScript 中的数据是如何存储在内存中的?

在javascript中,原始数据类型的赋值都是完整复制变量值,而引用数据类型的赋值是赋值引用地址

在javascript执行过程中,主要有三种类型空间:代码空间、栈空间、堆空间。其中的代码空间主要是用来存储可执行代码的,原始类型(Null、String、undefined、Number、Boolean、Symbol、BigInt)的数据值都是存储在栈内存中的,而引用类型是存在堆内存中的,因此在栈空间中(执行上下文),原始类型存储的是变量的值,而引用类型存储的是在堆中的地址,当js需要访问该数据时,是通过栈中存储的引用地址来访问的。

在编译过程中,如果js引擎判断到一个闭包,也会在堆空间中创建一个closure(fn)对象,用来保存闭包中的对象,所以比闭包中的对象是存储在堆空间中的。

JavaScript 引擎需要用栈来维护程序执行期间上下文的状态,如果栈空间大了话,所有的数据都存放在栈空间里面,那么会影响到上下文切换的效率,进而又影响到整个程序的执行效率。通常情况下,栈空间都不会设置太大,主要用来存放一些原始类型的小数据。而引用类型的数据占用的空间都比较大,所以这一类数据会被存放到堆中,堆空间很大,能存放很多大的数据,不过缺点是分配内存和回收内存都会占用一定的时间。因此需要“栈”和“堆”两种空间。

3.数据类型检测

  • typeof
    typeof对于原始类型来说除了null都可以显示正确的类型

    console.log(typeof 2);               // number
    console.log(typeof true);            // boolean
    console.log(typeof 'str');           // string
    console.log(typeof []);              // object     []数组的数据类型在 typeof 中被解释为 object
    console.log(typeof function(){});    // function
    console.log(typeof {});              // object
    console.log(typeof undefined);       // undefined
    console.log(typeof null);            // object     null 的数据类型被 typeof 解释为 object
    

    typeof对于对象来说除了function,都会显示object,所以说 typeof 并不能准确判断变量到底是什么类型,所以想判断一个对象的正确类型,这时候可以考虑使用 instanceof

  • instanceof
    instanceof可以正确的判断对象类型,因为内部机制是判断对象的原型链中是不是能找到来行的prototype

    console.log(2 instanceof Number);                    // false
    console.log(true instanceof Boolean);                // false 
    console.log('str' instanceof String);                // false  
    console.log([] instanceof Array);                    // true
    console.log(function(){} instanceof Function);       // true
    console.log({} instanceof Object);                   // true
    
  • instanceof可以准确地判断复杂的引用类型,但是不能正确的判断基础数据类型;

  • typeof也存在弊端,他虽然可以准确的判断基础数据类型(除null),但是却不能准确的判断引用类型(function除外)

    // 我们也可以试着实现一下 instanceof
    function _instanceof(left, right) {
        // 由于instance要检测的是某对象,需要有一个前置判断条件
        //基本数据类型直接返回false
        if(typeof left !== 'object' || left === null) return false;
    
        // 获得类型的原型
        let prototype = right.prototype
        // 获得对象的原型
        left = left.__proto__
        // 判断对象的类型是否等于类型的原型
        while (true) {
        	if (prototype === left)
        		return true
        	left = left.__proto__
        }
    }
    
    console.log('test', _instanceof(null, Array)) // false
    console.log('test', _instanceof([], Array)) // true
    console.log('test', _instanceof('', Array)) // false
    console.log('test', _instanceof({}, Object)) // true
    
  • constructor

    console.log((2).constructor === Number); // true
    console.log((true).constructor === Boolean); // true
    console.log(('str').constructor === String); // true
    console.log(([]).constructor === Array); // true
    console.log((function() {}).constructor === Function); // true
    console.log(({}).constructor === Object); // true
    

    这里有个问题,如果我创建一个对象并修改他的原型,此时constructor就失效了

  • Object.prototype.toString.call()

    toString() 是 Object 的原型方法,调用该方法,可以统一返回格式为 “[object Xxx]” 的字符串,其中 Xxx 就是对象的类型。对于 Object 对象,直接调用 toString() 就能返回 [object Object];而对于其他对象,则需要通过 call 来调用,才能返回正确的类型信息

    Object.prototype.toString({})       // "[object Object]"
    Object.prototype.toString.call({})  // 同上结果,加上call也ok
    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]"
    
    // 从上面这段代码可以看出,Object.prototype.toString.call() 可以很好地判断引用类型,甚至可以把 document 和 window 都区分开来
    

    全局通用的数据类型判断方法:

    function getType(obj){
      let type  = typeof obj;
      if (type !== "object") {    // 先进行typeof判断,如果是基础数据类型,直接返回
        return type;
      }
      // 对于typeof返回结果是object的,再进行如下的判断,正则返回结果
      return Object.prototype.toString.call(obj).replace(/^\[object (\S+)\]$/, '$1');  // 注意正则中间有个空格
    }
    /* 代码验证,需要注意大小写,哪些是typeof判断,哪些是toString判断?思考下 */
    getType([])     // "Array" typeof []是object,因此toString返回
    getType('123')  // "string" typeof 直接返回
    getType(window) // "Window" toString返回
    getType(null)   // "Null"首字母大写,typeof null是object,需toString来判断
    getType(undefined)   // "undefined" typeof 直接返回
    getType()            // "undefined" typeof 直接返回
    getType(function(){}) // "function" typeof能判断,因此首字母小写
    getType(/123/g)      //"RegExp" toString返回
    
总结
  • typeof
    • 直接在计算机底层根据二进制进行检测
    • type null 为object是因为对象存在在计算机中,都是以000开始的二进制存储,所以检测出来的结果是对象
    • typeof 普通对象/数组对象/正则对象/日期对象 都是object
    • typeof NaN === ‘number’
  • instanceof
    • 检测当前实例是否属于这个类
    • 底层机制:只要原型链上出现过这个类结果都是true
    • 不能检测基本数据类型
  • constructor
    • 支持基本类型
    • constructor可以随便改,也不准
  • object.prototype.toString.call()
    • 能够检测类型

判断 Target 的类型,单单用 typeof 并无法完全满足,这其实并不是 bug,本质原因是 JS 的万物皆对象的理论。因此要真正完美判断时,我们需要区分对待:

  • 基本类型(null): 使用 String(null)
  • 基本类型(string / number / boolean / undefined) + function: - 直接使用 typeof即可
  • 其余引用类型(Array / Date / RegExp Error): 调用toString后根据[object XXX]进行判断
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菜鸡的觉醒之路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值