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:这个是一个参数列表
使用哪个取决于参数的类型