写在前面:执行上下文创建阶段,其中一个过程是,创建作用域,接下来就简单谈谈我对作用域的理解。
目录
一、基本概念
定义:程序中定义变量的区域,它决定了当前执行代码对变量的访问权限。
产生:代码定义的时候
作用域链:当前作用域没有到上层作用域查找
作用域包括:全局作用域,局部作用域(即,函数作用域,块级作用域) ❗没有对象作用域
//注意和闭包区分👇
function fun(){
var num=123;
var a='aa';
function fun2(){
console.log(num);
}
fun2();
}
fun(); //输出:123
除此以外,还接触到了词法作用域,块级作用域的概念 👇
二、词法作用域
定义:意味着函数被定义的时候,它的作用域就已经确定了,和拿到哪里执行没有关系,因此词法作用域也被称为 “静态作用域”。
//🍕面试题
var x=10;
function f(){
console.log(x);
}
function show(f){
var x=20;
f()
}
show(f); //10 三个作用域(两个函数作用域并列) 若当前作用域没有到上层作用域查找
过程分析:
三个作用域:全局作用域,f
函数作用域,show
函数作用域
f
里访问了本地作用域中没有的变量 x
。根据前面说的,引擎为了拿到这个变量就要去 f
的上层作用域查询,那么 f
的上层作用域是什么呢?是它 调用时 所在的 show
作用域?还是它 定义时 所在的全局作用域?
这里就需要用词法作用域解释了,函数作用域在定义时被创建,和调用没有关系。
三、块级作用域
定义:任何一对花括号{}
中的语句都属于一个块级作用域,{}
中的所有变量在代码块外都是不可见的。
1.块级作用域与变量声明
在ES6之前,我们都是用var来声明变量,而且JS只有函数作用域和全局作用域,没有块级作用域,所以{}限定不了var声明变量的访问范围。ES6新增的let,可以声明块级作用域的变量。
// var定义变量
if(true){
var x = 0;
}
console.log(x); //0
// let定义变量
if(true){
let x = 0;
}
console.log(x); //报错
var, let 关于块级作用域的场景
//var定义变量
for(var i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i);
}, 0);
}
//结果:3,3,3
//let定义变量
for(let i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i);
}, 0);
}
//结果:0,1,2
我们知道函数调用完后,变量会被销毁,我们可以用这个特性来模拟出var的块级作用域
for(var i = 0; i < 3; i++) {
(function(i){
setTimeout(function() {
console.log(i);
}, 0);
}) (i)
}
//结果:0,1,2
2.块级作用域与函数声明
除了块级作用域与变量声明的问题,还发现对于函数声明
console.log(a) //function a(){ return 1}
console.log(b) //undefined
function a(){ return 1}
if(true){
function b(){ return 1}
}
👉【ES6】关于var, let和const的区别_Chailo的博客-CSDN博客
🍕 最后整理的面试题
//🍕面试题1
var fn = function(){
console.log(fn);
}
fn(); //function
//🍕面试题2 ❗ ❗ ❗
var obj = {
fn2:function(){
console.log(fn2);
}
}
obj.fn2(); //报错fn2 is not defined 两个作用域 全局和函数(对象作用域错❌)
//🍕面试题3 ❗ ❗ ❗
var obj = {
fn2:function(){
console.log(obj.fn2);//=console.log(this.fn2); this-->obj
}
}
obj.fn2(); //function