运行时的函数
程序员文章站
2022-12-21 16:51:40
1. 一级函数 first class functions 1. 函数是一个对象 2. 函数是一级函数,函数可以 1. 存储在变量中\(函数表达式\) 2. 从一个函数返回 3. 作为参数传递给另一个函数\(回调\) 3. 高阶函数 higher order function 1. 返回另一个函数的 ......
-
一级函数 first-class functions
-
函数是一个对象
-
函数是一级函数,函数可以
存储在变量中(函数表达式)
从一个函数返回
- 作为参数传递给另一个函数(回调)
-
高阶函数 higher-order function
-
返回另一个函数的函数 或 接受其他函数作为参数的函数 被称为高阶函数
function alertthenreturn() { alert('message 1!'); return function () { alert('message 2!'); }; } const innerfunction = alertthenreturn(); alertthenreturn(); // 显示 'message 2!' innerfunction(); //显示 'message 2!' alertthenreturn()(); //显示 'message 1!' 然后显示 'message 2!'
-
-
回调callback
-
作用域
-
词法作用域lexical scope和执行环境execution context
块作用域和函数作用域称为词法作用域
- 当一个函数被运行时,会创建一个新的运行时作用域。这个作用域表示该函数的上下文,就是可供该函数使用的一组变量。这就是运行时作用域,即执行环境。
-
执行环境包括:
函数的参数
函数内声明的本地变量
父函数作用域内声明的变量
- 全局变量
-
函数作用域 function scope
-
块级作用域 block scope
es6用let 和 const 关键字实现块级作用域
-
var x = 10; // 这里输出 x 为 10 { let x = 2; // 这里输出 x 为 2 } // 这里输出 x 为 10
-
const
- 此声明创建一个常量。常量的值不能通过重新赋值来改变,并且不能重新声明
- 作用域可以是全局或本地声明的块
-
let
- 声明一个块级作用域的本地变量,并且可选的将其初始化为一个值。
- 为什么使用let
- 像数学里的描述,let x be an arbitrary
-
暂存死区
通过let声明的变量直到他们的定义被执行时才初始化,在初始化前访问该变量会导致referenceerror.
该变量处在自顶部到初始化处理的暂存死区。
如以下代码中的referenceerror
function do_something() { console.log(bar); // undefined console.log(foo); // referenceerror var bar = 1; let foo = 2; }
-
-
用var关键字声明的变量不具备块级作用域的特性,在{ }外依然能被访问到
var x = 10; // 这里输出 x 为 10 { var x = 2; // 这里输出 x 为 2 } // 这里输出 x 为 2
-
函数作用域
- 函数可以访问自己的所有变量和外部的所有全局变量
var globalnumber = 5; function globalincrementer() { const localnumber = 10; globalnumber += 1; return globalnumber; } console.log(globalincrementer()); // 6 console.log(globalincrementer()); // 7 console.log(globalincrementer()); // 8 console.log(localnumber); // referenceerror: localnumber is not defined // 这里localnumber在log函数的外部,因为无法取到localnumber的值,const定义的块级作用域
-
作用域链 scope chain
-
- 在访问变量时,js引擎将遍历作用域链(查找变量的顺序是线性的),首先查看最内层,然后查看外层作用域,最后在必要时到达全局作用域。
- window对象
- 声明的任何全局变量都是作为window对象(全局对象)的属性被访问的,它表示作用域链的最外层。
-
-
变量阴影variable shadowing
-
创建的变量与作用域中的另一个变量具有相同名称时,局部作用域的变量会shadow外部作用域中的变量
var money = '¥'; function mymoney() { var money = '$'; console.log(money); } mymoney(); console.log(money);
- 指向'$'的变量是在函数内部声明的,将shadow位于外部作用域的同名变量,即指向'¥'的全局变量
- 如果函数内部的没有变量声明,只有一个赋值,则会造成scope shadowing
- 在不同执行环境中的变量之间有任何重名重叠,会通过从内部作用域到外部作用域
遍历作用域链来解决。
-
-
-
-
闭包
-
词法作用域lexical scoping
- 'lexical' refers to the fact that lexical scoping uses the location where a variable is declared within the source code to determine where that variable is available.词法作用域通过源代码(自己写的)中变量声明的位置来确定变量在此处否可用。
-
闭包 closure
-
词法环境(又一个坑)-
a lexical environment is a specification type used to define the association of identifiers to specific variables and functions based upom the lexical nesting structure of es code. 词法环境是一个规范类型,是标识符与特定变量和函数基于es代码的词法嵌套结构的关联。一个词法环境由环境记录和可能为空的外部词法环境引用组成。
function makefunc() { var name = 'count'; function func2() { console.log(name); } return func2; } var output = makefunc(); output(); // 'count'
- func2还未执行,被func1返回。一般来说,该段代码不能正常运行,因为局部变量name在func1执行完毕后,name将不能再被访问。但是,why it works?
- 因为js中的函数会形成闭包。函数保留对其作用域的访问的这个过程被称为闭包。
- 闭包是由函数和创建该函数的词法环境组合而成。
- 在这里“词法环境”是指在js文件中编写的代码。
- output是func2函数实例的引用,而func2实例仍可访问其词法作用域中的变量,即可以访问name.
- 因为js中的函数会形成闭包。函数保留对其作用域的访问的这个过程被称为闭包。
-
-
-
函数保留其作用域
标识符是指用来标识某个实体的一个符号,在不同的应用环境下有不同的含义。在编程语言中,标识符是用户编程时使用的名字,用于给变量、常量、函数、语句块等命名,以建立起名称与使用之间的关系。
当使用标识符时,作用域链将被检查,以检索标识符的值。作用域链对于函数访问代码中的标识符来说非常强大的工具。
-