《重学前端》学习笔记(5)

JavaScript执行(三):函数

在 JavaScript,切换上下文最主要的场景是函数调用。

函数

在 ES2018 中,函数已经是一个很复杂的体系了。

  • 普通函数:用 function 关键字定义的函数

    function foo () {
     // code
    }
    
  • 箭头函数:用 => 运算符定义的函数

     foo = () => {
     // code
    }
    
    
  • 方法:在 class 中定义的函数

    class C {
     foo(){
     //code
     }
    }
    
  • 生成器函数:用 function * 定义的函数

  • 类:用 class定义的类,实际上也是函数

    class Foo {
     constructor(){
     //code
     }
    }
    
  • 第六 / 七 / 八种,异步函数:普通函数、箭头函数和生成器函数加上 async关键字。

    async function foo(){
     // code
    }
    const foo = async () => {
     // code
    }
    async function foo*(){
     // code
    }
    

对普通变量而言,这些函数并没有本质区别,都是遵循了“继承定义时环境”的规则,它们的一个行为差异在于 this关键字。

this 关键字的行为

this是 JavaScript 中的一个关键字,它的使用方法类似于一个变量。但是this跟变量的行为有很多不同。

this 是执行上下文中很重要的一个组成部分。同一个函数调用方式不同,得到的 this 值也不同

扫描二维码关注公众号,回复: 9145414 查看本文章

普通函数的 this值由“调用它所使用的引用”决定,其中奥秘就在于:我们获取函数的表达式,它实际上返回的并非函数本身,而是一个 Reference 类型。Reference类型由两部分组成:一个对象和一个属性值。

调用函数时使用的引用,决定了函数执行时刻的 this 值。

从运行时的角度来看,this跟面向对象毫无关联,它是与函数调用时使用的表达式相关。

生成器函数、异步生成器函数和异步普通函数跟普通函数行为是一致的,异步箭头函数与箭头函数行为是一致的

this 关键字的机制

函数能够引用定义时的变量,如上文分析,函数也能记住定义时的 this,因此,函数内部必定有一个机制来保存这些信息。
在 JavaScript 标准中,为函数规定了用来保存定义时上下文的私有属性 [[Environment]]

当一个函数执行时,会创建一条新的执行环境记录,记录的外层词法环境(outer lexical environment)会被设置成函数的 [[Environment]]。这个动作就是切换上下文

JavaScript 用一个栈来管理执行上下文,这个栈中的每一项又包含一个链表。如下图所示:
在这里插入图片描述

当函数调用时,会入栈一个新的执行上下文,函数调用结束时,执行上下文被出栈。
this 则是一个更为复杂的机制,JavaScript 标准定义了 [[thisMode]]私有属性。

[[thisMode]] 私有属性有三个取值:

  • lexical:表示从上下文中找 this,这对应了箭头函数。
    -global:表示当 this 为 undefined 时,取全局对象,对应了普通函数。
    -strict:当严格模式时使用,this 严格按照调用时传入的值,可能为 null或者 undefined。

非常有意思的是,方法的行为跟普通函数有差异,恰恰是因为 class 设计成了默认按strict模式执行

函数创建新的执行上下文中的词法环境记录时,会根据[[thisMode]]来标记新纪录的 [[ThisBindingStatus]]私有属性。
代码执行遇到 this时,会逐层检查当前词法环境记录中的 [[ThisBindingStatus]],当找到有 this的环境记录时获取 this 的值。

操作 this 的内置函数

Function.prototype.callFunction.prototype.apply可以指定函数调用时传入的 this

function foo(a, b, c){
 console.log(this);
 console.log(a, b, c);
}
foo.call({}, 1, 2, 3);// {}  1 2 3
foo.apply({}, [1, 2, 3]);// {}  1 2 3

这里 callapply作用是一样的,只是传参方式有区别

发布了33 篇原创文章 · 获赞 73 · 访问量 2773

猜你喜欢

转载自blog.csdn.net/weixin_46124214/article/details/104199509
今日推荐