變量對象(Variable Object)
是與執行上下文有關的數據作用域。它是與上下文相關聯的特殊對象,用於存儲定義在上下文中的變量(Variables)和函數聲明(function declarations)。
var x=30; function bar(){} (function baz(){}); //全局上下文中的變量對象包含: x //30 bar //<funciton>
活動對象(Activation Object)
當函數被調用者激活時,這個特殊的活動對象就被創建了,活動對象在函數上下文中被作為變量對象(vo)中使用。
function add(x,y){ var z=x+y; function bar(){}; (function baz(){}); return z; }
add(10,20);
"add"函數上下文中的一個活動對象(AO)包括:
形參:x,y //10,20
實參:參數對象:arguments {0:10,1:20}
局部變量:z //30
內部函數:bar
//函數表達式也不在AO之列
作用域鏈(Scope Chain)
作用域鏈和原型鏈很相似,如果在自己的作用域沒有,那么它會尋找父級的,直到頂層。
var x=10; (function foo(){ var y=20; (function bar(){ var z=30; console.log(x+y+z); }(); })();
閉包(Closures)
function foo(){ var x=10; return function bar(){ console.log(x); }; } //foo返回的也是一個funciton //並且這個返回的函數可以任意地調用內部變量x var ret=foo(); var x=20; ret();//是10而不是20
閉包(因為閉包就是一個函數,而函數是有作用域的)可以有效地將變量隔離,防止出現變量同名的問題(因為一個項目可能有多個人來寫)如上例中的外部的x的值不會影響閉包內的x
//方法1 function a() { var i=0; function b() { alert(++i); } return b; } var c=a(); c();//1 c();//2 // 方法2--立即執行函數 var c=(function() { var i=0; function b() { alert(++i); } return b; })(); c();//1 c();//2
1、閉包就是能夠讀取其它函數內部變量的函數
2、讓這些變量的值始終保持在內存中
3、閉包可以保證函數內變量的安全
NaN
//NaN表示非數字的意思 typeof NaN //'number' 'a1'==NaN //false 任何數據和NaN做==比較,結果都是false,包括和自己 NaN==NaN //false //判斷一個數據是不是數字要用isNaN isNaN('12') //false 函數參數一般為number或string isNaN('a1') //true
if條件是否為真的簡寫
//條件假 //number中的0 //string中的''注意是空字符串,而不是空格串 //boolean中的false //null if(!x) console.log('條件成立') //當x取值為上述列出的值時,條件成立,反之,不成立
if(typeof(x)!='undefined' && x)//表示x已定義且不為空
JS的繼承
//父類
function Person(name,age){
this.name=name;
this.age=age;
}
//父類方法
Person.prototype.show=function(){
console.log('my name is '+this.name+','+this.age+' years old.');
}
Person.prototype.hello=function(){
console.log(this.name+' is saying hello!');
}
//子類
function Player(name,age,type){
Person.call(this,name,age);//或Person.apply(this,[name,age]);
this.type=type; }
//子類方法
Player.prototype.show=function(){//子類的同名方法show,因為有了空對象作為橋梁,所以不會覆蓋父類方法
Person.prototype.show.call(this);//子類的去調用父類的同名方法
console.log('I am a '+this.type+' player.');
}
Player.prototype.play=function(){
console.log(this.name+' is playing '+this.type+'.');
}
//子類通過原型鏈和父類建立關系
function F(){}
F.prototype=Person.prototype;
Player.prototype=new F();
//子類的原型是空對象,而空對象的原型又是父類
//子類可以重寫父類的同名方法,但又不會覆蓋父類的同名方法
jordan=new Player('Jordan',50,'basketball');//構造一個子類對象
jordan.show();//此處調用的是子類的show方法
//my name is Jordan,50 years old.
//I am a basketball player.
zhang=new Person('ZhangSan',20);
zhang.show();//此處調用的是父類show方法
//my name is ZhangSan,20 years old.
//子類可以繼承父類方法
zhang.hello();
//ZhangSan is saying hello!
jordan.hello();
//Jordan is saying hello!
//子類也可以有自己獨有的方法 jordan.play();
//Jordan is playing basketball.
zhang.play();
//undefined is not a function //call和apply方法的第一個參數為調用構造器的對象,后面是要傳遞的實參,只是apply采用數組的形式。
事件和函數綁定
var btn1=document.getElementById('btn1'); /*方法一*/ btn1.onclick=function() { this.innerHTML='how are you?' } /*方法二 事件注冊*/ function myAlert() { alert('one click only!'); removeEvent(btn1,'click',myAlert) } //w3c btn1.addEventListener('click',myAlert,false); //IE btn1.attachEvent('onclick',myAlert); //寫一個跨瀏覽器的通用方法 function addEvent (elem,type,fn) { if(elem.attachEvent){ //IE elem.attachEvent('on'+type,fn); return; } if(elem.addEventListener){ //W3C elem.addEventListener(type,fn,false); } } //通用調用 addEvent(btn1,'click',myAlert);
事件解綁
//寫一個跨瀏覽器的通用方法--解除綁定 function removeEvent (elem,type,fn) { if(elem.detachEvent){ elem.detachEvent('on'+type,fn); return; } if(elem.removeEventListener){ elem.removeEventListener(type,fn,false); } } //寫一個跨瀏覽器的通用方法--事件綁定 function addEvent (elem,type,fn) { if(elem.attachEvent){ elem.attachEvent('on'+type,fn); return; } if(elem.addEventListener){ elem.addEventListener(type,fn,false); } } var btn1=document.getElementById('btn1'); //事件處理程序 function myAlert() { alert('one click only!'); removeEvent(btn1,'click',myAlert);//調用一次立即解除綁定,以后再單擊就不會執行該事件處理程序 } addEvent(btn1,'click',myAlert);
阻止默認事件
//阻止默認行為 function myEventHandler (e) { e=e || window.event; if(e.preventDefault){ e.preventDefault(); }else{ e.returnValue=false; } } //事件處理程序 function aHandler (e) { myEventHandler(e); console.log('you Click a!'); } //html <a id="a1" href="http://www.nba.com">Mike</a> a1=document.getElementById("a1"); //事件綁定 a1.addEventListener('click',aHandler,false); //這樣點擊鏈接后不會跳轉到指定的url,只會執行該事件處理程序
事件冒泡
//html <div id="div1"> <p id="p1">I love <a id="a1" href="">Mike</a>.</p> </div> //獲取Dom元素
div1=document.getElementById("div1"); p1=document.getElementById("p1"); a1=document.getElementById("a1");
//阻止默認的事件,避免鏈接跳轉 function myEventHandler (e) { e=e || window.event;//e為w3c標准事件對象,window.event為微軟IE的事件對象
//w3c if(e.preventDefault){ e.preventDefault();
//IE }else{ e.returnValue=false; } } //div的事件處理程序 function divHandler () { console.log('you Click div!'); }
//p的事件處理程序 function pHandler () { console.log('you Click p!'); }
//a的事件處理程序 function aHandler (e) { myEventHandler(e); e=e || window.event; if(e.stopPropagation){ //W3C e.stopPropagation(); }else{ //IE e.cancelBubble=true; } console.log('you Click a!'); } //事件注冊 div1.addEventListener('click',divHandler,false); p1.addEventListener('click',pHandler,false); a1.addEventListener('click',aHandler,false);
//如果不阻止事件冒泡,則點擊鏈接后,先觸發a的事件,再觸發p的事件,最后觸發div的事件。
//如果在a的事件中阻止向上冒泡的話,則只會引發a的事件。
事件委托
var table1=document.getElementById('table1'); table1.onclick=function(e) { e=e || window.event; console.log(e); var targetNode=e.target || e.srcElement; if(targetNode.nodeName.toLowerCase()==='tr'){ alert('You clicked a table row!'); } } /*如果你有一個很多行的大表格,在每個<tr>上綁定點擊事件是個非常危險的想法,因為性能是個大問題。流行的做法是使用事件委托。事件委托描述的是將事件綁定在容器元素上,然后通過判斷點擊的target子元素的類型來觸發相應的事件。 事件委托依賴於事件冒泡,如果事件冒泡到table之前被禁用的話,那上面的代碼就無法工作了。*/