一、self
這個(gè)非常簡單神僵。我們知道雁刷,打開任何一個(gè)網(wǎng)頁,瀏覽器會(huì)首先創(chuàng)建一個(gè)窗口保礼,這個(gè)窗口就是一個(gè)window對(duì)象沛励,也是js運(yùn)行所依附的全局環(huán)境對(duì)象和全局作用域?qū)ο笤鹩铩elf 指窗口本身,它返回的對(duì)象跟window對(duì)象是一模一樣的侯勉。也正因?yàn)槿绱损谐铮瑆indow對(duì)象的常用方法和函數(shù)都可以用self代替window铝阐。舉個(gè)例子址貌,常見的寫法如“self.close();”,把它放在<a>標(biāo)記中:“<a href="javascript:self.close();">關(guān)閉窗口</a>”徘键,單擊“關(guān)閉窗口”鏈接练对,當(dāng)前頁面關(guān)閉。
二吹害、this關(guān)鍵字
在講this之前螟凭,看下面的一段代碼:
<body>
<script type="text/javascript">
function thisTest()
{
this.textValue = 'this的dom測試';
this.element= document.createElement('span');
this.element.innerHTML = this.textValue;
this.element.style.color = "blue";
this.element.style.cursor = "pointer";
this.element.attachEvent('onclick', this.ToString);
}
thisTest.prototype.RenderDom = function()
{
document.body.appendChild(this.element);
}
thisTest.prototype.ToString = function()
{
alert("單擊我:"+this.textValue);
};
var test= new thisTest();
test.RenderDom();
//test.ToString();
</script>
</body>
本來的目的是想在body中添加一個(gè)span元素,對(duì)于這個(gè)span元素它呀,制定了它的字體顏色螺男,懸浮在它上面的鼠標(biāo)樣式和單擊觸發(fā)事件。問題就出現(xiàn)在它的單擊事件上(彈出"單擊我:undefined")纵穿。也許有人會(huì)說你丫傻呀下隧,寫這么多sb代碼還不就是為了實(shí)現(xiàn)下面這個(gè)東東嗎?
<span style='cursor:pointer;color:blue;' onclick="alert(this.innerHTML)">this的dom測試</span>
你看多簡單直觀谓媒,而且還不容易出錯(cuò)淆院?!kao句惯,我暈土辩。我正要講的是您正在使用的this.innerHTML中的this呀。
1抢野、this到底指什么拷淘?
我們熟悉的c#有this關(guān)鍵字,它的主要作用就是指代當(dāng)前對(duì)象實(shí)例(參數(shù)傳遞和索引器都要用到this)指孤。在javascript中启涯,this通常指向的是我們正在執(zhí)行的函數(shù)本身,或者是指向該函數(shù)所屬的對(duì)象(運(yùn)行時(shí))邓厕。
2逝嚎、常見使用方式
(1)、直接在dom元素中使用
<input id="btnTest" type="button" value="提交" onclick="alert(this.value))" />
分析:對(duì)于dom元素的一個(gè)onclick(或其他如onblur等)屬性详恼,它為所屬的html元素所擁有补君,直接在它觸發(fā)的函數(shù)里寫this,this應(yīng)該指向該html元素昧互。
(2)挽铁、給dom元素注冊js函數(shù)
a伟桅、不正確的方式
<script type="text/javascript">
function thisTest(){
alert(this.value); // 彈出undefined, this在這里指向??
}
</script>
<input id="btnTest" type="button" value="提交" onclick="thisTest()" />
分析:onclick事件直接調(diào)用thisTest函數(shù),程序就會(huì)彈出undefined叽掘。因?yàn)閠hisTest函數(shù)是在window對(duì)象中定義的楣铁,
所以thisTest的擁有者(作用域)是window,thisTest的this也是window更扁。而window是沒有value屬性的盖腕,所以就報(bào)錯(cuò)了。
b浓镜、正確的方式
<input id="btnTest" type="button" value="提交" />
<script type="text/javascript">
function thisTest(){
alert(this.value);
}
document.getElementById("btnTest").onclick=thisTest; //給button的onclick事件注冊一個(gè)函數(shù)
</script>
分析:在前面的示例中溃列,thisTest函數(shù)定義在全局作用域(這里就是window對(duì)象),所以this指代的是當(dāng)前的window對(duì)象膛薛。而通過document.getElementById("btnTest").onclick=thisTest;這樣的形式听隐,其實(shí)是將btnTest的onclick屬性設(shè)置為thisTest函數(shù)的一個(gè)副本,在btnTest的onclick屬性的函數(shù)作用域內(nèi)哄啄,this歸btnTest所有雅任,this也就指向了btnTest。其實(shí)如果有多個(gè)dom元素要注冊該事件咨跌,我們可以利用不同的dom元素id沪么,用下面的方式實(shí)現(xiàn):
document.getElementById("domID").onclick=thisTest; //給button的onclick事件注冊一個(gè)函數(shù)。
因?yàn)槎鄠€(gè)不同的HTML元素雖然創(chuàng)建了不同的函數(shù)副本虑润,但每個(gè)副本的擁有者都是相對(duì)應(yīng)的HTML元素成玫,各自的this也都指向它們的擁有者,不會(huì)造成混亂拳喻。
為了驗(yàn)證上述說法哭当,我們改進(jìn)一下代碼,讓button直接彈出它們對(duì)應(yīng)的觸發(fā)函數(shù):
<input id="btnTest1" type="button" value="提交1" onclick="thisTest()" />
<input id="btnTest2" type="button" value="提交2" />
<script type="text/javascript">
function thisTest(){
this.value="提交中";
}
var btn=document.getElementById("btnTest1");
alert(btn.onclick); //第一個(gè)按鈕函數(shù)
var btnOther=document.getElementById("btnTest2");
btnOther.onclick=thisTest;
alert(btnOther.onclick); //第二個(gè)按鈕函數(shù)
</script>
其彈出的結(jié)果是:
//第一個(gè)按鈕
function onclick(){
thisTest()
}
//第二個(gè)按鈕
function thisTest(){
this.value="提交中";
}
從上面的結(jié)果你一定理解的更透徹了冗澈。
By the way钦勘,每新建一個(gè)函數(shù)的副本,程序就會(huì)為這個(gè)函數(shù)副本分配一定的內(nèi)存亚亲。而實(shí)際應(yīng)用中彻采,大多數(shù)函數(shù)并不一定會(huì)被調(diào)用,于是這部分內(nèi)存就被白白浪費(fèi)了捌归。所以我們通常都這么寫:
<input id="btnTest1" type="button" value="提交1" onclick="thisTest(this)" />
<input id="btnTest2" type="button" value="提交2" onclick="thisTest(this)" />
<input id="btnTest3" type="button" value="提交3" onclick="thisTest(this)" />
<input id="btnTest4" type="button" value="提交4" onclick="thisTest(this)" />
<script type="text/javascript">
function thisTest(obj){
alert(obj.value);
}
</script>
這是因?yàn)槲覀兪褂昧撕瘮?shù)引用的方式肛响,程序就只會(huì)給函數(shù)的本體分配內(nèi)存,而引用只分配指針惜索。這樣寫一個(gè)函數(shù)特笋,調(diào)用的地方給它分配一個(gè)(指針)引用,這樣效率就高很多巾兆。當(dāng)然猎物,如果你覺得這樣注冊事件不能兼容多種瀏覽器虎囚,可以寫下面的注冊事件的通用腳本:
//js事件 添加 EventUtil.addEvent(dom元素,事件名稱,事件觸發(fā)的函數(shù)名) 移除EventUtil.removeEvent(dom元素,事件名稱,事件觸發(fā)的函數(shù)名)
var EventUtil = new eventManager();
//js事件通用管理器 dom元素 添加或者移除事件
function eventManager() {
//添加事件
//oDomElement:dom元素,如按鈕,文本,document等; ****** oEventType:事件名稱(如:click,如果是ie瀏覽器,自動(dòng)將click轉(zhuǎn)換為onclick);****** oFunc:事件觸發(fā)的函數(shù)名
this.addEvent = function(oDomElement, oEventType, oFunc) {
//ie
if (oDomElement.attachEvent) {
oDomElement.attachEvent("on" + oEventType, oFunc);
}
//ff,opera,safari等
else if (oDomElement.addEventListener) {
oDomElement.addEventListener(oEventType, oFunc, false);
}
//其他
else {
oDomElement["on" + oEventType] = oFunc;
}
}
this.removeEvent = function(oDomElement, oEventType, oFunc) {
//ie
if (oDomElement.detachEvent) {
oDomElement.detachEvent("on" + oEventType, oFunc);
}
//ff,opera,safari等
else if (oDomElement.removeEventListener) {
oDomElement.removeEventListener(oEventType, oFunc, false);
}
//其他
else {
oDomElement["on" + oEventType] = null;
}
}
}
正像注釋寫的那樣,要注冊dom元素事件蔫磨,用EventUtil.addEvent(dom元素,事件名稱,事件觸發(fā)的函數(shù)名)即可淘讥, 移除時(shí)可以這樣寫:EventUtil.removeEvent(dom元素,事件名稱,事件觸發(fā)的函數(shù)名)。這是題外話堤如,不說了蒲列。
(3)、類定義中使用this關(guān)鍵字
這個(gè)其實(shí)再常見不過煤惩,看示例:
function thisTest()
{
var tmpName = 'jeff wong';
this.userName= 'jeff wong';
}
var test= new thisTest();
alert(test.userName==test.tmpName);//false
alert(test.userName); //jeff wong
alert(test.tmpName); //undefined
分析一下結(jié)果嫉嘀,其實(shí)這里的this和c#里的是類似的。
(4)魄揉、為腳本對(duì)象添加原形方法
理解這里的前提是你必須了解js里的原型概念(說道這里,kao拭宁,我還真的需要面壁一下):js中對(duì)象的prototype屬性洛退,是用來返回對(duì)象類型原型的引用的。所有js內(nèi)部對(duì)象都有只讀的prototype屬性杰标,可以向其原型中動(dòng)態(tài)添加功能(屬性和方法)兵怯,
但該對(duì)象不能被賦予不同的原型。但是對(duì)于用戶定義的對(duì)象可以被賦給新的原型腔剂∶角看個(gè)簡單的示例:
//js的內(nèi)部對(duì)象String,向其原型中動(dòng)態(tài)添加功能(屬性和方法)
//去掉字符串兩端的空白字符
String.prototype.Trim = function() {
return this.replace(/(^\s+)|(\s+$)/g, "");
}
function thisTest()
{
var tmpName = 'jeff wong';
this.userName= ' jeff wong ';
}
//給用戶定義的對(duì)象添加原型方法
thisTest.prototype.ToString = function()
{
alert(this.userName); //jeff wong(*有空格*)
alert(this.userName.Trim()); //jeff wong (*無空格*)
//alert(tmpName); //腳本錯(cuò)誤,tmpName未定義
}
var test= new thisTest();
test.ToString(); //調(diào)用原型的ToString()
function myTest(){
this.userName= ' test ';
}
var test1=new myTest();
//test1.ToString(); //這里暫時(shí)不支持調(diào)用ToString()方法
//用戶定義的對(duì)象被賦給新的原型
myTest.prototype = new thisTest();
test1.ToString(); //調(diào)用原型的ToString()
測試結(jié)果顯示,這里的this指代的是被添加原形(方法或?qū)傩裕┑念惖膶?shí)例掸犬,和(3)中的定義基本相似袜漩。
(5)、在函數(shù)的內(nèi)部函數(shù)中使用this關(guān)鍵字
這個(gè)你要是理解作用域和閉包湾碎,問題就迎刃而解宙攻。看最典型的示例:
function thisTest()
{
this.userName= 'outer userName';
function innerThisTest(){
var userName="inner userName";
alert(userName); //inner userName
alert(this.userName); //outer userName
}
return innerThisTest;
}
thisTest()();
分析:thisTest()調(diào)用內(nèi)部的innerThisTest函數(shù)介褥,形成一個(gè)閉包座掘。innerThisTest執(zhí)行時(shí),第一次彈出innerUserName柔滔,是因?yàn)閕nnerThisTest函數(shù)作用域內(nèi)有一個(gè)變量叫userName溢陪,所以直接彈出當(dāng)前作用域下變量的指定值;第二次彈出outer userName是因?yàn)閕nnerThisTest作用域內(nèi)沒有userName屬性(示例中的this.userName),所以它向上一級(jí)作用域中找userName屬性睛廊,這次在thisTest中找到(示例中的this.userName= 'outer userName';)形真,所以彈出對(duì)應(yīng)值。
(6)通過Function的call和apply函數(shù)指定特定的this
這個(gè)指定來指定去喉前,this就有可能造成“你中有我没酣,我中有你”的局面王财,不想把自己弄暈了的話,了解一下就可以了裕便。改變this指定對(duì)象對(duì)于代碼維護(hù)也是一件很不好的事情绒净。貼出舊文中的示例代碼結(jié)束吧:
function myFuncOne() {
this.p = "myFuncOne-";
this.A = function(arg) {
alert(this.p + arg);
}
}
function myFuncTwo() {
this.p = "myFuncTwo-";
this.B = function(arg) {
alert(this.p + arg);
}
}
function test() {
var obj1 = new myFuncOne();
var obj2 = new myFuncTwo();
obj1.A("testA"); //顯示myFuncOne-testA
obj2.B("testB"); //顯示myFuncTwo-testB
obj1.A.apply(obj2, ["testA"]); //顯示myFuncTwo-testA,其中[ testA”]是僅有一個(gè)元素的數(shù)組
obj2.B.apply(obj1, ["testB"]); //顯示myFuncOne-testB,其中[ testB”]是僅有一個(gè)元素的數(shù)組
obj1.A.call(obj2, "testA"); //顯示myFuncTwo-testA
obj2.B.call(obj1, "testB"); //顯示myFuncOne-testB
}
總結(jié):到這里,對(duì)于開篇中的span彈出undefined的問題你是不是已經(jīng)豁然開朗偿衰?如果你還在懵懂中挂疆,給個(gè)可有可無的提示:當(dāng)前的這個(gè)span元素有沒有textValue屬性啊O卖帷缤言?
三、void
1视事、定義
javascript中void是一個(gè)操作符胆萧,該操作符指定要計(jì)算一個(gè)表達(dá)式但是不返回值。
2俐东、語法
void 操作符用法格式如下:
(1). javascript:void (expression)
(2). javascript:void expression
注意:expression是一個(gè)要計(jì)算的js標(biāo)準(zhǔn)的表達(dá)式跌穗。表達(dá)式外側(cè)的圓括號(hào)是可選的,但是寫上去你可以一眼就知道括弧內(nèi)的是一個(gè)表達(dá)式(這和typeof后面的表達(dá)式語法是一樣的)虏辫。
3蚌吸、實(shí)例代碼
function voidTest() {
void (alert("it is a void test")); //執(zhí)行函數(shù)
var oTestNum = 1;
void (oTestNum++); //整數(shù)自加
alert(oTestNum);
oTestNum = 1;
void (oTestNum += " void test"); //整數(shù)加字符串
alert(oTestNum);
}
voidTest();
4、在a元素下使用void(0)
(1)適用情況
在網(wǎng)頁中砌庄,我們經(jīng)掣耄看到html里的a標(biāo)簽不需要它導(dǎo)航到某一個(gè)頁面時(shí),href屬性設(shè)置的寫法:
<a href="#">link1</a>
<a href="javascript:void(0);">link2</a>
注意:第一種“#”的寫法(其實(shí)#可以是多個(gè)娄昆,通常都是1個(gè))佩微,當(dāng)a元素所在的鏈接在瀏覽器一屏以下時(shí),會(huì)導(dǎo)致頁面回滾到頂部稿黄;所以當(dāng)我們需要a標(biāo)簽不導(dǎo)航到其他頁面喊衫,不需要網(wǎng)頁位置的回滾,都會(huì)采取void(0)那種寫法杆怕。
(2)ie6下void(0)造成的詭異問題
這個(gè)問題網(wǎng)上有很多討論族购,個(gè)人認(rèn)為“落葉滿長沙”總結(jié)的很有代表性,這里就不再贅述了陵珍。