close

注意

以下內容是大爺學習Javascript的整理筆記,絕無侵犯作者版權之意,如作者不希望小弟截錄,請來信告知謝謝。

以下內容截錄「Javascript大全-第五版」這本書。部份章節內容拷貝至其它網站,都在標題有文章的相關連結,如果內容有錯誤,麻煩還留個言,謝謝。


1.函式實字

函式實字是定義「不具名函式」的運算式。
例:
var f= function fact (x) { 
    if (x <=1) 
        return 1; 
    else 
        return X*fact(x-1); };


2.選擇性參數
以「不夠的參數」呼叫(不是宣告)函式時,其他的參數值會定義成「undefined」。

function copyPropertyNamesToArray(o, /* optional */ a){
    if (!a) a=[ ]; //如果是 undefined 或 null,則使用空陣列
    for ( var property in o ) 
        a.push (property);
    return a;
}

更有彈性的呼叫:
var a = copyPropertyNamesToArray(o); //取得o的屬性加到新陣列
copyPropertyNamesToArray(p,a); //附加 p 的屬性到那個陣列


3.長度變動的參數清單:Arguments 物件
查驗函式是否以正確的參數數目被呼叫:
function f (x, y, z){
    //檢查是不是傳來正確的參數數目。
    if (arguments.length != 3) {
        throw new Error("function f called with " + arguments.length + "arguments, but it expects 3 arguments.");
    }
    //…以下是函式主體
}

函式接受任意數目參數
function max (/*…*/){
    var m = Number.NEGATIVE_INFINITY;

    //繞遍所有的參數,找出並記住最大的值
    for ( var i=0; i < arguments.length; i++)
        if (arguments[i] > m) m = arguments[i];
     
    //傳回最大值
    return m;
}
Arguments 不是真正的陣列,它是一個Arguments物件。雖然每個Arguments物件也定義有編號的陣列元素和length屬性,但技術上它仍不是陣列;最好將它視為剛好具有「編號屬性的物件」。
Arguments 物件有一個非常獨特的功能。當「函數有具名的參數」時,Arguments物件的「陣列元素」是「存放函式參數的區域變數的同義詞」。arguments [ ] 陣列和具名參數不過是指向同一變數的兩種不同方式。利用「參數名稱」改變參數之值,將同時改變透過arguments [ ] 陣列取得的值。相反地,經由arguments [ ] 陣列改變參數的值,同樣會改變以參數名稱取得的參數值。

4.callee屬性
這個屬性代表現在正在執行的函式,它可以讓未命名的函式自已遞迴呼叫自已。
計算階乘
function (x){
    if (x <= 1) return 1;
       return x * arguments.callee(x-1);
}
5.物件屬性作為參數
利用傳遞物件實字的方式「name / value」 來達成任意順序傳遞,但這個方法較沒效率。
function easycopy(args){
    arraycopy(args.from,
                   args.from_start || 0, //提供預設值
                   args.to,
                   args.to_start || 0,
                   args.length);
}
//呼叫easycopy();
var a = [1,2,3,4];
var b = new Array (4);
easycopy({from: a, to: b, length: 4});


6.參數型態
檢查傳遞型態是否正確
//回傳陣列 ( 或類似陣列物件) 元素的總和 a 
// a 元素必須都是數字,null 和 undefined 元素則忽略。
function sum (a) {
    if (( a instanceof Array) || ( a && typeof a == "object" && "length" in a)) { /判斷是否為陣列,或是否類似陣列
        var total=0;
        for ( var i=0; i < a.length; i++){
            var element = a[i];
            if (!element) continue; //略過 null 和 undefined參數
            if (typeof element == "number") total += element;
            else throw new Error ( " sum() : all array elements must be numbers");
        }
        return total;
    }
    else throw new Error ( "sum(): argument must be an array");
}

把非數值轉成數值,或按型態處理
function flexisum(a){
    var  total =0;
    for(var i=0; i < arguments.length; i++){
        var element = arguments[i];
        if (!element) continue; //忽略 null 或 undefined參數
        
        //轉換參數型態成數字n,或以它的型態主
        switch ( typeof element){
        case "number":
            n = element;    //不用轉換
            break;
        case "object":
            if ( element instanceof Array) //
                n = flexisum.apply(this, element); //給陣列遞迴
            else
                n= element.valueOf(); //給其他物件的 valueOf method
            break;
        case "function":
            n = element();    //嘗試呼叫函式
            break;
        case "string":
            n = parseFloat(element); //嘗試解析字串
            break;
        case "boolean":
            n= NaN;    //無法轉換布林值
            break;
        }//switch end

        //如果得到有效的數字,加到總和。
        if (typeof n == "number" && !isNaN(n))
             total += n;
        else 
            throw new Error ( "sum(): can't convert " + element + "to number");  //否則傳回錯誤訊息
    }//for end

    return total;

}end function


7.函式資料
函式指定給物件屬性,這些函式就叫做method
var o=new Object
o.square= function (x) { return x*y; } //函式實字
y=o.square(16); //y=256

函式指定給陣列元素,函式不需名稱
var a = new Array(3);
a[0] = function (x) { return x*y;}
a[1] = 20;
a[2] = a[0] ( a[1] ); // a[2] = 400

函式當作資料使用
範例1:
//定義一些簡單的函式
function add (x,y) { return x+y; }
function subtract (x,y) { return x-y; }
function multiply (x,y) {return x*y; }
function divide (x,y) { return x/y; }

//將上面函式之一當作參數,並用兩個運算元呼叫
function operate ( operator, operand1, operand2){
    return operator ( operand1, operand2);
}

//呼叫函式,計算 (2+3) (4*5)
var i= operate(add, operate (add, 2, 3), operate (multiply, 4, 5));

範例2:
//在物件實字內使用函式實字
var operators = {
    add:        function (x,y) { return x+y; },
    subtract:  function (x,y) { return x-y; },
    multiply:  function (x,y) { return x*y; },
    divide:     function (x,y) { return x/y; },
    pow:       Math.pow //事先定義的函式也有用
}

//函式在物件中尋找運算子,取得它的名稱
//然後用所給的運算元呼叫函式
//注意這裡呼叫運算子函式用的語法
function operate2 (op_name, operand1, operand2){
    if ( typeof operators[op_name] == "function")
        return operators[op_name] (operand1, operand2);
    else
        throw "unknown operator";
}

//呼叫函式,計算 ("hellow" + " " + "world" ) 的值
var j= operate2 ("add', "hellow", operate2 ("add", " ", "world"));
//使用預先定義的 Math.pow() 函式
var k = operate2 ("pow", 10, 2)


8.length屬性
arguments陣列的length屬性是「指傳遞給函式的參數數目」。
函式自已的length屬性則是指函式「需要」的參數數目,並且這個屬性是唯讀的,並且在函式主體的裡面和外面皆可使用

function check(args) {
    var actual = args.length; //實際的參數個數
    var expected = args.calle.length; //要求的參數個數
    if (actual != expected) {
        throw new Error(" Wrong number of arguments: expected: " + expected + "; actually passed " + actual);
    }
}

function (x,y,z){
    //檢查實際的參數個數與要求的參數個數是否相符
    //如果不符合,丟出例外事件
    check(arguments);
    //正常執行函式其餘部份
    return x+y+z;
}


9.自定函式屬性
當函式在呼叫期間,可以使用Function物件的屬性,來定義一個不變的變數值。

//建立並初始化「靜態」變數
//函式的宣告會在程式執行前被處理,所以可以在函式宣告前這麼做

uniqueInteger.counter = 0;

//這個函式在每次被呼叫時,都會傳回一個不同的值
//並用函式自已的「靜態」屬性記錄前一次傳回的值
function uniqueInteger(){
    //遞增並傳回「靜態」變數
    return uniqueInteger.counter++;
}


10.apply()與call() method

以下文章內容僅截錄一小部份,完整內容請連結至:http://webdesign.kerthis.com/post/javascript-call-%E8%88%87-apply-%E5%87%BD%E5%BC%8F

call()和apply()是用來呼叫(執行)函式,而使用call(或apply)呼叫函式與傳統使用( )運算符呼叫函式的差異在哪?

利用call和apply呼叫函數可以改變函數內部的this所指向的對象(Object)。

也可以解釋成

利用call和apply你可以在一物件(Object)內部引用屬於另一個物件的函式來自用。…… 

 (請參考原作者網站)


11.函式範圍與Closure

語彙範圍(lexical scoping)、範圍鏈、Call物件

以下文章內容僅截錄一小部份,完整內容請連結至:http://caterpillar.onlyfun.net/Gossip/JavaScript/ScopeChain.html


 變數 中談過變數範圍的問題,當時的說明是:使用var所宣告的變數,作用範圍是在當時所在環境,不使用var直接指定值而建立的變數,則是全域物件上的一個特性,也就是俗稱的全域範圍。單就使用JavaScript而言,這就足以瞭解使用變數時,有無使用var的差別。

在 
closure(Closure) 中則以自由變數的觀念,從語法層面說明closure的意義與作用,也可應付絕大多數的情況。

事實上,JavaScript在查找變數時,會循著範圍鏈(Scope chain)一層一層往外找,範圍鏈的觀念可說明為何JavaScript沒有區域範圍,也可是JavaScript中closure的實現機制。

要瞭解範圍鏈,首先得瞭解一些名詞。
首先是語彙範圍(Lexical Scope),這代表著JavaScript原始碼的物理位置(Physical placement)。例如:

var x = 10;
function outer() {
    var y = 20;
    function inner() {
        var z = 30;
    }
}
func();


 (請參考原作者網站)


Closure

以下文章內容僅截錄一小部份,完整內容請連結至:http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html

 (closure)是Javascript語言的一個難點,也是它的特色,很多高級應用都要依靠closure實現。

下面就是我的學習筆記,對於Javascript初學者應該是很有用的。

一、變數的作用域

要理解closure,首先必須理解Javascript特殊的變數作用域。

變數的作用域無非就是兩種:全局變數和局部變數。

Javascript語言的特殊之處,就在於函數內部可以直接讀取全局變數。

var n=999;

  function f1(){
    alert(n);
  }

  f1(); // 999

另一方面,在函數外部自然無法讀取函數內的局部變數

function f1(){
    var n=999;
  }

alert(n); // error

這裡有一個地方需要注意,函數內部聲明變數的時候,一定要使用var命令。如果不用的話,你實際上聲明了一個全局變數!

  function f1(){
    n=999;
  }

  f1();

  alert(n); // 999


二、如何從外部讀取局部變數?

出於種種原因,我們有時候需要得到函數內的局部變數。但是,前面已經說過了,正常情況下,這是辦不到的,只有通過變通方法才能實現。

那就是在函數的內部,再定義一個函數。

  function f1(){

    n=999;

    function f2(){
      alert(n); // 999
    }

  }

 (請參考原作者網站)


三、closure的概念

上一節程式碼中的f2函數,就是closure。

各種專業文獻上的"closure"(closure)定義非常抽象,很難看懂。我的理解是,closure就是能夠讀取其他函數內部變數的函數。

由於在Javascript語言中,只有函數內部的子函數才能讀取局部變數,因此可以把closure簡單理解成"定義在一個函數內部的函數"。

所以,在本質上,closure就是將函數內部和函數外部連接起來的一座橋樑。

四、closure的用途

closure可以用在許多地方。它的最大用處有兩個,一個是前面提到的可以讀取函數內部的變數另一個就是讓這些變數的值始終保持在記憶體中

 (請參考原作者網站)

五、使用closure的注意點

1)由於closure會使得函數中的變數都被保存在記憶體中,記憶體消耗很大,所以不能濫用closure,否則會造成網頁的性能問題,在IE中可能導致記憶體洩露。解決方法是,在退出函數之前,將不使用的局部變數全部刪除。

2) (請參考原作者網站)

六、思考題

如果你能理解下面兩段程式碼的運行結果,應該就算理解closure的運行機制了。

程式碼片段一。

  var name = "The Window";

  var object = {

  (請參考原作者網站)


程式碼片段二。

var name = "The Window";

  var object = {
    name : "My Object",

    (請參考原作者網站)


12.function()建構式

var f = function ("x", "y", "return x*y;");

相同於

function f(x, y) { return x*y; }

arrow
arrow
    全站熱搜

    大爺 發表在 痞客邦 留言(0) 人氣()