You Don't Know JS: Scope & Closures (第4章: Hoisting)

Chapter4: Hoisting

变量附加到哪个层次的scope,由它们在哪里和如何声明(let, var)来决定。

Function scope/Block scope都有相同的法则:任何变量在一个scope内声明,则这个变量附加到这个作用域上。

但有一个细节问题:当声明declarations出现在一个作用域中的不同的位置的时候,scope附加如何与declarations协作?


Chicken or The Egg?

temptation: a strong desire to have or do sth even thought you know you should not(邪念,诱惑人的事物)

当程序执行时,JS 代码被一行行,从上到下的顺序被解译。但有例外:

a = 2;

var a;

console.log( a );  输出2

可是:

console.log( a );

var a = 2;  
//输出undefined

怎么回事? 一个先有鸡还是先有蛋的问题。 the declaration是蛋, assignment是鸡。


The Compiler Strikes Again 编译器又罢工了

Engine实际是先编译JS code,在interprtes it之前。

编译器先声明变量,然后Engine在Scope中查询这个变量,如果发现就分配它。

所以思考事情的最好的方式是:

所有的声明declarations,包括变量和函数,被首先处理processed。在你的代码被执行executed前。

var a = 2; 其实是2个statements: var a;和a = 2;

var a 是声明,在编译阶段被处理;

a = 2是assignment, 会留在执行阶段execution phase处理。

所以,前2个例子就可以理解了:

//第一个例子:
var a;
a = 2;
console.log(a);   // 2

//第二个例子:
var a;
console.log(a);  //undefined
a = 2;

结论:先有蛋(declarations),后有?? assignment.

  1. 只有声明自身会被hoisted!!
  2. 另外, hoisting是per-scope,只在声明所在的作用域内hoisting它。
  3. 函数表达式不是声明!!所以不会hoisting它!
  1. foo(); // not ReferenceError, but TypeError!
    var foo = function bar() {
        // ...
    };Uncaught TypeError: foo is not a function
    
    解释:var foo被提升hoisting,但它没有value。使用foo(),就是认为foo的值是函数,用()执行函数。typeof foo //undefined所有,提示?,foo不是一个函数,不能使用()!(表达式和声明的区分见第三章,Function as Scope)

另一个例子:

foo(); // TypeError ,foo is not a function
bar(); // ReferenceError, (bar是函数,但是)bar is not defined

var foo = function bar() {
    // ...
};

等同于:
var foo;

foo(); // TypeError
bar(); // ReferenceError

foo = function() {
	var bar = ...self...
	// 证明作为表达式,bar 只在内部{ .. }被使用
}

Functions First

  • 先函数声明hoisting,再变量声明hoisting。
  • 多重/副本 var声明会被忽略。 但可以重写函数声明。
foo(); // 3

function foo() {          //hoisting ,第一行
    console.log( 1 );
}

var foo = function() {         //多重var声明,被忽略,不会hoisting。
    console.log( 2 );       //这里重写了foo函数。
};

function foo() {          //hoisting,第二行    
    console.log( 3 );
}
foo()   //输出2
 

ES7最新版:块内函数声明, 要小心使用!foo没有hoisting到全局作用域!!


Review

var a = 2;其实是2部分,var a 是在编译阶段处理, =2在执行阶段处理

所有声明都首先被处理!在它们执行前!

分配, 甚至分配一个函数表达式,都不会被hoisted!

小心duplicate declarations。尤其是混合了正常的var声明和函数声明,要避免这种使用!

写代码先写声明,是好的习惯!!

You Don't Know JS: Scope & Closures (第4章: Hoisting)

原文地址:https://www.cnblogs.com/chentianwei/p/9739698.html

时间: 2024-10-10 00:16:42

You Don't Know JS: Scope & Closures (第4章: Hoisting)的相关文章

You Don't Know JS: Scope & Closures (第3章: 函数 vs 块作用域)

第二章,作用域由一系列的bubbles组成.每一个都代表了一个container或bucket,装着被声明的identifiers(variables, functions).这些bubbles相互嵌套.这种嵌套是在开发阶段写完的. 什么制造了一个新的bubble? 只是函数吗?其他的JS结构可以创建bubbles of scope吗? Function Vs. Block Scope Scope From Functions 探索函数作用域和它的暗示implications. 函数作用域内的所

You Don't Know JS: Scope & Closures(翻译的试试)

Chapter 1: What is Scope? 第一章:什么是作用域 One of the most fundamental paradigms of nearly all programming languages is the ability to store values in variables, and later retrieve or modify those values. In fact, the ability to store values and pull value

You Don't Know JS: Scope & Closures (附加:Lexical/dynamic作用域)

JavaScript只有Lexical Scope 模式 Lexical Scope就是在写代码的时候,定义函数的时候创建的作用域! 而动态作用域是在runtime时,函数被调用的地方的作用域! 实际上 dynamic Scope是 this关键字的近亲.这会在this & Object Prototypes系列讲解. 第二章,lexical scope是这方面的法则:Engine如何查询一个变量,在哪找到这个变量! 关键特征就是lexical scope是定义在author-time,打代码的

You Don't Know JS: this & Object Prototypes( 第一章 this or That?)

Foreword this 关键字和prototypes 他们是用JS编程的基础.没有他们创建复杂的JS程序是不可能的. 我敢说大量的web developers从没有建立过JS Object,仅仅对待这门语言作为一个事件绑定胶水,在按钮和Ajax请求之间. 我也曾是他们的一员,但是当我了解到如何掌握prototypes并创建JS对象,一个世界的可能性对我打开了. Chapter 1: this Or That? Chapter 2: this All Makes Sense Now! Chap

Practical Node.js (2018版) 第7章:Boosting Node.js and Mongoose

参考:(mongoose和mongodb模块的区别)https://www.jianshu.com/p/87bcf4fdb479 参考: mongoose官网(https://mongoosejs.com/docs/models.html) 参考: 英文:Boosting Node.js和MongoDB with Mongoose 简介:mongoose Mongoose is a fully developed object document mapping (ODM) library for

js 高级编程前三章

1.简单接受js历史 2.介绍js使用 及head  defer  type async 异步等等 3.js基本语法 1.typeof 是操作符 不是函数 ,有五种基本类型 Undefined Null Boolean String Number  一种复杂类型object 2. undefied null 3. true false, js中一切的值都可以转化成 这两个值 4. string  非空字符串 ('')  number  0或者Nan  object 除了null, underfi

JS高级程序设计(1-3章笔记)

第一章    JavaScript简介 1.1    JavaScript简史 1995.02- 公司:Netscape 主要人物:就职于Netscape的Brendan Eich(布兰登.艾奇) 事件:为Netscape Navigator 2开发一种名为LiveScript的脚本语言 1995.02-前夕 公司:Netscape 事件:临时将LiveScript改名为JavaScript 1995.02+ JavaScript1.0获得巨大成功 1996.08 公司:微软 IE3加入名为JS

JS 入门经典 第三章 判断、循环和函数

1.比较运算符 在所有的比较运算符中,==和!=的优先级最低,而>.<.<=.>=则具有相同的优先级 所有的比较运算度的优先级都比算数运算符要低,所以先执行算数运算符,在执行比较运算符. 2.字符串的比较 JS将按照顺序依次的比较左右两边的字符串在同一位置的字符,以检查两个字符是否相等,一旦遇到不等的情况,就停止比较并且返回false.JS中字符串的比较是区分大小写的 3.一般使用整数作为循环计数器的. 4.for...in循环语句主要用于数组类型和对象类型的数据.它的特点是:可以

JS中作用域和变量提升(hoisting)的深入理解

作用域(Scoping) javascript作用域之所以迷惑,是因为它程序语法本身长的像C家族的语言.我对作用域的理解是只会对某个范围产生作用,而不会对外产生影响的封闭空间.在这样的一些空间里,外部不能访问内部变量,但内部可以访问外部变量. c语言的变量分为全局变量和局部变量,全局变量的作用范围是任何文件和函数访问(当然,对于非变量定义的其他c文件,需要使用extern关键字进行申明,使用static关键字也可以将作用范围限定在当前文件中),局部变量的作用范围就是从申明到最近的大括号涵盖的块级