变量对象(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之前被禁用的话,那上面的代码就无法工作了。*/