i5ting_ztree_toc: scopeChain

The concept of pre-parsed

What is pre-parsed

js code before execution, interpretation translation of the code, the code can reduce abnormal at the time of execution

Why pre-parsed

Compiled language

Compiled languages: C, C ++, C #, Java ... need a "translator" program to translate source code into binary data (command) then the computer can read into an executable file that is stored will translate well in advance. , direct execution runtime to get results

An interpreted language

Interpreted (script type): JavaScript, SQL, ... in the implementation of the code, there is a translation program to read a code to perform a code read a code, then execute a code.

Why pre-parsed

Code before execution, quick "preview" again, the wrong part of the exposure, you can improve the efficiency of execution as much as possible.

Pre-analytic features

Affirms process completion code portions labeled with the pre-resolved settings variable scope

What is stated

Looking identifier mark, the current environment js execution engine know what things are available

Variables declared

语法:     var 变量名;
目的: 告诉解释器, 有一个名字是一个变量, 在当前环境中可以被使用.

var a; // 申明变量a 值是undefined
var b = 123; // 申明变量b 同时在执行时赋值123;

Affirming upgrade

if('a' in window){
    var a = 123;
}

console.log(a);

// 分析:
//    1.读取所有的代码( 字符串 ). 包含每一个字节, 每一个数据. 但是 "只留意" var
//     2.判断 var 后面紧跟的名字是否被标记. 如果没有, 则标记上. 
//        如果已标记, 则忽略.    表示在当前环境中已经有该变量了.
//     3.读取完毕后, 代码再从头开始, 从上往下, 从左至右一句一句的执行代码.
//        执行 'a' in window. 很显然当前环境中已有变量 a, 所以结果为真.

Declaring functions

Defined function of the form

  • Declarative :

      function func () {
          console.log( '使用声明式定义' );
      }
    
  • Expression type (anonymous functions, literal function, lambda functions) :

      var func = function () {
          console.log( '使用表达式式定义' );
      };
    
      /*也可以带有名字*/
      var func = function fn(){
          console.log('表达式式函数');
      };
    

Characteristics of two forms of defined functions

Is independent of the function declaration statement. No need to add a semicolon. Not embedded in the code expression. Function declarations are independent of code execution. Code when execution section has been completed at statement stage pre-parsing process. Therefore, Affirming the first can be called.

Expression style, is essentially a function expression (literal) assign values ​​to variables, so it is statement.

Note that the function expression that defines the point

var f1 = function f2 () {
    console.log( '带有名字的  函数表达式' );
    console.log( f2 );
};

// 当函数声明语法嵌入表达式环境中, 会自动进行转换, 将转换成函数表达式.
// 1> 引用函数的规则还是使用变量赋值, 所以外部可以使用该名字调用函数.即可以使用f1调用函数
// 2> 函数表达式带有名字, 该名字只允许在函数内部使用. 属于局部作用域. ( IE8 除外 )即f2只能在f2函数内部使用
// 3> 带有名字的函数表达式, 函数的 name 属性即为该名字,即函数的name为f2

What expression

1. The operator expression operand connected.

2. The result of the presence of the code means (not including statements).

var a;        // 声明, 不是语句, 也没有结果
123            // 字面量, 有值, 是表达式. 是常量表达式
a = 123        // 赋值, 有值, 就是被赋值的那个值. 是赋值表达式.

Declaring functions and variables declared at the same time pay attention to the point that appears

Declare a variable, the current environment is to tell the interpreter can use that name.

Statement function is to tell the interpreter, in addition to the use of the name, the name also represents a function body.

After the first var function

var num;
function num(){

}
console.log(num); // 打印函数体

// 先 var num; 后 function num ...
// 首先告知解释器有 名字 num 了
// 后面是函数声明. 由于已经有 num 名字可以使用了, 所以就不再告诉解释器可以使用 num
// 而是直接将 num 与函数结合在起义.

After the first function var

function num(){};
var num;
console.log(num); // 打印函数体

// 先 function num ... 后 var num;
// 一开始已经有 num 了, 而且是函数. 所以后面的 var num; 属于重复声明.

Special case

if ( true ) {
    function foo() {
        console.log( true );
    }
} else {
    function foo() {
        console.log( false );
    }
}
foo();

// 在早期的浏览器中( 2015 年前) 所有的浏览器( 除了火狐 )都是将其解释为声明 : false
// 但是现在的运行结果, 得到: true. 表示 if 起到了作用

/******************************/

if ( true ) {
    function foo1() {
        console.log( true );
    }
} else {
    function foo2() {
        console.log( false );
    }
}
foo1();
// foo2();  大专栏  i5ting_ztree_toc:scopeChain // error: foo2 is not function. 已定义, 但是函数为被指向

// 好比: var foo1 = function foo1 () { ... }

// 虽然这两个函数不是声明, 但是也不能解释成函数表达式. 如果是函数表达式 foo1 与 foo2 只能在函数内部使用.

Lexical scoping

What is the scope

Variables can be used to scope can not be used

js lexical scoping

js lexical scope is based on use of the pre-parsing rules defined variables, and may function to limit the scope js only. Other access can not be defined range. In practice it may be referred to as lexical scoping function scope.

Lexical scoping Features

  1. Code function may be defined scope. Function allows access to external variables not vice versa.

  2. Priority access to internal variables declared within a function, only if there is no external access.

  3. Access rules for all variables, according to pre-parsing rules to access

  4. Js variables in scope chain and the environment when the definition of, nothing to do with execution.

Case

Case 01

var num = 123;
function f1 () {
    console.log( num );
}
function f2 () {
    console.log( num );
    var num = 456;
    f1();
    console.log( num );
}
f2();

1> 读取代码预解析. 得到 num, f1, f2
2> 逐步的执行代码
    1) 赋值 num = 123;   注意 f1 和 f2 由于是函数, 所以也有数据.
    2) 调用 f2.
        进入到函数体内. 相当于做一次预解析. 得到 num. 注意, 此时有内外两个 num
        执行每一句代码
        -> 打印 num. 因为函数内部有声明 num. 所以此时访问的是函数内部的 num. 未赋值, 得到 undefined
        -> 赋值 num = 456
        -> 调用 f1(). 调用函数的规则也是一样. 首先看当前环境中是否有函数的声明. 如果有直接使用. 如果没有, 则在函数外面找, 看是否有函数. 此时在函数 f2 中没有 f1 的声明. 故访问的就是外面的 f1 函数
        -> 跳入 f1 函数中. 又要解析一次. 没有得到任何声明.
        -> 执行打印 num. 当前环境没有声明 num. 故在外面找. 外面的是 123. 所以打印 123. 
            函数调用结束, 回到 f2 中.
        -> 继续执行 f2, 打印 num. 在 f2 的环境中找 num. 打印 456.

Case 02

(function ( a ) {
    console.log( a );
    var a = 10;
    console.log( a );
})( 100 );

拆解
( 函数 ) ( 100 )
第一个圆括号就是将函数变成表达式
后面一个圆括号就是调用该函数

注意: 函数定义参数, 实际上就是在函数最开始的时候, 有一个变量的声明
function ( a ) { ... }
其含义就是, 在已进入函数体, 在所有操作开始之前( 预解析之前 )就有了该变量的声明.

由于已经有了 a 参数的声明. 所以在代码中 var a = 10 是重复声明. 其声明无效.
所以上面的代码, 等价于
var func = function ( a ) {
    console.log( a );            // => 100
    a = 10;
    console.log( a );            // => 10
}
func( 100 );

Case 03

(function ( a ) {
    console.log( a );
    var a = 10;
    console.log( a );
    function a () {
        console.log( a );
    }
    a();
})( 100 );

1> 直接调用
2> 进入到函数中, 已有声明 a 并且其值为 100
3> 在函数内部预解析. 得到 一个结论. 函数声明是两个步骤. 
    1) 让当前环境中, 有变量名 a 可以使用. 但是不需要. 因为已经有 a 的声明了
    2) 让 a 指向函数. 相当于
        var a;
        function a () {}
        ...
4> 开始逐步执行每一句代码
    1) 打印 a. 所以打印函数体
    2) 赋值 a = 10
    3) 打印 a, 打印出 10
    4) 调用 a, a已经被赋值为10,不在是函数体, 所以报错 error: a is not function

The scope chain

In fact, the chain refers to an access rule, the scope chain refers to the scope of access rules

Draw the scope chain rule

1. 将所有的 script 标签作为一条链结构. 标记为 0 级别的链.
2. 将全局范围内, 所有的声明变量名和声明函数名按照代码的顺序标注在 0 级链中.
3. 由于每一个函数都可以构成一个新的作用域链. 所以每一个 0 级链上的函数都延展出 1 级链.
4. 分别在每一个函数中进行上述操作. 将函数中的每一个名字标注在 1 级链中.
5. 每一条 1 级链中如果有函数, 可以再次的延展出 2 级链. 以此类推...

Analysis code execution

1. 根据代码的执行顺序( 从上往下, 从左至右 )在图中标记每一步的变量数据的变化
2. 如果需要访问某个变量. 直接在当前 n 级链上查找变量. 查找无序.
3. 如果找到变量, 直接使用. 如果没有找到变量 在上一级, n - 1 级中查找.
4. 一直找下去, 直至到 0 级链. 如果 0 级链还没有就报错. xxx is not defined.

Classic face questions

var  arr = [ { name: '张三1' }, 
             { name: '张三2' }, 
             { name: '张三3' }, 
             { name: '张三4' } ];

// 利用循环, 添加方法, 在方法中打印 name
for ( var i = 0; i < arr.length; i++) {
    // arr[ i ] 绑定方法
    arr[ i ].sayHello = function () {
        // 打印名字
        console.log( 'name = ' + arr[ i ].name );
    };
}

for ( var i = 0; i < arr.length; i++ ) {
    arr[ i ].sayHello();
}

// 打印结果?

Guess you like

Origin www.cnblogs.com/liuzhongrong/p/12390149.html