文档章节

浅析javascript中的函数及执行环境

x
 xszl
发布于 2017/09/08 21:34
字数 1427
阅读 8
收藏 0
点赞 0
评论 0

###函数简介 函数是javascript中一个主要的组成部分,像闭包、this、全局变量和局部变量都和函数息息相关,想要真正了解javascript是如何工作的,首先就得了解函数。

函数能访问内部声明的局部变量,也可以访问那些通过函数参数传递进来的变量,还能访问当前作用域外声明的全局变量,所有的这些都是基于函数的执行环境,一个提供变量可以被函数访问的环境。

要了解清楚函数被调用时所发生的一切细节会相对有些困难,下面所述部分只是技术说明的一个简化,想要了解详情的可以参考ECMA文档。

###执行环境的创建 当函数被调用时,会创建该函数的执行环境,下面来看看这个执行环境是如何构建的,你需要注意每一步的顺序

  1. 创建arguments属性,这是一个具有整数键的数组式对象(并非是数组),对象引用传入函数调用的值,同时该对象还包括length(函数传递进来的参数的数量)和callee(指向该函数的引用)属性
  2. 通过[[scope]]属性和执行环境创建函数的作用域。后面会详细说明
  3. 变量实例化,分为三步
    • 执行环境将argument对象中的值赋给函数签名,如果argument中没有,则赋值成undefined
    • 扫描函数体,检测是否有函数声明,如果有,将函数名作为环境变量的一个属性
    • 扫描函数体,检测是否有变量声明,如果有,将变量名作为函数变量的一个属性,属性值为undefined
  4. 创建this属性,这个需要依据函数如何被调用
    • 作为正常函数被调用,this指向全局对象
    • 作为对象的方法被调用,this指向该对象
    • 作为构造函数被调用,this指向那个构造函数生成的新对象
    • 使用call或者apply调用,this指向call或者apply的第一个参数
    • 使用setTimeout或者setInterval调用,this指向全局对象

####示例:

    function foo(a, b ,c) {
        function z() {
            alert('z!');
        }
        var d = 3;
    }
    foo('foo', 'bar');

调用foo('foo', 'bar'):

  • step1:创建arguments属性
ExecutionContext: {
    arguments: {
        0: 'foo',
        1: 'bar',
        length: 2,
        callee: function() //Points to foo function
    }
}
  • step3a: 变量实例化,arguments
ExecutionContext: {
    arguments: {
        0: 'foo',
        1: 'bar',
        length: 2,
        callee: function() //Points to foo function
    },
    a: 'foo',
    b: 'bar',
    c: undefined
}
  • step3b:变量实例化,function
ExecutionContext: {
    arguments: {
        0: 'foo',
        1: 'bar',
        length: 2,
        callee: function() //Points to foo function
    },
    a: 'foo',
    b: 'bar',
    c: undefined,
    z: function() //Created z() function
}

-step3c:变量实例化,variables

ExecutionContext: {
    arguments: {
        0: 'foo',
        1: 'bar',
        length: 2,
        callee: function() //Points to foo function
    },
    a: 'foo',
    b: 'bar',
    c: undefined,
    z: function(), //Created z() function
    d: undefined
}

-step4:this赋值

ExecutionContext: {
    arguments: {
        0: 'foo',
        1: 'bar',
        length: 2,
        callee: function() //Points to foo function
    },
    a: 'foo',
    b: 'bar',
    c: undefined,
    z: function(), //Created z() function
    d: undefined,
    this: window
}

###环境栈 函数的作用域创建完之后,函数开始执行代码,从第一行直到函数结束(最后一行或者return),这期间访问变量都是从上面ExecutionContext这个对象中读取。

每个函数都会有一个与之相关联的ExecutionContext,所有的声明都是在ExecutionContext中执行(在全局执行环境中有一个GlobalExecutionContext,和ExecutionContext类似,只是全局执行环境中没有arguments,所以没有第一步)

随着程序的执行,从一个函数进入另一个函数,那么就会创建一个环境栈。我们来看下述代码

    function a() {
        function b() {
            var c = {
                d: function() {
                    alert(1);
                }
            };
            c.d();
        }
        b.call();
    }
    a();

当javascript引擎将要执行aler()函数时,执行环境栈是:

  • d() Execution context
  • b() Execution context
  • a() Execution context
  • Global execution context

进入一个函数,就会将它的执行环境压入环境栈中,这个环境栈也被称作作用域链,需要注意的是作用域链和函数调用栈大是不同的。

在函数中查找一个变量,javascript引擎会先从作用域链的最前端开始搜索,如果没有找到,会向下一级的作用域链查找,直到作用域链的最底端,如果还没找到,就返回undefined 。

###总结

  • this的值是在函数被调用的时候动态绑定,因此具备多重含义
  • arguments不是数组,而是一个带有数字作为属性的常规对象
  • 变量的定义实际是在步骤3c中定义,当代码执行到达初始化指令时,会发生初始化
  • 可以在函数声明之前调用函数
  • 不会执行的函数声明依旧会被创建(js作用域提升)
    function foo() {
        if (false) {
            function bar() {
                alert(1);
            }
        }
        bar();
    }

在执行代码进行if判断之前,bar() 已经在作用域中被创建,所以能正常运行

  • 变量覆盖,基于作用域链
  • 闭包:子函数会携带父函数的作用域,当我们访问一个变量时,如果当前执行环境中没有找到,但在下一级的作用域链中能找到
  • 全局变量在作用域链的最底端,访问全局变量需要遍历整个作用域链,效率很低。

javascript函数的核心其实就是执行环境和作用域链,合理利用这些进行设计,会让程序变得更简单自然,基于mixin的继承系统也很容易实现。很多javascript库,比如jquery,依靠执行环境加载模块,从而不会污染全局变量,尽可能深入的去了解执行环境和作用域链能发挥javascript的强大能力

© 著作权归作者所有

共有 人打赏支持
x
粉丝 0
博文 14
码字总数 17267
作品 0
javascript 执行上下文

归纳总结一下执行上下文系列,其中包括了变量对象、作用域链和 this。本篇主要详细介绍执行上下文。 执行上下文(Execution Context,EC)可以理解为当前代码的运行环境。 在 javascript 中,...

淘淘笙悦 ⋅ 06/09 ⋅ 0

关于js的bind牌胶水,了解一下?

前言 今天聊一聊js中的bind方法,主要从三个维度来阐述:why——>what——>how。文章虽经个人多次校验,对语言表述、代码书写等进行了认真审核,但仍免不了有疏漏之处,如若发现,还望指出,...

hanmin ⋅ 05/14 ⋅ 0

JavaScript 工作原理之六-WebAssembly 对比 JavaScript 及其使用场景

原文请查阅这里,略有改动,本文采用知识共享署名 4.0 国际许可协议共享,BY Troland。 本系列持续更新中,Github 地址请查阅这里。 这是 JavaScript 工作原理的第六章。 现在,我们将会剖析...

tristan ⋅ 05/15 ⋅ 0

JS 底蕴之 变量、作用域和垃圾回收

基本类型和引用类型 在 JavaScript 中,数据类型可分为基本类型和引用类型, 基本类型有六种:Null,Undefined,String,Boolean,Number,Symbol; 而引用类型就是传说中的 Object 了。 其中...

Fly_001 ⋅ 05/23 ⋅ 0

JavaScript核心概念归纳整理

原文出处: 熊俊漉 JavaScript语言本身是一个庞大而复杂的知识体系,复杂程度不低于任何一门后端语言,本文针对JavaScript语言的核心概念进行简单的梳理,对应的每个知识点仅仅点到为止,不作...

音乐宇Code ⋅ 05/27 ⋅ 0

[译] JavaScript 如何工作:对引擎、运行时、调用堆栈的概述

原文地址: https://blog.sessionstack.com/how-does-javascript-actually-work-part-1-b0bacc073cf PS: 好久没写东西了,最近一直在准备写一个自己的博客,最后一些技术方向已经敲定了,又可...

小烜同学 ⋅ 2017/11/12 ⋅ 0

将一个前端项目改写为chromo插件(一)

编写第一个chrome插件? 编写chrome插件完全就是前端知识加上一些专门的知识。 假设文件夹下有文件 嗯,现在看来他只是普通的html,其实,你只要在当前文件夹下加上文件,chrome浏览器就可以把...

saltfish666 ⋅ 05/27 ⋅ 0

手把手教你撸一个简易的 webpack

背景 随着前端复杂度的不断提升,诞生出很多打包工具,比如最先的,。到后来的和。但是目前很多脚手架工具,比如已经帮我们集成了一些构建工具的使用。有的时候我们可能并不知道其内部的实现...

muwoo ⋅ 06/07 ⋅ 0

[译] JavaScript 是如何工作的:对比 WebAssembly + 为什么在某些场景下它比 JavaScript 更合适

原文地址:How JavaScript works: A comparison with WebAssembly + why in certain cases it’s better to use it over JavaScript 原文作者:Alexander Zlatkov 译文出自:掘金翻译计划 本......

stormluke ⋅ 05/23 ⋅ 0

js笔记二十九之this关键字

我们在js中主要研究的都是函数中的this js中的this代表的是当前行为执行的主体 js中的context(上下文)代表的是当前行为执行的环境(区域) this是谁和函数在哪定义的和在哪执行的都没有任何的关...

uplyw ⋅ 05/25 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

6. Shell 函数 和 定向输出

Shell 常用函数 简洁:目前没怎么在Shell 脚本中使用过函数,哈哈,不过,以后可能会用。就像java8的函数式编程,以后获取会用吧,行吧,那咱们简单的看一下具体的使用 Shell函数格式 linux ...

AHUSKY ⋅ 8分钟前 ⋅ 0

MySQL 内核深度优化

MYSQL数据库适用场景广泛,相较于Oracle、DB2性价比更高,Web网站、日志系统、数据仓库等场景都有MYSQL用武之地,但是也存在对于事务性支持不太好(MySQL 5.5版本开始默认引擎才是InnoDB事务...

OSC_cnhwTY ⋅ 15分钟前 ⋅ 0

单片机软件定时器

之前写了一个软件定时器,发现不够优化,和友好,现在重写了 soft_timer.h #ifndef _SOFT_TIMER_H_#define _SOFT_TIMER_H_#include "sys.h"typedef void (*timer_callback_function)(vo...

猎人嘻嘻哈哈的 ⋅ 17分钟前 ⋅ 0

好的资料搜说引擎

鸠摩搜书 简介:鸠摩搜书是一个电子书搜索引擎。它汇集了多个网盘和电子书平台的资源,真所谓大而全。而且它还支持筛选txt,pdf,mobi,epub、azw3格式文件。还显示来自不同网站的资源。对了,...

乔三爷 ⋅ 25分钟前 ⋅ 0

Debian下安装PostgreSQL的表分区插件pg_pathman

先安装基础的编译环境 apt-get install build-essential libssl1.0-dev libkrb5-dev 将pg的bin目录加入环境变量,主要是要使用 pg_config export PATH=$PATH:/usr/lib/postgresql/10/bin 进......

玛雅牛 ⋅ 26分钟前 ⋅ 0

inno安装

#define MyAppName "HoldChipEngin" #define MyAppVersion "1.0" #define MyAppPublisher "Hold Chip, Inc." #define MyAppURL "http://www.holdchip.com/" #define MyAppExeName "HoldChipE......

backtrackx ⋅ 55分钟前 ⋅ 0

Linux(CentOS)下配置php运行环境及nginx解析php

【part1:搭建php环境】 1.选在自己需要安装的安装包版本,wget命令下载到服务器响应目录 http://php.net/releases/ 2.解压安装包 tar zxf php-x.x.x 3.cd到解压目录执行如下操作 cd ../php-...

硅谷课堂 ⋅ 今天 ⋅ 0

Nginx服务架构初探(四):nginx服务器的rewrite功能

nginx服务器的rewrite功能 1.nginx后端服务器组的配置 1>upstream name {…} name是给服务器组限的组名 2>server address [parameters]; address为服务器地址 parame......

余温灬未存 ⋅ 今天 ⋅ 0

layer.prompt使文本框为空的情况下也能点击确定

最近一直在使用layui,但是用到弹出层layer.prompt时,如果文本框是空的话点击确定没有反应,不能向下执行。 但是我又需要空值,看看我原来的代码。 123456789 layer.prompt...

孟飞阳 ⋅ 今天 ⋅ 0

Linux普通文件压缩工具gzip、Bzip2、xz

第六章 文件压缩和打包 6.1 压缩打包介绍 Linux环境常见压缩文件类型: .zip,.gz,.bz2,.xz, .tar.gz,.tar.bz2,.tar.xz 压缩打包的目的 方便文件传输 节省磁盘空间 减少传输花费的时间 ...

弓正 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部