学习参拷:http://www.cnblogs.com/TomXu/archive/2011/12/15/2288411.html
第一节:基础
1.1:变量
javascript中,默认所有全局变量都共享一个空间(即你的JavaScript应用程序和web页面上的所有代码都共享了这些全局变量),带来的问题就是变量冲突(造成变量重新赋值)
<script language="javascript" type="text/javascript"> var a='111'; //在方法外面声明的变量 c='333'; //隐试全局变量 function varloa(){ b='2222'; //未使用var 声明的变量叫 隐试全局变量 } </script>使用var创建的全局变量不能使用delete删除,而隐试全局变量可以
<script language="javascript" type="text/javascript"> var a='111'; //在方法外面声明的变量 c='333'; //隐试全局变量 function varloa(){ b='2222'; //未使用var 声明的变量叫 隐试全局变量 } delete a; delete b; delete c; document.write("<br/>" +typeof a); document.write("<br/>" +typeof b); document.write("<br/>" +typeof c); </script>访问全局变量
<script language="javascript" type="text/javascript"> var a='111'; function varloa(){ var a='444'; document.write("<br/>" +a); //访问局部就是 document.write("<br/>" +window.a); //所有全局变量都在window对象的一个属性,用.即可访问 document.write("<br/>" +this.a); //this代表window对象 document.write("<br/>" +window['a']); } varloa(); </script>别外还可以把window赋值给其它变量来访问
<script language="javascript" type="text/javascript"> var a='111'; var global = (function () { //把window对象赋值给global变量 return this; }()); document.write("<br/>" +global.a); </script>
var散布的问题
JavaScript中,你可以在函数的任何位置声明多个var语句,并且它们就好像是在函数顶部声明一样发挥作用,这种行为称为 hoisting(悬置/置顶解析/预解析)。当你使用了一个变量,然后不久在函数中又重新声明的话,就可能产生逻辑错误。
<script language="javascript" type="text/javascript"> a='111'; function varglo(){ document.write("<br/>" +a); //undefined var a='222'; //a被声明为局部变量,故上面a也是,但它没初始化,因此是nudefined document.write("<br/>" +a); } varglo(); </script>
1.2:for 循环
遍历数组或类似数组的对象(arguments
和HTMLCollection
对象)
<body> <p></p> <p></p> <p></p> </body> <script language="javascript" type="text/javascript"> var b = document.getElementsByTagName("p"); for(var i=0;i<b.length;i++){ //问题在于每次循环都会重新获得b的长度 document.write("<br/>" +i); //b是dom对象,遍历dom效率低下 } for(var i=0,j=b.length;i<j;i++){ //这样只会遍历一次dom console.log("pCollection.length: ", b.length); } var j=b.length; for(;j--;){ //效率更高 console.log("pCollection.length: ", b.length); } </script>
补充:HTMLCollections指的是DOM方法返回的对象
document.getElementsByClassName()
document.getElementsByTagName()
document.images: 页面上所有的图片元素
document.links : 所有a标签元素
document.forms : 所有表单
document.forms[0].elements : 页面上第一个表单中的所有域
遍历对象使用for-in
<script language="javascript" type="text/javascript"> var b = { //对象 a:1, b:2 } for(var i in b){ document.write("<br/>" +i); } if(typeof Object.prototype.close === 'undefined'){ //判断对象是否有close属性 Object.prototype.close =function(){} //为所有对象增加close属性 } for(var i in b){ if (b.hasOwnProperty(i)) { //过滤对象原型属性(即Object.prototype,从object继承来的属性) document.write("<br/>" +i); } } //另种形式 var i, hasOwn = Object.prototype.hasOwnProperty; for (i in b) { if (hasOwn.call(b, i)) { // 过滤 console.log(i, ":", b[i]); } } </script>
(不)扩展内置原型
<script language="javascript" type="text/javascript"> Array.prototype.Array =function(){alert('哈哈')} var a=new Array(); a.Array(); </script>
这样作会使用代码混乱,难以维护,别人总是希望调用原始的方法
1.3:switch
<script language="javascript" type="text/javascript"> var a=0 switch (a){ case 0: alert(0); break; //避免贯穿所有判断 case 1: alert(1); break; default: alert(3); } </script>
1.4变量类型隐试转换(false == 0 或 “” == 0 返回的结果是true)
<script language="javascript" type="text/javascript"> var a=0 if(a==false){ console.log("=="+a); } if(a===false){ //严格相等,包括类型 console.log("==="+a); } </script>
1.5:避免使用eval (接受任意的字符串,并当作JavaScript代码来处理)
1):如果代码事先知道(非运行时确认),不应使用eval,
2):如果代码是在运行时动态生成,有一个更好的方式不使用eval而达到同样的目标就不使用它。
<script language="javascript" type="text/javascript"> var a={name:"gbz"}; var name= 'name'; console.log(eval("a."+name)); console.log(a[name]); //事先已经知道取对象的name值,就不应使用eval </script>
3):安全问题,如果代码从网上得来时已经被篡改,会很危险 ; 给setInterval(), setTimeout()和Function()构造函数传递字符串,大部分情况下,与使用eval()是类似的,因此要避免。
setTimeout("myFunc()", 1000); // 更好的 setTimeout(myFunc, 1000);
4):如果非要使用eval,可以使用new Function()代替(eval中定义变量是作用域在方法外,Function变量的作用域在方法内)
console.log(typeof un); // "undefined" console.log(typeof deux); // "undefined" console.log(typeof trois); // "undefined" var jsstring = "var un = 1; console.log(un);"; eval(jsstring); // logs "1" jsstring = "var deux = 2; console.log(deux);"; new Function(jsstring)(); // logs "2" jsstring = "var trois = 3; console.log(trois);"; (function () { eval(jsstring); }()); // logs "3" console.log(typeof un); // number console.log(typeof deux); // "undefined" console.log(typeof trois); // "undefined" 放到()中即作用域在()内
eval会干扰变量
(function () { var local = 1; eval("local = 3; console.log(local)"); // logs "3" console.log(local); // logs "3" }()); (function () { var local = 1; Function("console.log(typeof local);")(); // logs undefined }());
1.6:正确使用ParseInt()
parseInt接收两个参数,即字符数字和类型(二进制2,十进制10),如果省略则当处理o9时按8进制处理,而8进制没有9会报错
1.7:花括号{}
当花括号可选时,尽量加上
// 坏 if (true) alert(1); // 好 if (true) { alert(1); } //注意,花括号的结束位置
1.8:空格的使用(改善代码的可读性和一致性)
for循环中初始化的多变量(i和max):for (var i = 0, max = 10; i < max; i += 1) {...}
分隔数组项的逗号的后面:var a = [1, 2, 3];
对象属性逗号的后面以及分隔属性名和属性值的冒号的后面:var o = {a: 1, b: 2};
限定函数参数:myFunc(a, b, c)
函数声明的花括号的前面:function myFunc() {}
匿名函数表达式function的后面:var myFunc = function () {};
在+, -, *, =, <, >, <=, >=, ===, !==, &&, ||, +=等前后都需要空格
函数、if-else语句、循环、对象字面量的左花括号的前面({)
else或while之间的右花括号(})
1.9:命名规范及声明对象
<script language="javascript" type="text/javascript"> var PI = 3.14; //常量大写(虽然javascript没有常量,表示不会改变的) var Person = { //构造函数,使用驼峰(Camel)命名法 _name:'bz', getName: function() { //公共方法 小驼峰命名 document.write("<br/>"+this._name+this._getFirst()); }, _getFirst: function() { //私有方法(它还是公共方法,这样会告诉用户这是私有方法) return 'g'; } } Person.getName(); //上面只是一个对象,不能用new实例化 //var adam = new Person(); //尽管没有类,构造函数只是一个方法,它用首字母大写 function Myclass() { //用 function 关键字模拟 class this._id = 'gbz'; //用this表明对象的属性 var name = '1111'; //用var声明的是局部变量 this.getId = function() { document.write("<br/>"+this._id); } } var adam = new Myclass(); adam.getId(); document.write("<br/>"+adam.name); //局部变量 undefined //另外一种声明对象的方法 function Myperson() { var Person = { _name:'bz', getName: function() { document.write("<br/>"+this._name); } }; return Person; } var a = new Myperson(); a.getName(); </script>
第二章:函数(函数表达式和函数声明)
2.1:区分表达式和声明
函数声明:function 函数名称 (参数:可选){ 函数体 }
函数表达式:function 函数名称(可选)(参数:可选){ 函数体 }
2:存在函数名,但作为var赋值的一部分为表达式
var bar = function foo(){};
new function foo(){}; #new的表达式
3:在函数体内是一个声明
(function(){ //表达式,()为分组操作符,里面只能是表达式
function bar(){} // 声明,因为它是函数体的一部分
})();
(function bar(){}) //表达式,()为分组操作符,里面只能是表达式
4:在程序最顶部是一个声明
分组操作符(里面会被当作表达式来对待,而不是代码块)
(var x = 5); // 分组操作符,只能包含表达式而不能包含语句:这里的var就是语句
} catch(err) {
// SyntaxError
}
声明会在任何表达式之前被分析,同名的函数声明会被覆盖,
2.2:命名函数表达式,理所当然,就是它得有名字(例:var bar = function foo(){};,在函数内部就名字是foo)
1):名字只在新定义的函数作用域内有效,因为规范规定了标示符不能在外围的作用域内有效:
<script language="javascript" type="text/javascript"> var f = function foo(){ return typeof foo; // foo是在内部作用域内有效 }; // foo在外部用于是不可见的 typeof foo; // "undefined" f(); // "function" </script>
2):为表达式命名是为了Firebug调式方便
<script language="javascript" type="text/javascript"> function foo(){ return bar(); } var bar = (function(){ if (window.addEventListener) { return function bar(){ return baz(); }; } else if (window.attachEvent) { return function bar() { return baz(); }; } })(); function baz(){ debugger; } foo(); </script>
Firebug显示的调用栈
第三章:Module模式
封装了变量和function,和全局的namaspace不接触,松耦合
只暴露可用public的方法,其它私有方法全部隐藏
3.1:基本样式(这样每次使用时都须要new一个对象)
<script language="javascript" type="text/javascript"> var Calculator = function (eq) { //这里可以声明私有成员 var eqCtl = 'gbz:' + eq ; return { // 暴露公开的成员 add: function (x, y) { var val = x + y; document.write("<br/>"+ eqCtl + val); } }; }; // debugger; var p = new Calculator('abc'); p.add(1,2); </script>3.2:匿名闭包
(function () { // ... 所有的变量和function都在这里声明,并且作用域也只能在这个匿名闭包里 // ...但是这里的代码依然可以访问外部全局的对象 }());//有括号,就是创建一个函数表达式,也就是自执行,用的时候不用和上面那样在new了
另一种形式:(function () {/* 内部代码 */})();
引用全局变量
(function ($, YAHOO) { // 这里,我们的代码就可以使用全局的jQuery对象了,YAHOO也是一样 } (jQuery, YAHOO));