作用域:
简单来说作用域就是一个变量可用的范围
作用域有以下三种
1. 全局作用域
在最外层定义的变量或者方法,全局都可以使用,所以是全局作用域。
2. 函数作用域(局部作用域)
js中可以通过函数来创建一个独立作用域称为函数作用域,函数可以嵌套,所以作用域也可以嵌套;
3. ES6新增的块级作用域
声明变量的方法 有var let const
var 声明的变量可以全局使用,存在变量提升,可以重新赋值
let 声明的变量只能在当前作用域内使用
const 声明的是常量,只能在当前作用域中使用
let/const声明的变量让当前代码块变成一个暂时性的死区
他们声明的变量不存在变量提升,在同一作用域内不能重新赋值
区别: const声明的变量必须给默认值 const声明的是常量不能重新赋值
const声明的变量的值如果是引用数据类型 则数据内部的数据可以修改
自由变量
假如在全局中定义了变量a,在函数中使用了这个a,这个a就是自由变量,可以这样理解,凡是跨了自己的作用域的变量都叫自由变量
作用域链
作用域链:由多级作用域连续引用形成的链式结果
掌管一切变量的使用顺序: 先在局部找,没有,就延作用域向父级作用域找
在JavaScript中,函数也是对象,实际上,JavaScript里一切都是对象。函数对象和其它对象一样,拥有可以通过代码访问的属性和一系列仅供JavaScript引擎访问的内部属性。其中一个内部属性是[[Scope]],该内部属性包含了函数被创建的作用域中对象的集合,这个集合被称为函数的作用域链,它决定了哪些数据能被函数访问。
当一个函数创建后,它实际上保存一个作用域链,并且作用域链会被创建此函数的作用域中可访问的数据对象填充。例如定义下面这样一个函数:
function func() {undefined
var num = 1;
alert(num);
}
func();
在函数func创建时,它的作用域链中会填入一个全局对象,该全局对象包含了所有全局变量,如下图所示(注意:图片只例举了全部变量中的一部分):
执行此函数时会创建一个称为“运行期上下文(execution context)”(有人称为运行环境)的内部对象,运行期上下文定义了函数执行时的环境。每个运行期上下文都有自己的作用域链,用于标识符解析,当运行期上下文被创建时,而它的作用域链初始化为当前运行函数的[[Scope]]所包含的对象。
这些值按照它们出现在函数中的顺序被复制到运行期上下文的作用域链中。它们共同组成了一个新的对象,叫“活动对象(activation object)”,该对象包含了函数的所有局部变量、命名参数、参数集合以及this,然后此对象会被推入作用域链的前端,当运行期上下文被销毁,活动对象也随之销毁。新的作用域链如下图所示:
外部环境不能访问内部环境的任何变量和函数。即可以向上搜索,但不可以向下搜索。
可以理解为什么有关于作用域链的定义说,作用域链是一群对象,或者对象列表(链表)。也有总结如下:
- 对于javascript最顶层的代码(不包含任何函数定义内的代码),其作用域链只包含一个对象:即全局对象。
- 对于不包含嵌套函数的函数,其作用域链包含两个对象:其自身的变量对象和全局变量对象。
- 对于包含了嵌套函数的函数,其作用域包含至少三个对象:自身的变量对象,外层的(将自身嵌套的),全局变量对象。
变量提升
var声明的变量,function声明的函数存在变量提升
let const 不会变量提升
区别: const声明的变量必须给默认值 const声明的是常量不能重新赋值
const声明的变量的值如果是引用数据类型 则数据内部的数据可以修改
举几个例子:
1. javascript中声明并定义一个变量时,会把声明提前,以下会先打印出undefined,再打印出10
console.log(a)
var a = 10
console.log(a)
相当于
var a
console.log(a);//undefined
a = 10
console.log(a) //10
2. 函数声明也是,以下函数相当于把整个fn提到作用域的最上面,所以调用fn时会正常打印jack
fn('jack');//jack
function fn (name){
console.log(name)
}
3. 不过函数表达式不行,以下是一个函数表达式,JavaScript会把var fn提到作用域最上面,没有吧函数提上去,所以会报错。
fn("jack");//报错
var fn = function(name) {
console.log(name);
};
面试:
变量提升面试题
大家可以说一下这个面试题的输出结果为什么,可以在评论区留言
代码如下:
var x = 30;
function test(){
alert(x);
var x = 10;
alert(x);
x=20;
function x(){
};
alert(x);
}
test();
理论:
1.作用域:
作用域就是一个变量可以使用的范围,主要分为全局作用域和局部作用域
全局作用域
在最外层定义的变量就被称为全局变量,全局都可以使用,所以是全局作用域。
函数作用域(局部作用域)
js中可以通过函数来创建一个独立作用域称为函数作用域,函数可以嵌套,所以作用域也可以嵌套
ES6的定义的块级作用域
声明变量的方法 有var let const
var 声明的变量可以全局使用,存在变量提升,可以重新赋值
let 声明的变量只能在当前作用域内使用
const 声明的是常量,只能在当前作用域中使用
let/const声明的变量让当前代码块变成一个暂时性的死区
他们声明的变量不存在变量提升,在同一作用域内不能重新赋值
区别: const声明的变量必须给默认值 const声明的是常量不能重新赋值
const声明的变量的值如果是引用数据类型 则数据内部的数据可以修改
变量提升
var声明的变量,function声明的函数存在变量提升
let const 不会变量提升
区别: const声明的变量必须给默认值 const声明的是常量不能重新赋值
const声明的变量的值如果是引用数据类型 则数据内部的数据可以修改
2.自由变量:
假如在全局中定义了变量a,在函数中使用了这个a,这个a就是自由变量,可以这样理解,凡是跨了自己的作用域的变量都叫自由变量。
3.作用域链
自由变量的向上级作用域一层一层查找,直到找到为止,最高找到全局作用域,就形成了作用域链。