JS----预编译(执行环境)
JavaScript 的执行环境
参考学习:https://blog.csdn.net/zwkkkk1/article/details/79766224#commentBox
JS执行顺序-函数声明提升、匿名函数、函数表达式
参考学习:https://www.cnblogs.com/can-i-do/p/8574450.html
JavaScript关于作用域、作用域链和闭包的理解:
参考学习:https://blog.csdn.net/whd526/article/details/70990994
声明的顺序是这样的:
1. 找到所有的函数声明,初始化函数体,如有同名的函数则会进行覆盖
2. 查找变量声明,初始化为undefined,如果已经存在同名的变量,就什么也不做直接略过
1.脚本执行js引擎都做了什么呢?
语法分析 很简单,就是引擎检查你的代码有没有什么低级的语法错误
预编译 简单理解就是在内存中开辟一些空间,存放一些变量与函数
解释执行 顾名思义便是执行代码
2.声明式函数 赋值型函数 匿名函数 自执行函数
声明式函数 和 赋值型函数
声明函数与赋值函数的区别在于: 在 JS 的预编译期间,声明式函数会被先提取出来,
然后才按照顺序执行 JS代码。
1 声明式:
A(); // 'A ' function A() { console.log('A'); }
2.赋值型:
B(); // error, B is not a function var B = function() { console.log('B'); }
3.匿名函数
没有名字的函数就是匿名函数。
function() {} // 匿名函数
4.自执行函数
(function() {
console.log(3);
})();
3.有关代码块script
代码块相互独立,变量和方法共享
代码块内出错依旧继续执行
JS引擎是按代码块顺序执行的(无法预处理)
4.函数
1.都是函数声明(后来居上)
f(); // 我是函数声明2
function f() {
console.log('我是函数声明1');
}
function f() {
console.log('我是函数声明2');
}
2.函数声明提前于赋值函数
f(); // 我是函数声明
function f() {
console.log('我是函数声明');
}
var f = function() {
console.log('我是赋值型函数');
}
3.函数声明提升优先级大于 变量声明,函数声明覆盖 变量声明
console.log(f); // Function
function f() {
console.log(1);
}
var f = 3;
例题(声明式函数和赋值性函数):
var getName = function(){
console.log(2);
}
function getName (){
console.log(1);
}
getName(); //结果为2
=====================================
function getName (){
console.log(1);
}
var getName = function(){
console.log(2);
}
getName(); // 结果为2
=====================================
getName(); //结果为 1
function getName() {
console.log(1);
}
var getName = function() {
console.log(2);
}
5.执行环境
执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。每个执行环境都有一个与之关联的变量对象(variableobject,一般简写为VO),环境中定义的所有变量和函数都保存在这个对象中。虽然我们编写的代码无法访问这个对象,但解析器在处理数据时会在后台使用它。
6.预编译(函数执行前)
- 创建AO对象(Active Object)
- 查找函数形参及函数内变量声明,形参名及变量名作为AO对象的属性,值为undefined
- 实参形参相统一,实参值赋给形参
- 查找函数声明,函数名作为AO对象的属性,值为函数引用
7.预编译(脚本代码块script执行前)
- 查找全局变量声明(包括隐式全局变量声明,省略var声明),变量名作全局对象的属性,值为undefined
- 查找函数声明,函数名作为全局对象的属性,值为函数引用
8.变量对象 活动对象
参考学习:http://www.cnblogs.com/hezhi/p/10053025.html
https://www.qdfuns.com/article/13446/3510a52e53e9d43b1159f521a5832816.html
变量对象:每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。
活动对象:在函数执行环境中,VO 是不能直接访问的,则将其活动对象(activation object)作为变量对象。
当一段 JavaScript 代码运行时,解释器(编译器)会创建执行环境,这里会有两个阶段:
创建阶段(编译阶段,当函数被调用,但是开始执行函数内部代码之前)
创建 Scope chain
创建 VO / AO
设置 this 的值
代码执行阶段
设置变量的值、
函数的引用,
然后解释、执行代码
对于创建 VO / AO,JavaScript 编译器主要做了下面的事:
根据函数的参数,创建并初始化 arguments对象
扫描函数内部代码,查找函数声明(Function declaration)
对于所有找到的函数声明,将函数名和函数引用存入 VO / AO 中
如果 VO / AO 中已经有同名的函数(变量),那么就进行覆盖
扫描函数内部代码,查找变量声明(Variable declaration)
对于所有找到的变量声明,将变量名存入VO/AO中,并初始化为"undefined"
如果变量名称跟已经声明的形参或函数相同,则变量声明不会干扰已经存在的这类属性
=====================================
全局变量对象
var foo = 10;
function bar() {} // // 函数声明
(function baz() {}); // 函数表达式
console.log(
this.foo == foo, // true
window.bar == bar // true
);
console.log(baz); // 引用错误,baz没有被定义
全局上下文中的变量对象(VO)会有如下属性:
全局变量对象
活动对象:
function foo(x, y) {
var z = 30;
function bar() {} // 函数声明
(function baz() {}); // 函数表达式
}
foo(10, 20);
“foo”函数上下文的下一个激活对象(AO)如下图所示:
活动对象