作用域

2019-08-10  本文已影响0人  kim_jin

了解JavaScript的机制

我们学习作用域的方法是将这个过程模拟成几个人之间的对话,那么我们先看一下都有谁参与到了这个对话:

演员表

引擎:从头到尾负责整个JavaScript的编译和执行的过程
编译器:引擎的好朋友之一,主要的工作是语法的分析和代码的生成
作用域:引擎的另外一位好朋友,负责收集并且维护所有声明的标识符进而组成一系列的查询,并执行一非常严格的规则,确定当前执行的代码的这些标识符的访问权限。

对话

当我们看到var a = 2;这段程序的时候,很可能认为这是一句声明的语句。但是在引擎的眼中,这个是两个过程:一个由编译器在编译的时候处理,另外的一个是引擎在执行的时候处理。
我们仔细的看一下这段代码在底层究竟是如何实现的:

函数作用域

在任意的代码片段外添加包装函数,可以将内部的变量和函数定义隐藏起来,导致外部是没有办法访问内部的任何内容的。

var  a = 2;
foo = ()=>{ // <--添加了这一行
  var a = 3;
  console.log(a); //3
}// <--添加了这一行
foo();// <--添加了这一行
console.log(a) // 2

这个技术解决了一写问题,但是还是有一点不理想,因为会导致一些其他的问题,因为这么做应该先声明一个具名函数foo(),但是这个foo()污染了全局作用域,其次,还是需要显示的调用才可以,但是我们期望可以不用使用函数名,并且可以自行运行,这样就更加理想了。

var a = 2;
(()=>{ // <--添加了这一行
  var a = 3;
  console.log(a); // 3
})()  // <--添加了这一行

console.log(a) // 2

匿名和具名

对于函数表达式最熟悉的场景就是毁掉参数,举个例子:

setTimeout(()=>{
  console.log("I waited 1 second")
})

上面的就是匿名函数表达式,因为function()..没有名称标识符,函数表达式是可以匿名的,然而函数表达式是不可以忽略函数名的-- 在JavaScript中是违法的。
匿名函数的缺点:

立即执行函数表达式

var a = 2;
(foo =()=>{
  var a = 3;
  console.log(a); // 3
})();

console.log(a); // 2

上面的函数被包含在一个括号的内部,因此形成了一个表达式,然后在结尾还添加了一个(),可以来立即执行这个函数,比如(foo=()={..})()
立即执行函数表达式的进阶使用方法:就是你把他们当做函数调用并传递参数进去。

var a = 2;
(function foo(global){
  var a = 3;
  console.log(a); // 3
  console.log(global.a); // 2
})(window);

console.log(a); // 2

我们将window对象的引用传递进去,并将其命名为global,因此在代码风格上对全局对象的引用变得比引用一个没有全局字样的变量更加清楚啦。这个模式的另外的一个应用场景就是解决undefined标识符的默认值被错误覆盖导致异常的情况。比如说:我们将一个参数命名成undefined,但是在对应的位置不传入任何的值,这样就可以保证在代码块中的undefined标识符的值就是undefined

undefined = true; // 这样做对其他的代码是不好的,一定不要这么做
(foo= (undefined)=>{
  var a ;
  if(a ===undefined){
    console.log('undefined is safe here');
  }
})();

任何的声明在某个作用域内的变量,都将依附于这个作用域。

a = 2;
var a;
console.log(a); // 2

// ===> 等价于
var a; // 进行编译
a = 2; // 执行的时候进行赋值
console.log(a)
console.log(a); // undefined
var a = 2;

导致上面的结果很简单,声明本身会被提升,提升到最开始,然而赋值或是其他的运行逻辑,会被留在原地。注意一下,我们在进行状态提升的时候会先提升函数的状态,其次才是函数的状态。

foo(); // 1
var foo;
function foo(){
  console.log(1);
}
 foo = function(){
  console.log(2)
}

因为对于上面的代码,JavaScript的引擎是这样进行理解的:

function foo(){
  console.log(1);
}
foo();
 foo = function(){
  console.log(2)
}
上一篇 下一篇

猜你喜欢

热点阅读