「JavaScript高級プログラム設計」メモ:関数式(7)

18619 ワード

再帰する
function factorial(num){
    if(num<=1){
        return 1;
    }else {
        return num * arguments.callee(num-1);
    }
}

console.log(factorial(4));
ただし、コードが厳密なパターンの下開発であれば、
"use strict";
function factorial(num){
    if(num<=1){
        return 1;
    }else {
        return num * arguments.callee(num-1);
    }
}

console.log(factorial(4));
結果:Uncaught TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them厳密なモードではスクリプトでarguments.calleeにアクセスできません.この属性にアクセスするとエラーが発生します.ネーミング関数式を使用して同じ結果に達することができます.
"use strict";
var factorial = (function f(num){
     if(num<=1){
        return 1;
    }else {
        return num * f(num-1);
    }
})

console.log(factorial(4)); //24
上記のコードはf()という名前の関数式を作成し、変数factorialに値を与えます.すなわち関数の値を他の変数に与えます.関数の名前はまだ有効です.
包みを閉じる
クローズドとは、別の関数のスコープにアクセスする権限を持つ変数の関数です.
クローズドと変数
作用するドメインチェーンのこの構成機構は,関数内の任意の変数を含む最後の値しか得られないという注意すべき副作用を引き出した.クローズドが保存されているのは変数オブジェクト全体であり、特定の変数ではないことを忘れないでください.
function createFunctions(){
    var result = new Array();

    for (var i=0; i<10; i++){
        result[i] = function(){
            return i;
        }
    }

    return result;
}
他の匿名関数を作成することによって強制的に閉じられた挙動を予想通りにすることができます.
function createFunctions(){
    var result = new Array();

    for (var i=0; i<10; i++){
        result[i] = function(num){
            return function(){
                return num;
            };
        }(i);
    }

    return result;
}
thisオブジェクトについて
大域関数では、thisはwindowに等しく、関数があるオブジェクトの方法として呼び出されると、thisはそのオブジェクトに等しくなります.しかし、匿名関数の実行環境は大域的であるため、そのthisオブジェクトは一般にwindowを指す.
var name = "The window";

var object = {
    name: "My Object",
    getNameFunc: function(){
        return function(){
            return this.name;
        };
    }
};

console.log(object.getNameFunc()()); // The window
ただし、外部作用領域のthisオブジェクトを一つのクローズドパケットでアクセスできる変数に保存すると、クローズドがそのオブジェクトにアクセスできるようになります.
var name = "The window";

var object = {
    name: "My Object",
    getNameFunc: function(){
        var that = this;
        return function(){
            return that.name;
        };
    }
};

console.log(object.getNameFunc()()); // My Object 
次のコードを見てください
var name = "The window";
var object = {
    name: "My Object",
    getName: function(){
        console.log(this.name);
    }
}

object.getName(); // My Object 
(object.getName)(); // My Object 
(object.getName = object.getName)(); // The window
で呼び出した結果を分析します.
第一行コードはいつものようにobject.getName()を呼び出してMy Object に戻りました.this.nameはobject.nameです.
第二行コードは、この方法を呼び出す前に括弧を入れます.括弧を入れると、関数を引用するだけのようですが、object.getName(object.getName)の定義は同じですので、thisは維持する価値があります.
第三行コードは、最初に割り当てられたステートメントを実行してから、その結果を呼び出します.この割当式の値は関数自体であるため、thisの値は維持できず、結果としてThe windowに戻ります.
もちろん、第二行と第三行のコードのようにこの方法を呼び出すことはできません.この例は、わずかな文法的変化を説明するだけで、いずれも意外な変化があるthisの値です.
メモリリーク
function assignHandler(){
                var element=document.getElementById('someElement');
                element.onclick=function(){
                    alert(element.id);
                }
            }
            
上記のコードはメモリを使っています.永遠に消えません.コードを修正して次のように解決します.
function assignHandler(){
        var element = document.getElementById('someElement');
        var id = element.id;
        element.onclick = function(){
            alert(id);
        }
        element = null;
    }
    
ブロックレベルのスコープを模倣する
ブロックレベルのスコープ(一般にはプライベートスコープと呼ばれる)を用いた匿名関数のシンタックスは、以下のように示されている.
(function(){
})();
プライベート変数
function add(num1,num2){
    var sum=num1+num2;
    return sum;
}
この関数の内部には三つのプライベート変数があります.sum,num 1,num 2.関数の内部でこれらの変数にアクセスできます.ただし、関数の外部ではそれらにアクセスできません.この関数の内部にクローズドパケットを作成すると、クローズドは自分のロールドメインチェーンを通してこれらの変数にもアクセスできます.この点を利用して、プライベート変数にアクセスするための共有方法を作成することができます.
私たちはプライベート変数とプライベート関数にアクセスする権利がある公開方法を特権方法と呼びます.相手に特権を作る方法は二つあります.第一は、構造関数において特権的な方法を定義することである.基本パターンは以下の通りです.
function myObejct(){
    //         
    var privateVariable=10;

    function privateFunction(){
        return false;
    }

    //    
    this.publicMethod=function(){
        privateVariable++;
        return privateFunction();
    }
}
プライベートおよび特権のメンバーを利用して、直接に変更すべきでないデータを隠すことができます.例えば、
function Person(name){
    this.getName=function(){
        return name;
    }
    this.setName=function(value){
        name=value;
    }
}
var person=new Person("Nicholas");
alert(person.getName());//Nicholas
person.setName("Greg");
alert(person.getName());//Greg
静的プライベート変数
プライベートスコープにプライベート変数や関数を定義することによって、特権的な方法を作成することもできます.その基本パターンは以下の通りです.
(function(){
    //         
    var privateVariable=10;

    function privateFunction(){
        return false;
    }
    //    
    MyObject=function(){

    };
    //  /    
    MyObject.prototype.publicMethod=function(){
        privateVariable++;
        return privateFunction();
    }
    
})();
もう一つの例を見ます.
(function(){
    var name = "";
    Person = function(value){
        name = value;
    };
    
    Person.prototype.getName = function(){
        return name;
    };

    Person.prototype.setName = function(value){
        name = value;
    };
})();

var person1 = new Person("Nicholas");
console.log(person1.getName()); //Nicholas
person1.setName('Grey');
console.log(person1.getName()); //Grey

var person2 = new Person("Michael");
console.log(person1.getName()); //Michael
console.log(person2.getName()); //Michael
一例でsetName()を呼び出すと、すべてのインスタンスに影響を与えます.
モジュールモード
モジュールモードは、一例でプライベート変数と特権を作成する方法です.一例とは、一例だけのオブジェクトのことです.慣例として、jsは対象の字面量の方式で単例オブジェクトを作成します.
var singleton={
    name:value,
    method:function(){
        //        
    }
};
モジュールモードは、一例に対してプライベート変数と特権方法を追加することにより、それを強化することができる.その文法形式は以下の通りです.
var singleton=function(){
    //         
    var privateVariable=10;

    function privateFunction(){
        return false;
    }
    //  /       
    return {
        publicProperty:true,
        publicMethod:function(){
            privateVariable++;
            return privateFunction();
        }
    }
}();
強化モジュールモード
var singleton=function(){

    //         
    var privateVariable=10;

    function privateFunction(){
        return false;
    }

    //    
    var object=new CustomType();

    //    /       
    object.publicProperty=true;

    object.publicMethod=function(){
        privateVariable++;
        return privateFunction();
    }

    //      
    return object;
}();