上篇文章對作用域和作用域鏈的基本概念有了一個詳細的介紹灭必,但是因為篇幅的原因沒有講解延長作用域鏈和塊級作用域稍浆,所以在這篇文章打算將這兩塊知識點進行補充炫惩。
延長作用域鏈
一般來說挤牛,執(zhí)行上下文中的作用域鏈是不會改變的臭家,但是在JS中忽匈,with
和try-catch
語句可以臨時的延長作用域鏈房午。
with語句
with語句為了簡化多次編寫訪問同一對象的工作,將一個特定的變量對象存儲到作用域鏈的最上層丹允。下面來看一個JavaScript高級程序設計上面的一個例子:
function buildUrl(){
var qs = "?debug=true";
with(location){
var url = href + qs;
}
return url;
}
console.log(buildUrl());//file:///C:/Users/Administrator/Desktop/%E7%8E%8B%E8%A7%82%E5%B9%B3/cityPicker/demo1.html?debug=true
在上面這段代碼中郭厌,with語句將location對象提升到了作用域鏈的最前端,那么原先的activation object就被處于第location對象的下方雕蔽。由于with關聯(lián)了location對象折柠,所以location在with內部相當于window對象的地位,甚至在用法方面也是一樣批狐,獲取location里面的屬性可以省略掉location扇售。JavaScript引擎對變量的處理方式是先查找該對象的屬性,如果是嚣艇,則停止查找承冰,如果不是,則繼續(xù)沿著作用域鏈查找食零。
從前面的說明中可以看出with的作用就是簡化代碼困乒,但是由于其將函數(shù)執(zhí)行時處于作用域鏈最前端的對象擠下一層沮榜,這樣會導致查詢的性能變慢补鼻;同時使用with語句還會帶來語義不明的問題,如下面代碼所示:
function fn(a,b){
with(a){
console.log(b);
}
}
調用fn函數(shù)的時候饿敲,輸出來的b可能是a對象里面的b屬性冈爹,也可能是傳入的參數(shù)b涌攻,還有可能是undefined,造成代碼的難以理解频伤;同時with語句會造成潛在的bug恳谎,具體代碼如下面所示:
function fn(obj){
with(obj){
a = 1;
}
};
var obj1 = {
a:2
};
var obj2 = {
b:3
};
fn(obj1);
fn(obj2);
console.log(obj1.a);//1
console.log(obj2.a);//undefined
console.log(a);//1
在上面的代碼中不難理解,在fn函數(shù)中憋肖,由于傳入的obj2沒有a屬性因痛,所以會將a屬性自動升級為全局變量(這與不加var字符串就直接聲明變量的原理是一樣的,即變量提升)岸更,而傳入的obj1中有a屬性鸵膏,就會修改obj1中的a屬性。所以怎炊,盡管with能夠延長作用域鏈谭企,但是由于其自身的缺陷導致在項目中使用并不高廓译。
try-catch語句
try-catch語句在JavaScript中用來處理異常,在catch(e){}中的錯誤對象組成了一個新的變量對象然后被加到了作用域的最前端债查。try-catch是個非常有用的語句非区,但是在使用前我們應當了解可能出現(xiàn)的錯誤。同時盹廷,我們可以簡化代碼來使catch子句對性能的影響最小化征绸,我們可以使用一個函數(shù)來處理錯誤,如下面代碼所示:
try{
fn();
}catch(ex){
handleError(ex);
}