javascript学习笔记

学习参拷: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>
 访问全局变量
          每个JavaScript环境有一个全局对象,当你在任意的函数外面使用this的时候可以访问到。你创建的每一个全部变量都成了这个全局对象的属 性。在浏览器中,方便起见,该全局对象有个附加属性叫做window,此window(通常)指向该全局对象本身。
<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可以声明多个变量 
var a='111',b='222',c;
 

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 循环

遍历数组或类似数组的对象(argumentsHTMLCollection对象)

<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.getElementsByName()
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循环分号分开后的的部分:如for (var i = 0; i < 10; i += 1) {...}
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:区分表达式和声明

1:有没有函数标识符(函数名)
函数声明:function 函数名称 (参数:可选){ 函数体 }
函数表达式:function 函数名称(可选)(参数:可选){ 函数体 }

2:存在函数名,但作为var赋值的一部分为表达式
var bar = function foo(){};
new function foo(){}; #new的表达式

3:在函数体内是一个声明
(function(){ //表达式,()为分组操作符,里面只能是表达式
function bar(){} // 声明,因为它是函数体的一部分
})();

(function bar(){}) //表达式,()为分组操作符,里面只能是表达式

4:在程序最顶部是一个声明

 分组操作符(里面会被当作表达式来对待,而不是代码块)

try {
(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显示的调用栈

javascript学习笔记
 

 第三章: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));
 
返回全局变量
<script language="javascript" type="text/javascript">
	var Calculator = (function () {
	    //这里可以声明私有成员
        var my = {} ,privateName = 'gbz';
        function getPrivateName(){
        	return privateName;
        }

        my.name = privateName;
        my.getName = function() {
        	return getPrivateName();
        } ;
	    return my;
	}())
   // debugger;
   document.write("<br/>"+Calculator.getName());  
</script>  
 
3.3:扩展
紧耦合扩展(可以生载方法)
<script language="javascript" type="text/javascript">
	var Calculator = (function () {
        var my = {} ,privateName = 'gbz';
        function getPrivateName(){
        	return privateName;
        }

        my.name = privateName;
        my.getName = function() {
        	return getPrivateName();
        } ;
	    return my;
	}())
   // 扩展
   var myObj =  (function (my) {   //这样就可以扩展原来的函数
     my.reName = function() {   //这里可以重载方法
     	return 'aaa';
     }
     return my;
   }(Calculator))  
   document.write("<br/>"+myObj.getName()); 
   document.write("<br/>"+myObj.reName());  
</script>  
 

松耦合扩展(每个js都是顺序加载到内存中的,当一个js文件引用另一个js文件但它还没加载时,就会停止加载 ;松耦合扩展就是为了js文件互相加载不影响)

    创建对象时:var cnblogs = cnblogs || {} ;

确保cnblogs对象,在存在的时候直接用,不存在的时候直接赋值为{}

var blogModule = (function (my) {

    // 添加一些功能   
    
    return my;
} (blogModule || {}));

  缺点是没办法重载方法

 

3.4:克隆与继承

var blogModule = (function (old) {
    var my = {},
        key;

    for (key in old) {
        if (old.hasOwnProperty(key)) {
            my[key] = old[key];
        }
    }

    var oldAddPhotoMethod = old.AddPhoto;
    my.AddPhoto = function () {
        // 克隆以后,进行了重写,当然也可以继续调用oldAddPhotoMethod
    };

    return my;
} (blogModule));

 其实该对象的属性对象或function根本没有被复制,只是对同一个对象多了一种引用而已,所以如果老对象去改变它,那克隆以后的对象所拥有的属性或function函数也会被改变,解决这个问题,我们就得是用递归,但递归对function函数的赋值也不好用,所以我们在递归的时候eval相应的function。

 

3.5:跨文件共享私有对象

 

var blogModule = (function (my) {
    var _private = my._private = my._private || {},
        
        _seal = my._seal = my._seal || function () {
            delete my._private;
            delete my._seal;
            delete my._unseal;
            
        },
        
        _unseal = my._unseal = my._unseal || function () {
            my._private = _private;
            my._seal = _seal;
            my._unseal = _unseal;
        };
        
    return my;
} (blogModule || {}));

 任何文件都可以对他们的局部变量_private设属性,并且设置对其他的文件也立即生效。一旦这个模块加载结束,应用会调用 blogModule._seal()"上锁",这会阻止外部接入内部的_private。如果这个模块需要再次增生,应用的生命周期内,任何文件都可以调用_unseal() ”开锁”,然后再加载新文件。加载后再次调用 _seal()”上锁”。

 

3.6: 子模块
blogModule.CommentSubModule = (function () {
    var my = {};
    // ...

    return my;
} ());
 

你可能感兴趣的:(JavaScript)