JS基础和ES6相关

这篇博客详细探讨了JavaScript的基础和ES6特性,包括数据类型、强制类型转换、对象转换、类型检测方法、执行上下文、词法作用域、作用域链、闭包、垃圾回收机制、this及改变this指向的方法、原型链、继承、数组操作、字符串方法、异步处理、事件循环机制、定时器、浏览器下的JavaScript执行模型以及ES6的let/const、Promise、Generator、async/await等内容,深入解析了JavaScript的核心概念和技术细节。
摘要由CSDN通过智能技术生成

JS基础和ES6相关

JS数据类型(记得介绍ES6新增symbol)

  1. 值类型(基本类型):String、Number、Boolean、Null、Undefined、Symbol(ES6引入的一种新的原始数据类型,表示独一无二的值)、bigint
  2. 引用数据类型:对象(Object)【包含普通对象- Object、数组对象(Array)、函数对象(Function)、日期对象(Date)、数字对象(Math)、正则对象(RegExp)】

JS强制类型转换

  1. 显式转换

    通过手动进行类型转换,JavaScript提供了以下转型函数

    转换为数值类型:Number(mix)、parseInt(string, radix)、parseFloat(string)
    转换为字符串类型:toString(radix)、String(mix)
    转换为布尔类型:Boolean(mix)
    
    • Number(mix),可以将任意类型的参数mix转换为数值类型,规则如下:

      1. 布尔值:true-1、false-0
      2. 数字值:返回本身
      3. null:返回0
      4. undefined:返回NaN
      5. 字符串:只包含数字—转换为十进制(忽略前导0)、包含有效的浮点格式—转换为浮点数值(忽略前导0)、空字符串—0、其他格式—NaN
      6. 对象:调用对象的valueOf(),依据前面规则转换返回值。如果转换结果为NaN,则调用对象的toString(),依照前面的规则转换返回的字符串值
    • **parseInt(string, radix)**函数,将字符串转换为整数类型的数值

      1. 忽略字符串前面的空格,直至找到第一个非空字符
      2. 如果第一个字符不是数字符号或者负号,返回NaN
      3. 如果第一个字符是数字,则继续解析直至字符串解析完毕或者遇到一个非数字符号为止
      4. 如果上步解析的结果以0开头,则将其当作八进制来解析;如果以0x开头,则将其当作十六进制来解析
      5. 如果指定radix参数,则以radix为基数进行解析
    • **parseFloat(string)**函数,将字符串转换为浮点数类型的数值

      与parseInt基本相同,但也有点区别:字符串中第一个小数点符号是有效的,另外parseFloat会忽略所有前导0,如果字符串包含一个可解析为整数的数,则返回整数值而不是浮点数值

    • **toString(radix)**方法。除undefined和null之外的所有类型的值都具有toString()方法,其作用是返回对象的字符串表示

    • **String(mix)**函数,将任何类型的值转换为字符串,其规则为

      1. 如果有toString()方法,则调用该方法(不传递radix参数)并返回结果
      2. 如果是null,返回”null”
      3. 如果是undefined,返回”undefined”
    • **Boolean(mix)**函数,将任何类型的值转换为布尔值。

      以下值会被转换为false:false、”"、0、NaN、null、undefined,其余任何值都会被转换为true。

  2. 隐式转换

    在某些情况下,即使我们不提供显示转换,Javascript也会进行自动类型转换

    1. 用于检测是否为非数值的函数:isNaN(mix)

      该函数会尝试将参数值用Number()进行转换,如果结果为“非数值”则返回true,否则返回false

    2. 递增递减操作符(包括前置和后置)、一元正负符号操作符

    3. 加法运算操作符

    4. 乘除、减号运算符、取模运算符

    5. 逻辑操作符(!、&&、||)

    6. 关系操作符(<, >, <=, >=)

    7. 相等操作符(==)

对象—原始值转换

当对象相加 obj1 + obj2,相减 obj1 - obj2,或者使用 alert(obj) 打印时会发生什么?在这种情况下,对象会被自动转换为原始值,然后执行操作。

  1. 如果Symbol.toPrimitive()方法,优先调用再返回
  2. 调用valueOf(),如果转换为原始类型,则返回
  3. 调用toString(),如果转换为原始类型,则返回
  4. 如果都没有返回原始类型,会报错

JS检测类型的方法(优缺点)

  • tyepof [value] :检测数据类型的运算符
  • [example] instanceof [class] : 检测某一个实例是否属于这个类
  • [example].constructor===[class] :检测实例和类关系的,从而检测数据类型
  • Object.prototype.toString.call([value]):检测数据类型
  1. typeof

    定义:用来检测数据类型的运算符

    语法:tyepof [value]

    返回值:

    • typeof 检测的结果首先是一个字符串;

    • 字符串中包含了对应的数据类型(例如: “number”“string”“boolean”“undefined”“object”“function”“symbol”“bigint”

      img

    • 优点:使用简单,基本数据类型值基本上都可以有效检测,引用数据类型值也可以检测出来

    • 局限性:

      NaN/Infinity都是数字类型的,检测结果都是“number”,typeof null的结果是“object”(这是浏览器的BUG:所有的值在计算中都以二进制编码储存,浏览器中把前三位000的当作对象,而null的二进制前三位是000,所以被识别为对象,但是他不是对象,他是空对象指针,是基本类型值);typeof 普通对象/数组对象/正则对象..., 结果都是“object”,这样就无法基于typeof 区分是普通对象还是数组对象``...等了

  2. instanceof

    • 定义:用来检测某个实例是否属于这个类
    • 语法:实例instanceof类
    • 属于返回true,否则反之
    • 优点:可以弥补typeof无法细分对象类型的缺点(想检测这个值是否为数组,只需要看他是否为Array类的实例即可)
    • 局限性:
      • 要求检测的实例必须是对象数据类型的
      • 基本数据类型的实例是无法基于它检测出来的
      • 不管是数组对象韩式正则对象,都是 Object 的实例,检测结果都是 TRUE ,所以无法基于这个结果判断是否为普通对象

    注意️:它本身不能完成数据类型检测,只是利用它(检测某个实例属否属于这个类的)特征来完成数据检测

  3. constructor

    • 定义:判断当前的实例的constructor的属性值是不是预估的类
    • 语法:实例.constructor === 类
    • 返回值:属于返回true,否则反之
    • 优点:实例.constructor一般都等于类.prototype.constructor也就是当前类本身,并且能检测基本数据类型
    • 局限性:
      • 不能够给当前类的原型进行重定向,会造成检测结果不准确
      • 不能够给当前实例增加私有属性constructor,也会造成检测的结果不准确
      • 非常容易被修改,因为JS中的construction是不被保护的,这样基于construct检测的值存在不确定性

    注意:它本身不能完成数据类型检测,利用他的实例数据类型检测(不能重定向)

  4. Object.prototype.toString.call()

    • 定义:找到Object.prototype上的toString方法,让toString方法执行,并且基于call让方法中的this指向检测的数据值,这样就可以实现数据类型检测了
    • 原理:
      • 每一种数据类型的构造函数的原型上都有toString方法
      • 除了Object.prototype上的toString是用来返回当前实例所属类的信息(检测数据类型的),其余的都是转换为字符串的
      • 对象实例.toString()toString方法中的THIS是对象实例,也就是检测它的数据类型,也就是THIS是谁,就是检测谁的数据类型
      • Object.prototype.toString.call([value]) 所以我们是把toString执行,基于call改变this为要检测的数据值
    • 使用方法:
      • Object.prototype.toString.call(被检测的实例)
      • ({}).toString.call(被检测的实例)
    • 返回值:是一个字符串“[Object 当前被检测实例所属的类]”
    • 优点:
      • 专门用来检测数据类型的方法,基本上不存在局限性的数据类型检测方式
      • 基于他可以有效的检测任何数据类型的值
    • 局限性:
      • 只能检测内置类,不能检测自定义类
      • 只要是自定义类返回的都是‘[Object Object]’

    注意:此方法是基于JS本身专门进行数据检测的,所以是目前检测数据类型比较好的方法

    img

执行上下文&&词法作用域&&作用域链

执行上下文

  1. 定义

    执行上下文是评估和执行JavaScript代码的环境的抽象概念,每当JavaScript代码在运行的时候,他都是在执行上下文中运行。当函数执行时候,会创建一个成为执行上下文的内部对象。一个执行上下文定义了一个函数执行时的环境,函数每次执行对应的执行上下文都是独一无二的,所以多次调用一个函数会导致创建多个执行上下文,当函数执行完毕,它所产生的执行上下文被销毁。

  2. 执行上下文的类型

    • 全局执行上下文

      默认的,任何不在函数内部的代码都在全局上下文中,他会执行两件事:创建一个全局的window对象,并且设置this的值等于这个全局对象。一个程序中只会有一个全局执行上下文

    • 函数执行上下文

      每当一个函数被调用时,都会为该函数创建一个新的上下文。每个函数都有自己的执行上下文,不过是在函数被调用的时候创建的,函数上下文可以有任意多个。每当一个新的执行上下文被创建,他会按定义顺序执行一系列步骤

    • Eval函数执行上下文

      在eval函数内部的代码也会有她属于自己的执行上下文

  3. 执行栈

    是一种拥有LIFO(后进后出)数据结构的栈,被用来存储代码运行时候创建的所以执行上下文。当 JavaScript 引擎第一次遇到你的脚本时,它会创建一个全局的执行上下文并且压入当前执行栈。每当引擎遇到一个函数调用,它会为该函数创建一个新的执行上下文并压入栈的顶部。引擎会执行那些执行上下文位于栈顶的函数。当该函数执行结束时,执行上下文从栈中弹出,控制流程到达当前栈中的下一个上下文。

  4. 怎么创建执行上下文

    • 创建阶段

      • this值的确定,即this绑定

        在全局执行上下文中,this的值指向全局对象,在函数执行上下文中,this的值取决于该函数是如何被调用的,如果他被一个引用对象调用,那么this会被设置成那个对象,否则this的值被设置为全局对象或者undefined

      • 创建词法环境组建

        词法环境的内部有两个组件:环境记录器一个外部环境的引用

        • 全局环境:是没有外部环境引用的词法环境。全局环境的外部环境引用是null,他拥有内建的Object/Array等,在环境记录器内的原型函数还有任何用户定义的全局变量,并且this的值指向全局对象
        • 函数环境:函数内部用户定义的变量存储在环境记录器中
      • 创建变量环境组建

        同样是一个词法环境,其环境记录器持有变量声明语句在执行上下文中创建的绑定关系。词法环境组件和变量环境的一个不同就是前者被用来存储函数声明和变量(letconst)绑定,而后者只用来存储 var 变量绑定。

词法作用域

  • [[scope]]:每个javascript函数都是一个对象,对象中有些属性我们可以访问,但有些不可以,这些属性仅供JavaScript引擎存取,[[scope]]就是其中一个,[[scope]]指的就是我们所说的作用域,其中存储了运行期上下文的集合

  • 作用域链

    [[scope]]中所存储的执行期上下文对象的集合,这个集合呈链式链接.当访问一个变量时,解释器会首先在当前作用域查找标示符,如果没有找到,就去父作用域找,直到找到该变量的标示符或者不在父作用域中,这就是作用域链

作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期。在JavaScript中,变量的作用域有全局作用域和局部作用域两种。

function a() {
   
  function b () {
   
    function c () {
   
    }
    c();
  }
  b()
}
a();

a defined a.[[scope]] ---> 0 : GO
a doing   a.[[scope]] ---> 0 : aAO
													 1 : GO
b defined b.[[scope]] ---> 0 : aAO
													 1 : GO
b defined b.[[scope]] ---> 0 : bAO
													 1 : aAO  
                           2 : GO
c defined c.[[scope]] ---> 0 : bAO
													 1 : aAO  
                           2 : GO 
c doing c.[[scope]]   ---> 0 : cAO
													 1 : bAO
													 2 : aAO  
                           3 : GO                    

JS执行步骤

  1. 语法分析

  2. 预编译

    预编译发生在函数执行的前一刻

    函数声明整体提升、变量 声明提升

    • 创建AO对象(执行期上下文)
    • 找形参和变量声明,将变量和形参作为AO属性名,值为undefined
    • 将实参值和形参统一
    • 在函数体里面找函数声明,值赋予函数体
    function fn(a) {
         
      console.log(a); // function a() {}
      var a = 123;
      console.log(a); // 123
      function a() {
         }
      console.log(a); // 123
      var b = function () {
         }
      console.log(b); // function () {}
      function d() {
         }
    }
    fn(1)
    
    创建AO对象
    AO {
         
        a: undefined->1->function a() {
         }->123
        b: undefined->function () {
         }
      	d: undefined->function d(){
         }
    }
    
    function test(a, b) {
         
      console.log(a); // 1
      c = 0;
      var c;
      a = 3;
      b = 2;
      console.log(b); // 2
      function b () {
         };
      function d () {
         };
      console.log(b); // 2
    }
    test(1);
    
    AO {
         
      a: undefined->1->3
      b: undefined->function b () {
         }->2
      c: undefined->0
      d: undefined->function d () {
         };
    }
    
    GO {
         
      global: undefined -> 100
      fn: function(){
         }
    }
    global = 100;
    function fn() {
         
      console.log(global); // undefined
      global = 200
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值