1

公众号:朝霞的光影笔记 ID:zhaoxiajingjing

公众号:朝霞的光影笔记 ID:zhaoxiajingjing

0 / 变量提升处理机制

变量提升:在当前上下文中(全局/私有/块级),JS代码自上而下执行之前,浏览器会处理一些事情(可以理解为词法解析的一个环节,词法解析一定是发生在代码执行之前的):

会把当前上下文中所有带var/function关键字的进行提前声明或者定义

var a = 10;

① 声明 declare:var a;

② 定义 defined:a = 10;

带VAR的只提前声明

带FUNCTION的会提前声明+定义

函数名就是变量名,函数是对象数据类型的需要堆内存存储

现在代码基本都用ES6语法的let/const写了,所以var的变量提升会少很多。声明函数也尽量使用函数表达式来写,这样可以规避掉直接使用function声明函数的而产生的变量提升

1 / 练习题目

(1)var的变量提升
/*
EC(G) 全局执行上下文
VO(G) 变量对象
     var a;  默认值是undefined
 -----
 代码执行:
 */
console.log(a); //=> undefined
var a = 12; //=> 创建12,a=12 赋值(声明在变量提升阶段完成了,浏览器懒得不会做重复的事情)
a = 11; //=> 全局变量 a = 11;
console.log(a); //=> 11

△ 变量提升

数据类型:

① 基本数据类型(string/number/boolean/null/undefined/symbol/bigin)

② 对象数据类型(object/functioin)

① 基本数据类型值:直接存储在栈内存中

② 对象数据类型值:由于数据类型比较复杂,存储在堆内存中,把堆内存的16进制地址放到栈内存中与变量关联起来

(2)function 的变量提升
/*
EC(G) 全局执行上下文
VO(G) 变量对象
       fn = 0x000001堆内存地址[声明+定义]
 -----
 代码执行:
 */
fn(); //=> 函数执行的结果:输出"hello"
function fn(){
    var a = 12;
    console.log('hello');
}

△ 函数

项目开发中推荐:函数表达式 var fn = function (){};

这样,在变量提升阶段只会声明变量,不会赋值

函数表达式
fn(); //=> Uncaught TypeError: fn is not a function
// 报错后面的代码就不执行了
var fn = function (){
    // 函数表达式:在变量提升阶段只会声明fn,不会赋值了
    console.log('hello');
};
fn();

△ 函数表达式

匿名函数具名化
var fn = function AA(){
    console.log('hello');
};
AA(); //=> Uncaught ReferenceError: AA is not defined

△ 匿名函数具名化

var fn = function AA(){
    console.log('hello');
    console.log(AA); //=> 输出当前函数体
};
fn();

△ 匿名函数具名化

把原本作为值的函数表达式的匿名函数“具名化”:

① 这个名字不能在函数体外部访问,也就是不会出现在当前上下文中

② 函数执行时,形成私有上下文,会把这个“具名化”的名字作为该上下文中的私有变量(它的值就是这个函数体)来处理

③ 在函数体内部不能修改这个名字的值,除非是重新声明这个变量

(3)不带var的
/*
EC(G) 全局执行上下文
VO(G) 变量对象

-----
代码执行:
 */
console.log('ok'); //=> 'ok'
//=> 没有写VAR/FUNCTION的,不能在定义前使用
console.log(a); //=> Uncaught ReferenceError: a is not defined
a=12;
console.log(a);

△ 不带var的

(4)带let的
/*
EC(G) 全局执行上下文
VO(G) 变量对象

-----
代码执行:
 */
console.log('ok'); //=> 'ok'
//=>LET/CONST 没有变量提升
console.log(a); //=> Uncaught ReferenceError: a is not defined
let a = 12;
a = 13;
console.log(a);

△ 带LET的

(5)在全局上下文的映射

基于VAR/FUNCTION在 <u>全局上下文EC(G)</u> 中声明的变量(全局变量)会“<u>映射</u>”到 <u>GO(window 全局对象)</u> 上一份,作为它的属性;而且一个修改另外一个也会跟着修改

var a = 12;
console.log(a); //=> 12 全局变量
console.log(window.a); //=> 12 映射到GO上的属性

window.a = 11;
console.log(a); //=> 11 映射机制:一个修改另一个也会修改

△ 全局上下文的映射机制

2 / 变量提升的题目

fn(); 
function fn(){ console.log(1); } 
fn();
function fn(){ console.log(2); }
fn();
var fn = function(){ console.log(3); }
fn();
function fn(){ console.log(4); }
fn();
function fn(){ console.log(5); }
fn();

△ 答案是?

/** 
 * EC(G)全局执行上下文
 * VO(G) 变量对象
 *     fn = 0x0000001=>log1
 *         = 0x0000002=>log2
 *       = 0x0000003=>log4
 *         = 0x0000004=>log5
 *  【var fn; 变量已经声明过了,不会再重复执行了】
 * --------
 * 代码执行:
 */
fn(); //=>5
function fn(){ console.log(1); }  //=>不再处理,变量提升阶段搞过了
fn(); //=>5
function fn(){ console.log(2); }
fn(); //=>5
var fn = function(){ console.log(3); }  //=>var fn不用在处理了,但是赋值在变量提升阶段没处理过,此处需要处理  fn=window.fn=>3
fn(); //=>3
function fn(){ console.log(4); }
fn(); //=>3
function fn(){ console.log(5); }
fn(); //=>3

△ 变量提升

var foo = 1;
function bar() {
    if (!foo) {
        var foo = 10;
    }
    console.log(foo);
}
bar();

△ 答案是?

公众号:朝霞的光影笔记 ID:zhaoxiajingjing

△ 图1.1_不论判断条件是否成立:var都会变量提升;function的要复杂一些,后面再说~

- end -

公众号:朝霞的光影笔记 ID:zhaoxiajingjing


Pink
269 声望14 粉丝

没有什么是20遍解决不了的,如果有~那就再写20遍