JavaScript 之 预编译 作用域,作用域链
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了JavaScript 之 预编译 作用域,作用域链,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含5255字,纯文字阅读大概需要8分钟。
内容图文
![JavaScript 之 预编译 作用域,作用域链](/upload/InfoBanner/zyjiaocheng/841/a48b88d3d8b14755a977bca6b249ddf1.jpg)
test(); //456
function test(){
console.log(456); }; ? console.log(a);? ? ? //undefined var a = 123; 上面四段代码当我们执行前两个的时候报错,浏览器告诉我们 test 和 a 没有被定义,而后两段代码并没有报错,这就是预编译。 在学习预编译的时候我们总是记住一句话:函数声明整体提升,变量? ? 声明提升。也就是说预编译会把整个函数放在最最前面。而变量 声明提升是什么意思呢? var a = 123;其实是变量声明和赋值的两个过程;1)var a;? ? ?2)a = 123;预编译只把声明提升在最前面 ? console.log(a); //undefined var a = 123; ---> var a; console.log(a); //undefined a = 123; -------------------------- test(); //456 function test(){ console.log(456); } ---> funciton test(){ console.log(456); } test(); // 456 但是光记住这两句话并不能解决所有的问题。 看一下下面的 console.log(a); function a(){ } var a = 123; 想一下打印的是什么? 居然是 ? a(){} 再看看下面的更复杂的 console.log(a); function a(a){ var a = 234; var a = function(){
} a(); } var a = 123;
这个打印出来是什么呢? ? a(a){ var a = 234; var a = function(){
} a(); } 这是为什么呢? 下面来讲一下预编译: imply global 暗示全局变量:即任何变量。如果变量未经申明就赋值,此变量就为全局对象(window)所有。 a = 123;如果 var a = b = 123;在函数里a就是函数内部变量,b则是全局变量。 一切声明的全局变量,全是window的属性(window 就是全局的域):var a = 123;-----> window.a = 123; 使用var声明的变量会自动被添加到最接近的环境中。 预编译发生在函数执行的前一刻。 预编译四部曲: 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 d() { } } fun(1); --> 1.生成AO对象 AO{
} 2.找形参和变量声明,将变量和形参名作为AO属性名,值为undefined AO{ a: undefined; b:undefined; } 3.将实参值和形参统一 AO{ a: 1; b:undefined; } 4.在函数体里面找到函数声明,值赋予函数体 AO{ a: function a(){}; b:undefined; d:function(){} } 预编译结束 函数执行 AO就像一个创库一样,函数执行期间里面的仓库也会变化 AO{ a: function a(){}; b:undefined; d:function(){} } function fun(a) { console.log(a);? ? ? // ? a() { } var a = 123; console.log(a);? ? ? //123 function a() { } console.log(a);? ? ? //123 var b = function () { } console.log(b);? ? ? //? () { } function d() { } } -------------------------- function test(){ console.log(b); if(a){ var b = 100; } console.log(b); c = 234; console.log(c); } var a; test(); a = 10; console.log(c);
预编译 全局GO GO{ a:undefined; test:function test(){} } AO{ b:undefined; } ------------ 执行函数 GO{ a:undefined;--->10 test:function test(){} c:234 } AO{ b:undefined; } function test(){ console.log(b); //undefined if(a){ var b = 100; } console.log(b); //undefined c = 234; console.log(c); //234 } var a; test(); a = 10; console.log(c); //234 ? 作用域 作用域链 function test(){}; 我们知道一个函数就像一个房子一样,这个房子形成单独的域,里面能看到外面的,外面的看不到里面的,我们可以把函数生成的空间叫做作用域那这个作用域到底是什么呢? 这个作用域是因函数产生而产生的,每个对象都有属性和方法,函数(function)也是一种特殊的对象,函数可以有test.name test.prototype ...这些是可以访问的 还有一些属性是不可以访问的隐式属性仅供JavaScript引擎处理。 比如[[scope]]:指的就是我们所说的作用域链,其中存储了执行期上下文的集合。 为什么时集合呢?作用域链:是[[scope]]中所存储的执行期上下文的集合,这个集合呈现链式连接,我们把这种连接叫做作用域链。 作用域链本质上是一个指向变量对象的指针列表,他只是引用,但不包含实际变量对象。 test.[[scope]]这里面存的就是作用域。系统会根据内部的原理去定期调用scope。 上面提到了执行期上下文(前面作用域也提到的AO对象就是这个):当函数执行的前一刻的时候,会创建一个称为执行期上下文的内部对象(AO activation object)。一个执行期上下文定义了一个函数执行时的环境 函数每次执行时对应的上下文都是独一无二的 test(); test();一样的函数但是执行期上下文并不相同,所以多次调用一个函数会导致创建多个执行上下文,当函数执行完毕,他所产生的执行上下文会销毁。
看一下下面的例子 function a(){} var glob = 100; a(); ? 当a函数被定义 a.[[scope]]---> 0:GO{} 因为a函数在全局作用域里,所以他的第一位存的时GO 当a执行执行 a.[[scope]]---> 0:AO{} 1:GO{} ---------------------------------------------- function a(){ function b(){ function c(){} c(); } b(); } a(); a defined a.[[scope]] ---> 0 : GO a doing a.[[scope]] ---> 0 : a AO 1 : GO b defined b.[[scope]] ---> 0 : a AO 1 : GO b doing b.[[scope]] ---> 0 : b AO 1 : a AO 2 : GO c defined c.[[scope]] ---> 0 : b AO 1 : a AO 2 : GO b doing c.[[scope]] ---> 0 : c AO 1 : b AO 2 : a AO 3 : GO
内容总结
以上是互联网集市为您收集整理的JavaScript 之 预编译 作用域,作用域链全部内容,希望文章能够帮你解决JavaScript 之 预编译 作用域,作用域链所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。