js 变量提升 函数提升 作用域

再说这个知识点前,我们先了解下javascript语言的本质。简单来说js是一个脚本语言,是介于标记语言(例html中使用的标签<.. /> 等是一种被动的,被用来浏览\显示的,无行动能力)与编程语言(具有逻辑性和行为能力,这是主动的)之间,特点是不需要编译,可以直接书写,但依赖解释器来负责解释执行。

js代码解析原则

js引擎首先在读取js代码时默认执行2个步骤:
1.解释(通篇扫描所有js代码,然后把所有声明(变量申明、函数声明)提升到对应作用域顶端)
2.执行(执行逻辑操作)


下面还是通过代码实例来看,运行本质吧:

变量提升

1.
console.log(b)
b=2; //输出 ReferenceError: b is not defined
例2.
console.log(b)
var b=2; //输出 undefined
----------
可以直观的发现例1、例2区别就是因为一个没有用var申明变量,导致不同的输出。
js引擎在解释的时候,例2相当于:
 var b;
 console.log(b);//由于未赋值 输出undefined 
 b=2; 
而针对例1而言,不会改变代码顺序,遇到b时,b还没被申明,只能输出b is not defined。

函数提升

首先要知道函数定义有两种方式的,一种是函数定义表达式,一种是函数声明语句。
//函数定义表达式 
var f = function (){ 
... 
}; 
//函数声明语句 
function f(){ 
 ... 
}
重点:函数提升针对是函数声明语句而言,其次变量提升只提升变量名而函数提升会提升整个函数体。
----------
例1.
f();
function f(){
  console.log("fffff");
} 
//输出 fffff2.
f();
var f=function(){
  console.log("fffff");
} 
//输出 TypeError f is not a function
----------
为什么例1正确执行呢,其原因就是函数提升,在js引擎解释的时,相当于:
function f(){
  console.log("fffff");
} 
f();//正确执行函数,输出fffff
而例2则相当于:
var f;
console.log(f); //undefined
f();//f不是一个函数 f is not a function
f=function(){
  console.log("fffff");
}  
----------
再来看看例3
console.log(f);
var f=10;
console.log(f);
function f(){
   console.log('fff');
 }
console.log(f);
输出:
ƒ f(){
   console.log('fff');
 }
10
10
这个例子就考察了一个优先级问题,函数提升会在变量提升的上面,在js引擎解释的时候就相当于:
function f(){
   console.log('fff');
 }
 var f;
 console.log(f);
 //ƒ f(){
   console.log('fff');
f=10
console.log(f);// 10
console.log(f);// 10

作用域

es5中只有全局作用域和函数作用域,es6新增了块级作用域。
var v = "hello";
if(true){
  console.log(v);
  var v = "world";
}
//输出 hello 说明es5是没有块级作用域
es6对块级作用域的支持
let n = 5;
if (true) {
    let n = 10;
 }
console.log(n); // 5
----------
es5中:
var v = "hello";
(function(){
  console.log(v);
  var v= "world";
})()
//输出 undefined 
原因函数作用域变量v遮盖了上层作用域变量v,再加上变量提升,相当于:
var v = "hello";
(function(){
  var v;
  console.log(v);// undefined
  v = "world";
})()
----------
es6允许块级作用域的任意嵌套。外层作用域无法读取内层作用域的变量。内层作用域可以定义外层作用域的同名变量。
{{
  {let insane = 'Hello World'}
  console.log(insane); //ReferenceError: insane is not defined
}};
{{
 let insane = 'Hello World';
  {let insane = 'Hello World';}
}};
----------
es6也规定,函数本身的作用域,在其所在的块级作用域之内。
function f() { console.log('I am outside!'); }
(function () {
  if(false) {
    // 重复声明一次函数f
    function f() { console.log('I am inside!'); }
  }
  f();   
}())
上面代码在es5中运行,输出 I am inside!,但是在es6中运行,会输出I am outside!。这是因为es5存在函数提升,不管会不会进入 if代码块,函数声明都会提升到当前作用域的顶部,得到执行;而es6支持块级作用域,不管会不会进入if代码块作用域,其内部声明的函数皆不会影响到作用域的外部。
----------
块级作用域外部,无法调用块级作用域内部定义的函数。
if(1==2){
  let a = 'secret';
  function f() {
    return a;
  }
}
f()//TypeError: f is not a function
----------
块级作用域内letconst命令所声明的变量,只在命令所在的代码块内有效。
if(true){
  let a = 10;
  var b = 1;
}
console.log(a)//ReferenceError: a is not defined.
console.log(b)// 1

猜你喜欢

转载自blog.csdn.net/u012982629/article/details/80515328