你不知道的javascript(二)

1.词法作用域

        就是定义在词法阶段的作用域,作用域查找会在找到第一个匹配的标识符时停止。在多层的嵌套作用域中可以定义同名的标识 符,这叫作“遮蔽效应”(内部的标识符“遮蔽”了外部的标识符)。抛开遮蔽效应,作用域查找始终从 运行时所处的最内部作用域开始,逐级向外或者说向上进行,直到遇见第一个匹配的标识符为止。

全局变量会自动成为全局对象(比如浏览器中的window对象)的属性,因此可以不直接通 过全局对象的词法名称,而是间接地通过对全局对象属性的引用来对其进行访问。如:window.a通过这种技术可以访问那些被同名变量所遮蔽的全局变量。但非全局的变量如果被遮蔽了,无 论如何都无法被访问到。无论函数在哪里被调用,也无论它如何被调用,它的词法作用域都只由函数被声明时所处的位置决定。
2.欺骗词法

function foo(str,a){
   eval(str);
   console.log(a,b);
}
var b=2;
foo('var b=3;',1);//1,3
eval(...)经常被用来执行动态创建的代码。

调用中的‘var b=3;’,这段代码会被当做本来就在那里一样来处理,由于那段代码声明了 一个新的变量b,因此它对已经存在的foo(..)的词法作用域进行了修改。事实上,和前面提到的原 理一样,这段代码实际上在foo(..)内部创建了一个变量b,并遮蔽了外部(全局)作用域中的同名 变量。
当console.log(..)被执行时,会在foo(..)的内部同时找到a和b,但是永远也无法找到外部的b。因 此会输出“1,3”而不是正常情况下会输出的“1, 2”。

but ....

function foo(str){
    'use strict';
    eval(str);
    console.log(a);//a is not defined
}
foo('var a=2');
在严格模式下,它就挣脱不了了。

with()通常被当作重复引用同一个对象中的多个属性的快捷方式,可以不需要重复引用对象本身。

var obj = {
       		a:1,
       		b:2,
       		c:3
       };
       //这样重复比较单调
       obj.a = 2;
       obj.b = 3;
       obj.c = 4;
       //快捷方式
       with(obj){
       	 a = 2;
       	 b = 3;
       	 c = 4;
       }
function foo(obj){
       	  with(obj){
       	  	 a = 2;
       	  }
       }
       var o1={
       	   a:3;
       }
       var o2={
       	   b:3;
       }
       foo(o1);
       console.log(o1.a)//2
       foo(o2);
       console.log(a2.a);//undefined
       console.log(a);//2  a被泄露到全局作用域上了


尽管with块可以将一个对象处理为词法作用域,但是这个块内部正常的var声明并不会被 限制在这个块的作用域中,而是被添加到with所处的函数作用域中。

o2的作用域、foo(..)的作用域和全局作用域中都没有找到标识符a,因此当a =2执行时,自动创建 了一个全局变量(因为是非严格模式)。

词法作用域意味着作用域是由书写代码时函数声明的位置来决定的。编译的词法分析阶段基本能 够知道全部标识符在哪里以及是如何声明的,从而能够预测在执行过程中如何对它们进行查找。 



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值