JavaScript预编译

2018-12-06  本文已影响0人  景色分明丶

JavaScript预编译,你不知道的JavaScript

隐式类型转换

// + , - , * , / , %    数学运算隐式转换number的值( + 与字符串做运算相当于连接符)
false           隐式转换为 0
null            隐式转换为 0
""," "         做减、乘、除、模运算隐式转为 0
undefined       隐式转换为 NaN
"123"           数字字符串做减、乘、除、模运算隐式转为相应数字(123)
"123abc"        非数字字符串做减、乘、除、模运算隐式转为 NaN

//!,!!...  隐式转换为boolean
!undefined       //true
!false          //true
!""            //true
!"   "         //flase
!null         //true
!NaN         //true

var a = "  ";       //true
var a = undefined;  //false
var a = null;       //false
var a = "";         //false
var a = NaN;        //false
var a = "aa";       //true
if(a){    //if括号内隐式转换为boolean
    document.write("true");
}else{
    document.write("false");
}

//==,=== 

typeof

  typeof 用来校验变量的类型,返回一个字符串。比如:

    typeof(NaN)     //"number"   也可以这么写:  typeof NaN

全局作用域

全局作用域 == window

局部作用域

一般指 function 函数内部

公式

1、创建AO对象(Activation Object)执行期上下文
2、找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
3、将实参值和形参值统一
4、在函数体里面找函数声明,值赋予函数体

练习

function fun(a) {
    console.log(a);
    var a =123;
    console.log(a);
    function a(){}
    console.log(a);
    var b = function(){}
    console.log(b);
    function c(){} 
}
fun(1);

套公式

第一步、第二步、第三步
AO{
    a:undefined,
    b:undefined,
    c:undefined
}
第四步
AO{
    a:function a(){},      
    b:function (){},
    c:function c(){}
}
预编译完成,开始执行
console.log(a)     //function a(){}
console.log(a)     //123
console.log(a)     //123
console.log(b)     //function(){}

校验

运行控制台显示结果为:

运行结果

想一想

a=100;
function demo(e){
    function e(){}
    arguments[0]=2;
    console.log(e);
    if(a){
        var b = 123;
    }
    a=10;
    var a;
    console.log(b);
    f = 123;
    console.log(a);
}
var a;
demo(1);
console.log(a);
console.log(f);

打印的结果是什么呢?

作用域与作用域链

[[scope]]:每个javascript函数都是一个对象,对象中有些属性,我们可以访问,有些属性我们不可以,这些属性仅供javascript引擎存取,[[scope]]就是其中一个。
[[scope]]指的就是我们所说的作用域,其中存储了运行期上下文的集合。

作用域链[[scope]]中所存储的执行期上下文对象的集合,这个集合呈链式链接,我们把这种链式链接叫做作用域链。

例子:
function  a(){
    function b(){
        var b = 234;
    }
    var a = 123;
    b();
}
var glob = 100;
a();
a被定义过程

套用之前的公式,第一步创建AO对象,因为被定义在全局之中,用GO表示全局AO。

GO{
   a:function a(){},
   glob:100,
   其他全局默认属性
}
a执行过程

a执行时,创建自己的执行期上下文,并将其添加到作用域链顶端。
a执行时,b被定义:


b被定义过程,自动继承a
aAO{
   a:123,
   b:function b(){},
   其他默认属性
}
b执行过程
bAO{
   b:234,
   其他默认属性
}

执行期上下文:当函数执行时,会创建一个执行期上下文的内部对象。一个执行期上下文定义了一个函数执行的环境,函数每次执行时对应的执行上下文都是独一无二的,所以多次调用一个函数会导致创建多个执行上下文,当函数执行完毕,它所产生的执行上下文被销毁

最终:
a defined a.[[scope]]    -->0:GO

a excute  a.[[scope]]    -->0:aAO
                         -->1:GO

b defined b.[[scope]]    -->0:aAO
                         -->1:GO

b excute  b.[[scope]]    -->0:bAO
                         -->1:aAO
                         -->2:GO

javascript引擎查找变量的时候都是从作用域链的最顶端开始向下查找。

闭包

function  a(){
    var num = 100;
    function b(){
        num++;
        console.log(num);
    }
    return b;
}
var demo = a();
demo();
demo();

运行控制台显示结果为:

运行结果
通过之前的叙述,我们知道函数执行完毕,它所产生的执行上下文被销毁(其实是底层的垃圾回收机制来实现)。上面这个函数可以这么去理解,当a函数执行时,b被定义,并将其引用给demo,因为b自动拥有a的作用域。所以,可以说是a执行时的上下文已经销毁,但b中人保留a的副本,所以当调用demo时,仍然可以通过作用域链访问num。

具体原理将会在下一篇中进行介绍。

上一篇 下一篇

猜你喜欢

热点阅读