javascript小結


一、說明

Javascript是動態語言,由瀏覽器執行,是解析性語言

二、介紹  (大部分從JavaScript高級程序設計(第2版)摘錄)

五種基本數據類型

基本類型值指的是那些保存在棧內存中的簡單數據段,即這種值完全保存在內存中的一個位置。基本類型有五種,UndefinedNullBooleanNumberString。還有一種復雜數據類型——Object(本質上是由一組無序的名值對組成)

可以使用使用typeof操作符來獲得數據類型:

l "undefined"——如果這個值未定義

l "boolean"——如果這個值是布爾值

l "string"——如果這個值是字符串

l "number"——如果這個值是數值

l "object"——如果這個值是對象或null

l "function"——如果這個值是函數

代碼:

View Code
 1 var a;
 2 var b = 1;
 3 var c = 'c';
 4 var d = {};
 5 var e = null;
 6 var f = true;
 7 var g=function(){
 8     
 9 };
10 function show() {
11     var aType = 'a:' + typeof a;
12     var bType = 'b:' + typeof b;
13     var cType = 'c:' + typeof c;
14     var dType = 'd:' + typeof d;
15     var eType = 'e:' + typeof e;
16     var fType = 'f:' + typeof f;
17     var gType = 'g:' + typeof g;
18 
19     alert(aType + "\n" + bType + "\n" + cType + "\n" + dType + "\n" + eType + "\n" + fType+"\n"+gType);
20 }

函數

函數使用function關鍵字來聲明,基本語法:

function functionName(arg0,arg1){

statements

}

 

注意下面幾點:

l 如果遇到return ; 函數會停止執行並返回undefined

l 所有參數傳遞都是值,不可能通過引用傳遞參數

l 參數在內部是用一個數組來表示的。函數接受到的始終都是這個數組,而不關心數組中包含哪些參數(如果有參數的話)。函數體內可以通過arguments對象來訪問這個參數。arguments對象只是與數組類似(並不是Array實例)。

l 沒有傳遞值的命名參數將自動被賦予undefined值

l 如果定義了兩個名字相同的函數,則后面的會覆蓋前面的。

l 除了什么時候可以通過變量訪問函數這一點區別外,函數聲明與函數表達式的語法其實是等價的。

l 要訪問函數的指針而不執行函數的話,必須去掉函數名后面的那對圓括號。

l 函數有兩個特殊的對象:arguments和this。arguments還有一個名叫callee的屬性(指針),指向擁有這個arguments對象的函數。this引用的是函數據以執行操作的對象。

l 每個函數都包含兩個屬性:length和prototype。length表示函數希望接受的命名參數的個數。

l 每個函數都包含兩個非繼承而來的方法:apply()和call()。這兩個方法的用途都是在特定的作用域中調用函數,實際上等於設置函數體內this對象的值。

l 每個函數都有一個非標准的caller屬性,該屬性指向調用當前函數的函數。(只建議將該屬性用於調試目的)。

l 函數實際上是對象,每個函數都是Function類型的實例,而且都與其他引用類型一樣具有屬性和方法。由於函數是對象,因此函數名實際上也是一個指向函數對象的指針,不會與某個函數綁定。

l arguments.callee是一個指向正在執行的函數的指針

l JavaScript中沒有私有成員的概念,所有對象屬性都是公有的。不過,在任何函數中定義的變量,都可以認為是私有變量,因此不能在函數的外部訪問這些變量。但有兩種方式創建特權方法

l 函數f1內部定義了另外一個函數f2,當f1執行完畢后,當f2仍存在,則其活動對象也不會被銷毀,因為f2的作用域仍然在引用這個活動對象,f1的執行環境的作用域鏈會被銷毀,但它的活動對象仍然會留在內存中,直到f2被銷毀后,f1的活動對象才會被銷毀。

 

構造函數

注意下面幾點:

l 構造函數在不返回值的情況下,默認會返回新對象實例。

l 寄生構造函數模式:返回的對象與構造函數或者與構造函數的原型屬性之前沒有關系:也就是說,構造函數返回的對象與在構造函數外部創建的對象沒有什么不同。

l 組合繼承=原型鏈+構造函數(會用到call或apply),是最常用的繼承模式

l 寄生組合式繼承是引用類型最理想的繼承范式,YUI的YAHOO.lang.extend()方法采用了寄生組合繼承,從而讓這種模式首次出現在了一個應用非常廣泛的javascript庫中

引用類型

引用類型值是指那些保存在堆內存中的對象,意思是變量中保存的實際上只是一個指針,這個指針指向內存中的另一個位置,該位置保存對象。

 

基本類型和引用類型在內存中保存情況如下圖:

 

注意下面幾點:

l 訪問對象屬性時一般都使用點表示法,不過也可以使用方括號表示法來訪問對象屬性,但屬性必須以字符串的形式放在方括號中。

l Array數組,每一項可以保存任何類型的數據,它的大小是可以動態調整的。

l 使用索引設置數組的值時,如果超過了數組現有項數,數組會自動增加到該索引值加1的長度

l 數組的length屬性不是只讀的。

l 數組有棧方法和隊列方法(IE對JavaScript的實現中存在一個偏差,其unshift方法總是返回undefined而不是數組的新長度)

l 引用類型與基本包裝類型的主要區別就是對象的生存期。使用new操作符創建的引用類型的實例,在執行流離開當前作用域之前都一直保存在內存中。而自動創建的基本包裝類型的對象,則只存在與一行代碼的執行瞬間,然后立即被銷毀。

l 對基本包裝類型的實例調用typeof會返回"object",而所有基本包裝類型的對象都會被轉換為布爾值true。

 

執行環境及作用域

執行環境定義了變量或函數有權訪問的其他數據,決定了它們各自的行為。每個執行環境都有一個與之關聯的變量對象,環境中定義的所有變量和函數都保存在這個對象中。雖然我們編寫的代碼無法訪問這個對象,但解析器在處理數據時會在后台使用它。

某個執行環境中的所有代碼執行完畢后,該環境被銷毀,保存在其中的所有變量和函數定義也隨之銷毀(如果還能在其他環境中被訪問到,則不銷毀)

環境的機制

存在環境棧,可把環境推入或彈出。當執行流進入一個函數時,函數的環境就會被推入一個環境棧中。而在函數執行之后,棧將其環境彈出,把控制權返回給之前的執行環境。

作用域鏈

當代碼在一個環境中執行時,會創建變量對象的一個作用域鏈。它的用途,是保證對執行環境有權訪問的所有變量和函數的有序訪問。

作用域鏈的前端,始終都是當前執行的代碼所在環境的變量對象。如果這個環境是函數,則將其活動對象作為變量對象。全局環境的變量對象始終都是作用域鏈中的最后一個對象。

標識符解析是沿着作用域鏈一級一級地搜索標識符的過程。

延長作用域鏈

try-catch語句的catch塊和with語句可以延長作用域鏈,即當執行流進入其中一個語句時,在作用域鏈的前端臨時增加一個變量對象,作用域鏈得到加長,該變量對象會在代碼執行后被已移除。(作用域增加的臨時變量對象都只是只讀的,所以在它們中定義的變量,成了函數執行環境的一部分)

注意下面幾點:

l JavaScript中沒有塊級作用域

l 變量在未經聲明的情況下被初始化,那么該變量會被自動添加到全局環境中。

l 局部變量會在它們離開執行環境時自動被解除引用(解除的真正作用是讓值脫離執行環境,以便垃圾收集器下次運行時將其回收)

l 垃圾收集策略:標記清除、引用計數(不常使用,除了IE,如果有循環引用會出現問題,需要手動斷開,即賦值為null,不然無法垃圾收集),不建議手動執行垃圾收集

頁面注意下面幾點:

l 在使用<script>嵌入JavaScript代碼時,不能在代碼的任何地方出現“</script>”字符串,會產生錯誤。因為按照解析嵌入式代碼的規則,當瀏覽器遇到字符串“</script>"時,就會認為那是結束的標簽。而通過把這個字符串分隔為兩部分可以解決這個問題。例如alert("<scr"+"ipt"/>);

l 解析器對<script>元素內部的所有代碼求值完畢以前,頁面中的 其余內容都不會被瀏覽器加載或顯示。

l 瀏覽器會按照<script>元素在頁面最后能夠出現的先后順序對它們依次進行解析。

l javascript代碼放在<head><body>的區別

l 變量定義沒有使用var,會看作全局變量

l 大量使用with語句會導致性能下降,同時也會給調試代碼造成困難,因此在開發大型應用程序時,不建議使用with語句。

l switch可以使用任何數據類型,每個case的值不一定是常量,可以是變量,甚至是表達式。switch語句在比較值時使用的是全等操作符,因此不會發生類型轉換(例如,字符串“10”不等於數值10)

 

三、理解

關於引用類型

javaC++中都采用了引用這個概念,但是二者的行為並不一樣。java的引用其實更象c++中的指針,而非c++中的引用

引用其實是特殊的"指針",它只是沒有指針運算(a++,a- -這些),這樣會更安全。所以聲明定義一個引用時,它都會在棧中建立一個空間。

var a={};

var b=a;

ab都代表同一個對象,而不是b擁有a的一個副本。

a存放了一個對象的內存地址,然后把地址賦值給了b,所以他們都指向同一個對象。注意的是,ab都擁有自己的棧空間。

 

關於string特殊的基本類型(希望有人可解答我疑問)

Javascript中的基本類型都存放在棧中,並且所占空間大小固定,可是string大小並不固定,它為什么也是基本類型?。下面是我對此的理解:

l 字符串值存放在棧中:

上面所說空間固定,指的是當已經存放了值后,值的大小已經確定了,無法改變。而並不是指string基本類型在存放值之前空間大小已經固定,所以可能出現有a,b兩個string類型的值,它們在棧中的空間大小卻不一樣

賦值操作時:

var a="a";

var b=a;

此時棧中有ab兩塊空間,存放的值都是"a",注意它們在不同的棧空間中。

l 字符串值存放在堆中:

上面所說空間固定,是指基本類型在存放值之前已經確定空間大小了。則string類型必定是一個引用,它存放指向堆空間的一個地址。可為什么不把它歸於基本類型呢?理由如下:

由於效率的原因,我們希望JS只復制對字符串的引用,而不是字符串的內容。但是另一方面,字符串在許多方面都和基本類型的表現相似,而字符串是不可變的這一事實(即沒法改變一個字符串值的內容),因此可以將字符串看成行為與基本類型相似的不可變引用類型。

 

關於關鍵字this

在 Java 等面向對象的語言中,this 關鍵字的含義是明確且具體的,即指代當前對象。一般在編譯期確定下來,或稱為編譯期綁定。而在 JavaScript 中,this 是動態綁定,或稱為運行期綁定的

我的理解是——this表示的是當前環境的變量對象。

匿名函數是全局性的理由是,它不存在除全局環境之外的任何環境中,也就是說沒有引用可以訪問得到它。這時的this是全局環境的window對象。

是否為匿名函數,主要看是否有引用指向它。

代碼:

View Code
/*
 * 是否為匿名函數,主要看是否有引用指向它
 */

var ob={};

ob.a=function () {
    (function() {//匿名函數
        alert("a this:" + this);
    })();
}


ob.b=function(){
     alert("b this:" + this);
}

ob.c=function(){
    return function(name){
       alert(name+" this:" + this); 
    };
}

ob.d=ob.c();//ob.c()返回一個匿名函數,但是ob.d指向了它,則它不再是匿名函數,this執行ob

function show() {
    ob.a();
    ob.b();
    ob.c()('c');//ob.c()得到一個匿名函數,可是卻沒有指針指向它,所以執行后this是window
    ob.d('d');
}

參考:JavaScript高級程序設計(第2版)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM