powerpoint2007官方下载免费完整版-componentsseparatedbystring
![启用javascript功能](/uploads/image/0915.jpg)
2023年3月31日发(作者:epub 阅读器)
JavaScript规范
全局命名空间污染与IIFE
总是将代码包裹成一个IIFE(Immediately-InvokedFunctionExpression),用
以创建独立隔绝的定义域。这一举措可防止全局命名空间被污染。
IIFE还可确保你的代码不会轻易被其它全局命名空间里的代码所修改(i.e.第三
方库,window引用,被覆盖的未定义的关键字等等)。
不推荐
=10,
2.y=100;
3.
4.//Declaringvariablesintheglobalscopeisresultinginglobalscope
iablesdeclaredlikethis
5.//veryuncleanandneedsto
beavoided.
(window.x+''+window.y);
复制代码
推荐
1.//WedeclareaIIFEandpassparametersintothefunctionthatwewilluse
fromtheglobalspace
2.(function(log,w,undefined){
3.'usestrict';
4.
=10,
6.y=100;
7.
8.//Willoutput'truetrue'
((w.x===undefined)+''+(w.y===undefined));
10.
11.}(,window));
复制代码
IIFE(立即执行的函数表达式)
无论何时,想要创建一个新的封闭的定义域,那就用IIFE。它不仅避免了干扰,
也使得内存在执行完后立即释放。
所有脚本文件建议都从IIFE开始。
立即执行的函数表达式的执行括号应该写在外包括号内。虽然写在内还是写在外
都是有效的,但写在内使得整个表达式看起来更像一个整体,因此推荐这么做。
不推荐
1.(function(){})();
复制代码
推荐
1.(function(){}());
复制代码
so,用下列写法来格式化你的IIFE代码:
1.(function(){
2.'usestrict';
3.
4.//Codegoeshere
5.
6.}());
复制代码
如果你想引用全局变量或者是外层IIFE的变量,可以通过下列方式传参:
1.(function($,w,d){
2.'usestrict';
3.
4.$(function(){
(electorAll('div').length);
6.});
7.}(jQuery,window,document));
复制代码
严格模式
ECMAScript5严格模式可在整个脚本或独个方法内被激活。它对应不同的
javascript语境会做更加严格的错误检查。严格模式也确保了javascript代码
更加的健壮,运行的也更加快速。
严格模式会阻止使用在未来很可能被引入的预留关键字。
你应该在你的脚本中启用严格模式,最好是在独立的IIFE中应用它。避免在你
的脚本第一行使用它而导致你的所有脚本都启动了严格模式,这有可能会引发一
些第三方类库的问题。
不推荐
1.//Scriptstartshere
2.'usestrict';
3.
4.(function(){
5.
6.//Yourcodestartshere
7.
8.}());
9.推荐
10.
11.(function(){
12.'usestrict';
13.
14.//Yourcodestartshere
15.
16.}());
复制代码
变量声明
总是使用var来声明变量。如不指定var,变量将被隐式地声明为全局变量,
这将对变量难以控制。如果没有声明,变量处于什么定义域就变得不清(可以是
在Document或Window中,也可以很容易地进入本地定义域)。所以,请
总是使用var来声明变量。
采用严格模式带来的好处是,当你手误输入错误的变量名时,它可以通过报错信
息来帮助你定位错误出处。
不推
1.x=10;
2.y=100;
复制代码
推荐
=10,
2.y=100;
复制代码
理解JavaScript的定义域和定义域提升
在JavaScript中变量和方法定义会自动提升到执行之前。JavaScript只有
function级的定义域,而无其他很多编程语言中的块定义域,所以使得你在某
一function内的某语句和循环体中定义了一个变量,此变量可作用于整个
function内,而不仅仅是在此语句或循环体中,因为它们的声明被JavaScript
自动提升了。
我们通过例子来看清楚这到底是怎么一回事:
原function
1.(function(log){
2.'usestrict';
3.
=10;
5.
=i*i;
(b);
9.}
10.
(a===10){
=function(){
(a);
14.};
15.f();
16.}
17.
onx(){
('Mr.X!');
20.}
21.x();
22.
23.}());
复制代码
被JS提升过后
1.(function(log){
2.'usestrict';
3.//Allvariablesusedintheclosurewillbehoistedtothetopofthe
function
,
5.i,
6.b,
7.f;
8.//Allfunctionsintheclosurewillbehoistedtothetop
onx(){
('Mr.X!');
11.}
12.
13.a=10;
14.
16.b=i*i;
(b);
18.}
19.
(a===10){
21.//Functionassignmentswillonlyresultinhoistedvariablesbutthe
functionbodywillnotbehoisted
22.//Onlybyusingarealfunctiondeclarationthewholefunctionwillbe
hoistedwithitsbody
23.f=function(){
(a);
25.};
26.f();
27.}
28.
29.x();
30.
31.}());
复制代码
根据以上提升过程,你是否可理解以下代码?
有效代码
1.(function(log){
2.'usestrict';
3.
=10;
5.
6.i=5;
7.
8.x();
9.
(b);
=i*i;
13.}
14.
(a===10){
16.f=function(){
(a);
18.};
19.f();
20.
;
22.}
23.
onx(){
('Mr.X!');
26.}
27.
28.}());
复制代码
正如你所看到的这段令人充满困惑与误解的代码导致了出人意料的结果。只有良
好的声明习惯,也就是下一章节我们要提到的声明规则,才能尽可能的避免这类
错误风险。
提升声明
为避免上一章节所述的变量和方法定义被自动提升造成误解,把风险降到最低,
我们应该手动地显示地去声明变量与方法。也就是说,所有的变量以及方法,应
当定义在function内的首行。
只用一个var关键字声明,多个变量用逗号隔开。
不推荐
1.(function(log){
2.'usestrict';
3.
=10;
=10;
6.
(vari=0;i<10;i++){
=a*b*i;
9.}
10.
onf(){
12.
13.}
14.
=100;
=function(){
d*d;
18.};
(x());
20.
21.}());
复制代码
推荐
1.(function(log){
2.'usestrict';
3.
=10,
5.b=10,
6.i,
7.c,
8.d,
9.x;
10.
onf(){
12.
13.}
14.
(i=0;i<10;i++){
16.c=a*b*i;
17.}
18.
19.
20.
21.d=100;
22.x=function(){
d*d;
24.};
(x());
26.
27.}());
复制代码
把赋值尽量写在变量申明中。
不推荐
,
2.b,
3.c;
4.
5.a=10;
6.b=10;
7.c=100;
复制代码
推荐
=10,
2.b=10,
3.c=100;
复制代码
总是使用带类型判断的比较判断
总是使用===精确的比较操作符,避免在判断的过程中,由JavaScript的强
制类型转换所造成的困扰。
如果你使用===操作符,那比较的双方必须是同一类型为前提的条件下才会
有效。
如果你想了解更多关于强制类型转换的信息,你可以读一读DmitrySoshnikov
的这篇文章。
在只使用==的情况下,JavaScript所带来的强制类型转换使得判断结果跟踪
变得复杂,下面的例子可以看出这样的结果有多怪了:
1.(function(log){
2.'usestrict';
3.
('0'==0);//true
(''==false);//true
('1'==true);//true
(null==undefined);//true
8.
={
f:function(){
'X';
12.}
13.};
14.
(x=='X');
16.
17.}());
复制代码
明智地使用真假判断
当我们在一个if条件语句中使用变量或表达式时,会做真假判断。if(a==true)
是不同于if(a)的。后者的判断比较特殊,我们称其为真假判断。这种判断会通
过特殊的操作将其转换为true或false,下列表达式统统返回false:false,0,
undefined,null,NaN,''(空字符串).
这种真假判断在我们只求结果而不关心过程的情况下,非常的有帮助。
以下示例展示了真假判断是如何工作的:
1.(function(log){
2.'usestrict';
3.
onlogTruthyFalsy(expr){
(expr){
('truthy');
7.}else{
('falsy');
9.}
10.}
11.
thyFalsy(true);//truthy
thyFalsy(1);//truthy
thyFalsy({});//truthy
thyFalsy([]);//truthy
thyFalsy('0');//truthy
17.
thyFalsy(false);//falsy
thyFalsy(0);//falsy
thyFalsy(undefined);//falsy
thyFalsy(null);//falsy
thyFalsy(NaN);//falsy
thyFalsy('');//falsy
24.
25.}());
复制代码
变量赋值时的逻辑操作
逻辑操作符||和&&也可被用来返回布尔值。如果操作对象为非布尔对象,
那每个表达式将会被自左向右地做真假判断。基于此操作,最终总有一个表达式
被返回回来。这在变量赋值时,是可以用来简化你的代码的。
不推荐
(!x){
(!y){
3.x=1;
4.}else{
5.x=y;
6.}
7.}
复制代码
推荐
1.x=x||y||1;
复制代码
这一小技巧经常用来给方法设定默认的参数。
1.(function(log){
2.'usestrict';
3.
onmultiply(a,b){
5.a=a||1;
6.b=b||1;
7.
('Result'+a*b);
9.}
10.
ly();//Result1
ly(10);//Result10
ly(3,NaN);//Result3
ly(9,5);//Result45
15.
16.}());
复制代码
分号
总是使用分号,因为隐式的代码嵌套会引发难以察觉的问题。当然我们更要从根
本上来杜绝这些问题[1]。以下几个示例展示了缺少分号的危害:
1.//1.
od=function(){
42;
4.}//Nosemicolonhere.
5.
6.(function(){
7.//Someinitializationcodewrappedinafunctiontocreateascopefor
locals.
8.})();
9.
10.
={
12.'i':1,
13.'j':2
14.}//Nosemicolonhere.
15.
16.//todoonethingonInternetExplorerandanotheronFirefox.
17.//Iknowyou'dneverwritecodelikethis,butthrowmeabone.
18.[ffVersion,ieVersion][isIE]();
19.
20.
NGS_TO_EAT=[apples,oysters,sprayOnCheese]//Nosemicolon
here.
22.
23.//ionalexecutionalabash
24.-1==resultOfOperation()||die();
复制代码
Sowhathappens?
JavaScript错误——首先返回42的那个function被第二个function当
中参数传入调用,接着数字42也被“调用”而导致出错。
八成你会得到‘nosuchpropertyinundefined’的错误提示,因为在真实
环境中的调用是这个样子:x[ffVersion,ieVersion][isIE]().
die总是被调用。因为数组减1的结果是NaN,它不等于任何东西(无论
resultOfOperation是否返回NaN)。所以最终的结果是die()执行完所获得
值将赋给THINGS_TO_EAT.
Why?
JavaScript中语句要以分号结束,否则它将会继续执行下去,不管换不换行。
以上的每一个示例中,函数声明或对象或数组,都变成了在一句语句体内。要知
道闭合圆括号并不代表语句结束,JavaScript不会终结语句,除非它的下一个
token是一个中缀符[2]或者是圆括号操作符。
这真是让人大吃一惊,所以乖乖地给语句末加上分号吧。
澄清:分号与函数
分号需要用在表达式的结尾,而并非函数声明的结尾。区分它们最好的例子是:
=function(){
true;
3.};//semicolonhere.
4.
onfoo(){
true;
7.}//nosemicolonhere.
复制代码
嵌套函数
嵌套函数是非常有用的,比如用在持续创建和隐藏辅助函数的任务中。你可以非
常自由随意地使用它们。
语句块内的函数声明
切勿在语句块内声明函数,在ECMAScript5的严格模式下,这是不合法的。
函数声明应该在定义域的顶层。但在语句块内可将函数申明转化为函数表达式赋
值给变量。
不推荐
(x){
onfoo(){}
3.}
复制代码
推荐
(x){
=function(){};
3.}
复制代码
异常
基本上你无法避免出现异常,特别是在做大型开发时(使用应用开发框架等等)。
在没有自定义异常的情况下,从有返回值的函数中返回错误信息一定非常的棘手,
更别提多不优雅了。不好的解决方案包括了传第一个引用类型来接纳错误信息,
或总是返回一个对象列表,其中包含着可能的错误对象。以上方式基本上是比较
简陋的异常处理方式。适时可做自定义异常处理。
在复杂的环境中,你可以考虑抛出对象而不仅仅是字符串(默认的抛出值)。
(name===undefined){
{
:'SystemError',
e:'Anameshouldalwaysbespecified!'
5.}
6.}
复制代码
标准特性
总是优先考虑使用标准特性。为了最大限度地保证扩展性与兼容性,总是首选标
准的特性,而不是非标准的特性(例如:首选(3)而不是string[3];
首选DOM的操作方法来获得元素引用,而不是某一应用特定的快捷方法)。
简易的原型继承
如果你想在JavaScript中继承你的对象,请遵循一个简易的模式来创建此继承。
如果你预计你会遇上复杂对象的继承,那可以考虑采用一个继承库,比
如elRauschmayer.
简易继承请用以下方式:
1.(function(log){
2.'usestrict';
3.
4.//Constructorfunction
onApple(name){
=name;
7.}
8.//Definingamethodofapple
=function(){
('Eating'+);
11.};
12.
13.//Constructorfunction
onGrannySmithApple(){
15.//Invokingparentconstructor
(this,'GrannySmith');
17.}
18.//
ype=(ype);
20.//Setconstructortothesubtype,otherwisepointstoApple
uctor=GrannySmithApple;
22.
23.//Callingasupermethod
=function(){
25.//Besuretoapplyitontoourcurrentobjectwithcall(this)
(this);
27.
('PoorGranySmith');
29.};
30.
31.//Instantiation
le=newApple('TestApple');
nnyApple=newGrannySmithApple();
34.
();//TestApple
();//GrannySmith
37.
38.//Instancechecks
(appleinstanceofApple);//true
(appleinstanceofGrannySmithApple);//false
41.
(grannyAppleinstanceofApple);//true
(grannyAppleinstanceofGrannySmithApple);//true
44.
45.//Callingmethodthatcallssupermethod
();//EatingGrannySmithnPoorGranySmith
47.
48.}());
复制代码
使用闭包
闭包的创建也许是JS最有用也是最易被忽略的能力了。关于闭包如何工作的合
理解释。
切勿在循环中创建函数
在简单的循环语句中加入函数是非常容易形成闭包而带来隐患的。下面的例子就
是一个典型的陷阱:
不推荐
1.(function(log,w){
2.'usestrict';
3.
4.//numbersandiisdefinedinthecurrentfunctionclosure
bers=[1,2,3],
6.i;
7.
(i=0;i<;i++){
eout(function(){
10.//Atthemomentwhenthisgetsexecutedtheivariable,coming
fromtheouterfunctionscope
11.//issetto3andthecurrentprogramisalertingthemessage3times
12.//'Index3withnumberundefined
13.//Ifyouunderstandclosuresinjavascriptyouknowhowtodealwith
thosecases
14.//It'sbesttojustavoidfunctions/newclosuresinloopsasthis
preventsthoseissues
15.
('Index'+i+'withnumber'+numbers[i]);
17.},0);
18.}
19.
20.}(,window));
复制代码
接下来的改进虽然已经解决了上述例子中的问题或bug,但还是违反了不在循
环中创建函数或闭包的原则。
不推荐
1.(function(log,w){
2.'usestrict';
3.
4.//numbersandiisdefinedinthecurrentfunctionclosure
bers=[1,2,3],
6.i;
7.
(i=0;i<;i++){
9.//CreatinganewclosurescopewithanIIFEsolvestheproblem
10.//Thedelayedfunctionwilluseindexandnumberwhichare
11.//intheirownclosurescope(oneclosureperloopiteration).
12.//---
13.//Stillthisisnotrecommendedasweviolateourruletonot
14.//createfunctionswithinloopsandwearecreatingtwo!
15.
16.(function(index,number){
eout(function(){
18.//Willoutputasexpected0>1,1>2,2>3
('Index'+index+'withnumber'+number);
20.},0);
21.}(i,numbers[i]));
22.}
23.
24.}(,window));
复制代码
接下来的改进已解决问题,而且也遵循了规范。可是,你会发现看上去似乎过于
复杂繁冗了,应该会有更好的解决方案吧。
不完全推荐
1.(function(log,w){
2.'usestrict';
3.
4.//numbersandiisdefinedinthecurrentfunctionclosure
bers=[1,2,3],
6.i;
7.
8.//Createafunctionoutsideoftheloopthatwillacceptargumentsto
createa
9.//nctionwillreturnafunctionthat
executesinthis
10.//closureparentscope.
onalertIndexWithNumber(index,number){
function(){
('Index'+index+'withnumber'+number);
14.};
15.}
16.
17.//Firstparameterisafunctioncallthatreturnsafunction.
18.//---
19.//Thissolvesourproblemandwedon'tcreateafunctioninsideour
loop
(i=0;i<;i++){
eout(alertIndexWithNumber(i,numbers[i]),0);
22.}
23.
24.}(,window));
复制代码
将循环语句转换为函数执行的方式问题能得到立马解决,每一次循环都会对应地
创建一次闭包。函数式的风格更加值得推荐,而且看上去也更加地自然和可预料。
推荐
1.(function(log,w){
2.'usestrict';
3.
4.//numbersandiisdefinedinthecurrentfunctionclosure
bers=[1,2,3],
6.i;
7.
h(function(number,index){
eout(function(){
('Index'+index+'withnumber'+number);
11.},0);
12.});
13.
14.}(,window));
复制代码
eval函数(魔鬼)
eval()不但混淆语境还很危险,总会有比这更好、更清晰、更安全的另一种方案
来写你的代码,因此尽量不要使用evil函数。
this关键字
只在对象构造器、方法和在设定的闭包中使用this关键字。this的语义在此有
些误导。它时而指向全局对象(大多数时),时而指向调用者的定义域(在eval
中),时而指向DOM树中的某一节点(当用事件处理绑定到HTML属性上
时),时而指向一个新创建的对象(在构造器中),还时而指向其它的一些对象
(如果函数被call()和apply()执行和调用时)。
正因为它是如此容易地被搞错,请限制它的使用场景:
在构造函数中
在对象的方法中(包括由此创建出的闭包内)
首选函数式风格
函数式编程让你可以简化代码并缩减维护成本,因为它容易复用,又适当地解耦
和更少的依赖。
接下来的例子中,在一组数字求和的同一问题上,比较了两种解决方案。第一个
例子是经典的程序处理,而第二个例子则是采用了函数式编程和ECMAScript
5.1的数组方法。
例外:往往在重代码性能轻代码维护的情况之下,要选择最优性能的解决方案而
非维护性高的方案(比如用简单的循环语句代替forEach)。
不推荐
1.(function(log){
2.'usestrict';
3.
=[10,3,7,9,100,20],
=0,
6.i;
7.
8.
(i=0;i<;i++){
+=arr[i];
11.}
12.
('Thesumofarray'+arr+'is:'+sum)
14.
15.}());
复制代码
推荐
1.(function(log){
2.'usestrict';
3.
=[10,3,7,9,100,20];
5.
=(function(prevValue,currentValue){
prevValue+currentValue;
8.},0);
9.
('Thesumofarray'+arr+'is:'+sum);
11.
12.}());
复制代码
另一个例子通过某一规则对一个数组进行过滤匹配来创建一个新的数组。
不推荐
1.(function(log){
2.'usestrict';
3.
bers=[11,3,7,9,100,20,14,10],
sGreaterTen=[],
6.i;
7.
8.
(i=0;i<;i++){
(numbers[i]>10){
(numbers[i]);
12.}
13.}
14.
('Fromthelistofnumbers'+numbers+'only'+
numbersGreaterTen+'aregreaterthanten');
16.
17.}());
复制代码
推荐
1.(function(log){
2.'usestrict';
3.
bers=[11,3,7,9,100,20,14,10];
5.
bersGreaterTen=(function(element){
element>10;
8.});
9.
('Fromthelistofnumbers'+numbers+'only'+
numbersGreaterTen+'aregreaterthanten');
11.
12.}());
复制代码
使用ECMAScript5
建议使用ECMAScript5中新增的语法糖和函数。这将简化你的程序,并让你
的代码更加灵活和可复用。
数组和对象的属性迭代
用ECMA5的迭代方法来迭代数组。使用h或者如果你要在特殊
场合下中断迭代,那就用。
1.(function(log){
2.'usestrict';
3.
4.//Iterateoveranarrayandbreakatacertaincondition
5.[1,2,3,4,5].every(function(element,index,arr){
(element+'atindex'+index+'inarray'+arr);
7.
(index!==5){
true;
10.}
11.});
12.
13.//Definingasimplejavascriptobject
={
15.a:'A',
16.b:'B',
17.'c-d-e':'CDE'
18.};
19.
20.//Iteratingovertheobjectkeys
(obj).forEach(function(element,index,arr){
('Key'+element+'hasvalue'+obj[element]);
23.});
24.
25.}());
复制代码
不要使用switch
switch在所有的编程语言中都是个非常错误的难以控制的语句,建议用ifelse
来替换它。
这个我表示不同意
数组和对象字面量
用数组和对象字面量来代替数组和对象构造器。数组构造器很容易让人在它的参
数上犯错。
不推荐
1.//Lengthis3.
1=newArray(x1,x2,x3);
3.
4.//Lengthis2.
2=newArray(x1,x2);
6.
7.//Ifx1isanumberanditisanaturalnumberthelengthwillbex1.
8.//Ifx1isanumberbutnotanaturalnumberthiswillthrowanexception.
9.//Otherwisethearraywillhaveoneelementwithx1asitsvalue.
3=newArray(x1);
11.
12.//Lengthis0.
4=newArray();
复制代码
正因如此,如果将代码传参从两个变为一个,那数组很有可能发生意料不到的长
度变化。为避免此类怪异状况,请总是采用更多可读的数组字面量。
推荐
=[x1,x2,x3];
2=[x1,x2];
3=[x1];
4=[];
复制代码
对象构造器不会有类似的问题,但是为了可读性和统一性,我们应该使用对象字
面量。
不推荐
=newObject();
2.
2=newObject();
4.o2.a=0;
5.o2.b=1;
6.o2.c=2;
7.o2['strangekey']=3;
复制代码
应该写成这样:
推荐
={};
2.
2={
4.a:0,
5.b:1,
6.c:2,
7.'strangekey':3
8.};
复制代码
修改内建对象的原型链
修改内建的诸如ype和ype是被严厉禁止的。修
改其它的内建对象比如ype,虽危害没那么大,但始终还是会
导致在开发过程中难以debug的问题,应当也要避免。
自定义toString()方法
你可以通过自定义toString()来控制对象字符串化。这很好,但你必须保证你
的方法总是成功并不会有其它副作用。如果你的方法达不到这样的标准,那将会
引发严重的问题。如果toString()调用了一个方法,这个方法做了一个断言[3],
当断言失败,它可能会输出它所在对象的名称,当然对象也需要调用toString()。
圆括号
一般在语法和语义上真正需要时才谨慎地使用圆括号。不要用在一元操作符上,
例如delete,typeof和void,或在关键字之后,例如return,throw,case,new
等。
字符串
统一使用单引号(’),不使用双引号(“)。这在创建HTML字符串非常有好处:
varmsg='ThisissomeHTML
三元条件判断(if的快捷方法)
用三元操作符分配或返回语句。在比较简单的情况下使用,避免在复杂的情况下
使用。没人愿意用10行三元操作符把自己的脑子绕晕。
不推荐
(x===10){
'valid';
3.}else{
'invalid';
5.}
复制代码
推荐
x===10?'valid':'invalid';
复制代码
[1]:作者指的是采用严格规范的语句写法,从根本上杜绝由分号缺失而引起的
代码歧义。
[2]:中缀符,指的是像x+y中的+。
[3]:断言一般指程序员在测试测序时的假设,一般是一些布尔表达式,当返回
是true时,断言为真,代码运行会继续进行;如果条件判断为false,代码运
行停止,你的应用被终止。
发布评论