名字解析顺序

155 阅读3分钟

这是我参与11月更文挑战的第7天,活动详情查看:2021最后一次更文挑战

前言

ECMAScript 6.0 简称ES6 , 是 JavaScript 语言的新一代的标准,于在 2015 年 6 月发布,正式名称就是《ECMAScript 2015 标准》。一般情况,泛指, 5.1版以后的标准,涵盖了 ES2015、ES2016、ES2017、ES2018、ES2019、ES2020、ES2021 等等

我们一起来学习变量名解析问题。

先看两个例子

给君2分钟,思考一下,各自的输出结果是什么?

function arg(){
    var arguments;
    console.log(arguments);
}

arg(1,2,3);
function arg(arguments){
    var arguments;
    console.log(arguments);
}

arg(1,2,3);  

答案:

  1. Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
  2. 1

这有什么规律吗?

名字来源

在JavaScript中,一个作用域(scope)中的名称(name)有以下四种:

1. 语言自身定义(Language-defined)
所有的作用域默认都会包含this和arguments。

2. 函数形参(Formal parameters)
函数有名字的形参会进入到函数体的作用域中。

3. 函数声明(Function decalrations)
通过function [name]() {}的形式。

4. 变量声明(Variable declarations)
通过var [name] 的形式。

当然,在ES6里面,多了 const 和 var的形式,基本也是属于第四种。

名字解析顺序

主要参考:JavaScript Scoping and Hoisting

一个名称进入一个作用域一共有四种方式。上面列出来的顺序,就是特名字的解析顺序。

总的来说,如果一个名称已经被 定义 了,他绝不会被另一个拥有不用属性的同名名称覆盖。

根据上面的顺序,函数声明比变量声明具有更高的优先级。仅仅是声明的部分会被忽略而已, 赋值操作依旧遵循该有的顺序。但是有下面几个例外:

  • arguments是在形参之后,函数声明之前被声明。这就意味着名为arguments的形参会比内置的arguments具有更高的优先级,即使这个形参是undefined。 这个描述来自

按照这个推导: 形参 > arguments > 函数申明 > 变量申明

这就解释了的下面的输出结果:

// 形参 > arguments
function arg(arguments){
   var arguments;
   console.log(arguments);
}

arg(1,2,3);   // 1
// arguments > 变量申明
function arg(){
   var arguments;
   console.log(arguments);
}

arg(1,2,3); // 
// Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]

但是这个结果有些意外

function arg(){
    console.log(arguments);
    function arguments(){}
}

arg(1,2,3);
// ƒ arguments(){}

咋眼一看不对啊, 其实 申明不等于赋值,而函数申明,直接会带有值,所以会进行覆盖。

形参,arguments, 变量申明,函数申明全部齐活, 其值依旧是 ƒ arguments(){}

function arg(arguments // 形参){
    var arguments; // 变量申明
    console.log(arguments);
    function arguments(){} // 函数申明
}
  • 任何地方试图使用this作为一个标识都会引起语法错误,这是一个好的特性。

  • 如果有多个同名形参,那位于列表最后的形参拥有最高的优先级,即使它是undefined。

function args(num1, num2 , num1){    
    console.log("num1:", num1);
}
args(1) // num1: undefined

协议的描述

ES5.1 10.5 Declaration Binding Instantiation 也有提到顺序.

小结

今天你收获了吗?

引用

[翻译]JavaScript Scoping and Hoisting
JavaScript Scoping and Hoisting
Declaration Binding Instantiation
Name resolution order in JavaScript