zl程序教程

您现在的位置是:首页 >  前端

当前栏目

JavaScript的strict模式与with关键字介绍

JavaScript模式 介绍 with 关键字 strict
2023-06-13 09:15:17 时间
2009年12月,ECMAScript发布了ECMAScript5,这距离上一个版本的ECMAScript3标准发布已经整整十年了,其间JavaScript虽然大行于web编程,ECMAScript4却最终因为利益相关的各大厂商和组织在此语言的复杂性(即是否增加大量特性以扩展ECMAScript的功能)上的分歧而夭折,使得ECMAScript新标准的制订大大落后于编程的实践。ECMAScript5在目标上没有那么雄心勃勃,除去新增了对JSON的支持和反射的更全面的控制,一项重要改进就是引入“严格模式”(strictmode)。在此模式下,ECMAScript的语法变得更严格,使得原先许多常见的易致错的代码不再被允许,包括强制变量声明和不允许with语句等。采用这种模式很简单,只要在脚本文件或者函数的首行添加"usestrict";这样一行字符串就可以了。

笔者后知,2010年还曾写了一篇小文讨论with关键字的缺陷,随附如下。
楔子

很久很久以前,神笔马良的家乡为了纪念他要将一条马路以他的名字命名。马良没有推辞,不过提出了四个字的意见。多年以后,一位外地人来到这里,在这条马路上拦住一个当地人问路。

请问这是神马路?

对,这是神马路。

你也不知道吗?

我就是这的人,怎么会不知道。

那这是神马路?

你知道了还问什么。

我就是不知道这是神马路。

那我不是已经告诉你这是神马路了吗?

你能不能再说一遍这是神马路?

……

过后,这个当地人想起当年神笔马良的意见,恍然大悟。马良说的是——勿用简称。

AQuestion

OnedayTomsaidtoWangEr,hisChinesefriend,“Ihaveadream.IwanttoshowmyselfonCCTV.”ThenextdayTombrokeintoaneighborshop.Thepolicedidn"ttakemuchtimetoidentifyandarrestTombecausehewascapturedveryclearlybytheshop"sCCTV.

ThequestioniswhenTomsaidhisdream,heis

A)ambitiousB)notambitiousC)ambiguousD)unambiguous

TherightanswerisB)andC).
正文

以上两个古今中外的例子说明简写有时会引起歧义。这在Javascript中也存在。有时候要反复引用一个名字很长的变量是很麻烦的,比如:

objectWithLongName1.propty1=value1;

objectWithLongName1.propty2=value2;

objectWithLongName1.propty3=value3;

objectWithLongName1.method1();

但是一个清晰的名字对于程序的可读性又是很重要的。所以Javascript提供了with语句。上面的例子可以改写成:
复制代码代码如下:

with(objectWithLongName1){

propty1=value1;

propty2=value2;

propty3=value3;

method1();

}

这样省去不少敲打键盘的功夫,而且程序的结构也变得更加清晰。但是这样的简写引入了歧义,我们如何知道大括号内的名称,哪些是objectWithLongName1的属性和方法,哪些是外部变量和函数。Javascript的解析规则是,先在objectWithLongName1上查找这些名称的属性,如果没有找到,则认为它们是外部变量。用代码说明就是这样:
复制代码代码如下:

if(objectWithLongName1.property1!==undefined){

if(objectWithLongName1.value1!==undefined){

objectWithLongName1.property1=objectWithLongName1.value1;//可能1

}else{

objectWithLongName1.property1=value1;//可能2

}

}else{

if(objectWithLongName1.value1!==undefined){

property1=objectWithLongName1.value1;//可能3

}else{

property1=value1;//可能4

}

}

我们希望的是这四种可能性之一,但是一不小心,程序执行的就会是另外一种可能。而且,这样的写法对于程序的读者来说也非常难解。另一方面,对于Javascript解释器,这种不确定性也影响了语言的性能。

其实只要一个小小的改进,就可以祛除这些缺陷。我们可以在省略了对象的属性前面加上点号,这样就在属性和外部变量之间加上了直观的区分,有不少其他语言就是这样做的。我们最初的例子会变成这样:
复制代码代码如下:
with(objectWithLongName1){

.propty1=value1;

.propty2=value2;

.propty3=value3;

.method1();

}

在Javascript做这样的改进之前,两害相权取其轻,要尽量避免使用with语句。我们仍然可以采用一些变通的方法。
复制代码代码如下:
varo1=objectWithLongName1;

o1.propty1=value1;

o1.propty2=value2;

o1.propty3=value3;

o1.method1();

或者对于这样的情况:

objectWithLongName1.propty1=objectWithLongName2.propty1;

objectWithLongName1.propty2=objectWithLongName2.propty2;

……

objectWithLongName1.propty10=objectWithLongName2.propty10;

可以写成:
复制代码代码如下:
(function(o1,o2,pl){

pl.forEach(function(item){o1[item]=o2[item];});

})(objectWithLongName1,objectWithLongName2,[‘propty1",‘propty2",…,‘propty10"]);