DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> JavaScript入門知識 >> 關於JavaScript >> Javascript教程:關於深入了解JS的幾個問題
Javascript教程:關於深入了解JS的幾個問題
編輯:關於JavaScript     

看了Dmitry Baranovskiy寫的這篇So, you think you know JavaScript?,也拜讀了Nicholas C. Zakas的答復,對Javascript的了解又進了一步,嘗試把自己的理解記錄如下
第一題:

DaimaRen.cn © 2009-2010 by Tomie Zhang
if (!("a" in window)) {
    var a = 1;
}
alert(a);

這一題是對JS變量的考察,這個測試翻譯成自然語言大意是:如果window裡不存在a這個屬性,那麼就定義個a的變量並給它賦值等於1。 這裡本來期望的值是1,但是很可惜它會彈出”undefined”,這是為什麼呢?首先javascript的全局變量都是window的屬性(properties),你可以用形如:

DaimaRen.cn © 2009-2010 by Tomie Zhang
alert("Daimaren.cn" in winodw)

來查看,var a = 1 等同於 window.a = 1,其次javascript引擎在掃描代碼時是將變量提前到scope之前運行,如:

DaimaRen.cn © 2009-2010 by Tomie Zhang
alert("a" in window);
var a;

其實在解析之後是

DaimaRen.cn © 2009-2010 by Tomie Zhang
var a;
alert("a" in window);

所以它的結果是true,最後javascript的聲明與初始化是分開的,

DaimaRen.cn © 2009-2010 by Tomie Zhang
var a = 1;
/*其實在運行時將變為*/
var a;
a=1;

javascript會自動將這兩個步驟分拆,Nicholas的解釋是這種分拆可以讓聲明前置在scope上方,而為什麼要這麼做,是因為聲明時就初始化變量,可能影響代碼運行時變量的值,導致意外的結果。
so,知道了這些,那麼開始那個測試其實在運行時會是這個樣子:

DaimaRen.cn © 2009-2010 by Tomie Zhang
var a;//自動前置運行的變量,沒有初始化
if (!("a" in window)) {//FLASE
    var a = 1;
}
alert(a);//彈出undefined

第二題:

DaimaRen.cn © 2009-2010 by Tomie Zhang
var a = 1,
b = function a(x) {
        x && a(--x);
};
alert(a);

如果理解上第一題,那這個題就很好解決了,這是關於function的,它有2種,一種是函數聲明(function declaration),一種是函數表達式(function expression),形如:

DaimaRen.cn © 2009-2010 by Tomie Zhang
function Daimaren(){//這是一個函數聲明
  do anything you want here........
}
var Daimaren = function(){//這是一個函數表達式
  do anything you want here........
}

所有的函數聲明在運行時是會被前置運行的,而函數表達式則不會,運行如下兩段代碼:

DaimaRen.cn © 2009-2010 by Tomie Zhang
foo();//將會彈出什麼呢?
function foo(){
	alert("i am a function function declaration from daimaren.cn");
}
var foo = function(){
	alert("i am a function function expression from daimaren.cn");
}
DaimaRen.cn © 2009-2010 by Tomie Zhang
function foo(){
	alert("i am a function function declaration from daimaren.cn");
}
var foo = function(){
	alert("i am a function function expression from daimaren.cn");
}
foo();//又將會彈出什麼呢?

通過這兩個例子我們可以請清楚的知道,第二題的答案將一直是1.
第三題

DaimaRen.cn © 2009-2010 by Tomie Zhang
function a(x) {
    return x * 2;
}
var a;
alert(a);

如果理解了前面的變量前置的概念,那這個也很好理解了,唯一不同的是函數聲明的優先級是高於普通的變量聲明的除非變量聲明被初始化,也就是說,上面這段代碼將先去執行function a而忽略掉var a,考慮如下:

DaimaRen.cn © 2009-2010 by Tomie Zhang
function a(x) {
    return x * 2;
}
var a = “1”;
alert(a);

第四題

DaimaRen.cn © 2009-2010 by Tomie Zhang
function b(x, y, a) {
    arguments[2] = 10;
    alert(a);
}
b(1, 2, 3);

這個很好理解,運行的值為10,這裡主要是對arguments的理解,引下ECMA-262第三版 10.1.8章節對arguments的解釋如下:

For each non-negative integer, arg, less than the value of the length property, a property is created with name ToString(arg) and property attributes { DontEnum }. The initial value of this property is the value of the corresponding actual parameter supplied by the caller. The first actual parameter value corresponds to arg = 0, the second to arg = 1, and so on. In the case when arg is less than the number of formal parameters for the Function object, this property shares its value with the corresponding property of the activation object. This means that changing this property changes the corresponding property of the activation object and vice versa.

參數對象相當於對應參數建立的副本,參數改變它也會跟著改變,他們的對應關系,例如在上面這個函數裡arguments[0]對應x,arguments[1]對應y,arguments[2]對應a,看起來似乎是array但是當你typof的時候會發現他們是object對象。對他們的對應關系理解如下例:

DaimaRen.cn © 2009-2010 by Tomie Zhang
function b(x, y, a) {
    arguments[2] = x;
    alert(a);//期望是3?但是看上一句,已經被指向了x,所以是1
}
b(1,2,3);

第五題

DaimaRen.cn © 2009-2010 by Tomie Zhang
function a() {
    alert(this);
}
a.call(null);

這個是call了(我比較頭疼的東西,囧,可是大師卻說是這5道題目裡最簡單的),來看下。首先,要搞清楚this指針是指向什麼的,Nicholas舉的例子:

DaimaRen.cn © 2009-2010 by Tomie Zhang
var o= {
    method: function() {
        alert(this === o);    //true
    }
}
o.method();

在method被呼叫的時候,tihs指向了o,因為它是o下的一個方法,它的上下文是在o中的,而如果它不在o這個object中,那麼它將會指向window:

DaimaRen.cn © 2009-2010 by Tomie Zhang
    function method() {
        alert(this === window);    //true
    }
o.method();

OK,那接下來要知道call是干什麼的,話說call是一個比較奇妙的方法,也很容易讓人迷糊,官方的解釋:

call 方法
請參閱
應用於:Function 對象
要求
版本 5.5
調用一個對象的一個方法,以另一個對象替換當前對象。

call([thisObj[,arg1[, arg2[, [,.argN]]]]])
參數
thisObj
可選項。將被用作當前對象的對象。
arg1, arg2, , argN
可選項。將被傳遞方法參數序列。
說明
call 方法可以用來代替另一個對象調用一個方法。call 方法可將一個函數的對象上下文從初始的上下文改變為由 thisObj 指定的新對象。

如果沒有提供 thisObj 參數,那麼 Global 對象被用作 thisObj。

官方解釋很容易讓人迷糊,Nicholas大濕的解釋如下:

The call() method executes a function as if it were a method of another object

那不如看個例子吧:

DaimaRen.cn © 2009-2010 by Tomie Zhang
function add(a,b)
{
    alert(a+b);
}
function sub(a,b)
{
    alert(a-b);
}
 
add.call(sub,3,1); //4

這裡其實就是用add的方法替換了sub的方法並且把參數值傳進去,等同於

DaimaRen.cn © 2009-2010 by Tomie Zhang
add.call(sub,3,1) == add(3,1)

好了,理解了this指針以及call,那回頭看這個題目,那它其實就相當於:

DaimaRen.cn © 2009-2010 by Tomie Zhang
function a() {
    alert(this);
}
a(null);

this不受任何影響指向的是a這個函數聲明,而a這個函數聲明則是一個object,於是結果就很明顯啦。
這算是半翻譯加半自己的理解,如有錯誤還請指教…. 另外Nicholas大師說有的人就喜歡拿這樣的題目當面試題,他覺得不尊重面試者也沒什麼用處,因為以上這些錯誤或者點不是平常工作都能遇到的,就如同面試乘務員而讓人家去解釋噴氣式動力的原理一樣…這個很贊同,學術研究下即可,如果拿去故意刁難人就有點不太好了。

XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved