JavaScript函数学习总结以及相关的编程习惯指南
null和undefined
Undefined相当于一个变量并没有明确的被赋值(是否被赋值,可能无心忽略,逻辑问题)JS的怪异之处就在于undefined真的是一个可以使用的值。
>varfoo; >foo undefined
同理,当缺失参数时JavaScript会分配一个undefined:
>functionid(x){returnx} >id() undefined a=1; a!==undefined//true a=undefined varb a===b//true
Null相当于变量被明确指定了没有值,而不是由于意外的原因被忽略掉了(赋值null,正当逻辑)
参与运算
JS的null如果进入运算,真的会被解析成为0或false:
(1+null)#1(1*null)#0(1*null)#Infinity
undefined进入运算,一律得到NaN:
(1+undefined)#NaN(1*undefined)#NaN(1/undefined)#NaN
逻辑判断
null和undefined逻辑判断时都认为是false。
只用一个判断,就可以同时检验这两项是否为真:
//也会把false,-0,+0,NaN与''当成“空值” if(v){ //v有值 }else{ //v没有值 }
但是如果碰到大坑==的时候
varfoo; console.log(foo==null);//true console.log(foo==undefined);//true console.log(foo===null);//false console.log(foo===undefined);//true console.log(null==undefined);//true
好的做法,一律使用===
判断一个量已定义且非空,只使用:if(a!==null&&a!==undefined)。
===和==
1.==用来判断两个值是否相等
当两个值类型不同时,会发生自动转换,得到的结果非常不符合直觉,这可能不是你想要的结果。
""=="0"//false 0==""//true 0=="0"//true false=="false"//false false=="0"//true false==undefined//false false==null//false null==undefined//true "\t\r\n"==0//true
2.===
类型+值比较
"如果两边的操作数具有相同的类型和值,===返回true,!==返回false。"——《JavaScript:语言精粹》
最佳实践:
任何时候在比较操作中使用===和 !==
json操作
varperson={name:'Saad',age:26,department:{ID:15,name:"R&D"}}; varstringFromPerson=JSON.stringify(person); /*stringFromPersonisequalto"{"name":"Saad","age":26,"department":{"ID":15,"name":"R&D"}}"*/ varpersonFromString=JSON.parse(stringFromPerson); /*personFromStringisequaltopersonobject*/ tostring varobj={ name:'myObj' }; JSON.stringify(obj);
函数对象及匿名函数
函数对象赋值
varslice_func=[].slice //slice_func() vara=function(){ }; //a() vara={ fun:function(){ }; } //a.fun() someElement.addEventListener("click",function(e){ //I'manonymous! });
以及
varf=functionfoo(){ returntypeoffoo;//foo是在内部作用域内有效 }; //foo在外部用于是不可见的 typeoffoo;//"undefined" f();//"function"
匿名函数
from varname='Chris'; varage='34'; varstatus='single'; functioncreateMember(){ //[...] } functiongetMemberDetails(){ //[...] } to varmyApplication=function(){ varname='Chris'; varage='34'; varstatus='single'; return{ createMember:function(){ //[...] }, getMemberDetails:function(){ //[...] } } }(); //myApplication.createMember()and //myApplication.getMemberDetails()nowworks.
最佳实践
1.定义多个变量时,省略var关键字,用逗号代替
varsomeItem='somestring'; varanotherItem='anotherstring'; varoneMoreItem='onemorestring';
更好的做法
varsomeItem='somestring', anotherItem='anotherstring', oneMoreItem='onemorestring';
2.谨记,不要省略分号,不要省略花括号
省略分号,可能导致更大的,未知的,难以发现的问题
varsomeItem='somestring' functiondoSomething(){ return'something' }
更好的做法
varsomeItem='somestring'; functiondoSomething(){ return'something'; }
3.使用{}代替newOjbect()
在JavaScript中创建对象的方法有多种。可能是传统的方法是使用”new”加构造函数,像下面这样:
varo=newObject(); o.name='Jeffrey'; o.lastName='Way'; o.someFunction=function(){ console.log(this.name); }
更好的做法
varo={};//空对象
varo={ name:'Jeffrey', lastName='Way', someFunction:function(){ console.log(this.name); } };
只要把多个全局变量都整理在一个名称空间下,拟将显著降低与其他应用程序、组件或类库之间产生糟糕的相互影响的可能性。——DouglasCrockford
4.使用[]代替newArray()
vara=newArray(); a[0]="Joe"; a[1]='Plumber';
更好的做法:
vara=['Joe','Plumber'];
5.typeof判断
typeof一般只能返回如下几个结果:number,boolean,string,function,object,undefined
expr:
typeofxx==='' typeofxx!==''
e.g.
//Numbers typeof37==='number'; typeof3.14==='number'; typeofInfinity==='number'; typeofNaN==='number';//尽管NaN是"Not-A-Number"的缩写,意思是"不是一个数字" //Strings typeof""==='string'; typeof"bla"==='string'; typeof(typeof1)==='string';//typeof返回的肯定是一个字符串 //Booleans typeoftrue==='boolean'; typeoffalse==='boolean'; //Undefined typeofundefined==='undefined'; typeofblabla==='undefined';//一个未定义的变量,或者一个定义了却未赋初值的变量 //Objects typeof{a:1}==='object'; typeof[1,2,4]==='object';//使用Array.isArray或者Object.prototype.toString.call方法可以分辨出一个数组和真实的对象 typeofnewDate()==='object'; //Functions typeoffunction(){}==='function'; typeofMath.sin==='function'; typeofnull==='object';//从JavaScript诞生以来,一直是这样的.
6.三元运算符:强大且风骚
语法
expression?xxx:yyy bad vardirection; if(x<200){ direction=1; }else{ direction=-1; } good vardirection=x<200?1:-1;
7.使用逻辑AND/OR做条件判断
varfoo=10; foo==10&&doSomething();//等价于if(foo==10)doSomething(); foo==5||doSomething();//等价于if(foo!=5)doSomething(); //默认值 a=b||'default' returnb||c||d>1?0:2
8.给一个变量赋值的时候不要忘记使用var关键字
给一个未定义的变量赋值会导致创建一个全局变量。要避免全局变量
9.自我调用的函数
自调用匿名函数(Self-InvokedAnonymousFunction)或者即时调用函数表达式(IIFE-ImmediatelyInvokedFunctionExpression)。这是一个在创建后立即自动执行的函数
(function(){ //someprivatecodethatwillbeexecutedautomatically })(); (function(a,b){ varresult=a+b; returnresult; })(10,20)
10.避免使用eval()和Function构造函数
Eval=邪恶,不仅大幅降低脚本的性能(译注:JIT编译器无法预知字符串内容,而无法预编译和优化),而且这也会带来巨大的安全风险,因为这样付给要执行的文本太高的权限,避而远之
使用eval和Function构造函数是非常昂贵的操作,因为每次他们都会调用脚本引擎将源代码转换成可执行代码。
varfunc1=newFunction(functionCode); varfunc2=eval(functionCode);
11.避免使用with()
使用with()会插入一个全局变量。因此,同名的变量会被覆盖值而引起不必要的麻烦
12.脚本放在页面的底部
记住——首要目标是让页面尽可能快的呈献给用户,脚本的夹在是阻塞的,脚本加载并执行完之前,浏览器不能继续渲染下面的内容。因此,用户将被迫等待更长时间
13.避免在For语句内声明变量
bad
for(vari=0;i<someArray.length;i++){ varcontainer=document.getElementById('container'); container.innerHtml+='mynumber:'+i; console.log(i); }
good
varcontainer=document.getElementById('container'); for(vari=0,len=someArray.length;i<len;i++){ container.innerHtml+='mynumber:'+i; console.log(i); }
14.给代码添加注释
//循环数组,输出每项名字(译者注:这样的注释似乎有点多余吧). for(vari=0,len=array.length;i<len;i++){ console.log(array[i]); }
15.instanceof
instanceof方法要求开发者明确地确认对象为某特定类型
varoStringObject=newString("helloworld"); console.log(oStringObjectinstanceofString);//输出"true" //判断foo是否是Foo类的实例 functionFoo(){} varfoo=newFoo(); console.log(fooinstanceofFoo)//true //判断foo是否是Foo类的实例,并且是否是其父类型的实例 functionAoo(){} functionFoo(){} Foo.prototype=newAoo();//JavaScript原型继承 varfoo=newFoo(); console.log(fooinstanceofFoo)//true console.log(fooinstanceofAoo)//true
16.apply/call
someFn.call(this,arg1,arg2,arg3); someFn.apply(this,[arg1,arg2,arg3]);
apply
Function.apply(obj,args)方法能接收两个参数
obj:这个对象将代替Function类里this对象
args:这个是数组,它将作为参数传给Function(args-->arguments)
call
Function.call(obj,[param1[,param2[,…[,paramN]]]])
obj:这个对象将代替Function类里this对象
params:这个是一个参数列表
使用哪个取决于参数的类型