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();

套用之前的公式,第一步创建AO对象,因为被定义在全局之中,用GO表示全局AO。
GO{
a:function a(){},
glob:100,
其他全局默认属性
}

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

aAO{
a:123,
b:function 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。
具体原理将会在下一篇中进行介绍。