JavaScriptを深く勉強する(二)

7468 ワード

関数式と関数宣言
関数宣言
 function    (  ){   }
関数式
function    (  )(  ){   }
例:
function foo(){} //   ,          
var bar = function foo(){}; //    ,             
new function bar(){}; //    ,    new   

(function(){
function bar(){} //   ,           
  })();
もう一つの一般的ではない関数式
function foo(){}//    
(function foo(){});//     ,               ,                             
//                  
try{
    (var x=5);  //var x=5     ,      
}catch(err){
    alert(err);
}
関数表現と関数宣言の役割は?
関数宣言は、関数式が解析され、合計される前に解析されます.関数式であれば、関数宣言の前に関数宣言も解析されます.
例:
alert(foo());
function foo(){
    return "Hello World";
}
ヒント:関数宣言は判断文では使わないほうがいいです.判定文には関数宣言が標準化されていないため、ブラウザ環境によっては異なる効果があります.
関数宣言はプログラムまたは関数の中にのみ表示されます.構文から言えば、それらはBlock(ブロック)({})に現れてはいけません.例えばif、while、またはfor文には現れません.ブロックにはステージステートメントしか含まれていないので、関数宣言のようなソース要素は含まれていません.一方、規則をよく見ると、Block(ブロック)に表現を出現させる唯一の可能性があることがわかってきます.しかし、規範が明確に規定されています.表現文はキーワードfunctionで始まることができません.これは、実際には、ステートメント文やブロックにも関数式が現れません(ブロックはSttement文で構成されていますので).
関数式の名前は、新規に定義された関数のスコープ内でのみ有効です.標準では、ラベルは外周のスコープ内では有効ではないと規定されています.
例:
var t=text(){
    return typeof text; //text        
};
typeof text;  //undefined
t();  //undefined
方法の内部に限定されているなら、文というのは外部からの引用ができないということです.なぜ匿名関数を使わないですか?なぜなら、表示関数は私達のデバッグに有利です.デバッグの過程で、デバッグスタックの中のオブジェクトがそれであることがよく分かります.匿名関数より便利です.
webkitのdisplayName属性
WebKitは「特殊」displayName属性(本質的には文字列)を導入しています.もし開発者が関数としてのこの属性割当値があれば、この属性の値は、試聴器または性能解析器に関数「名称」の位置に表示されます.
JavaScriptのModuleモード
基本的な使い方
//       
var module=function(eq){
    //    
    var VALUE="6",
        my={};
    //    
    my.Name="xiecanyong";
    my.money=function(data){
        text(data);//    
    }
    //    
    function text(data){
        console.log(data);
    }
    //      
    /*return {
        add:function(x,y){
            var count=x+y;
        }
    }*/
    return my;//               
}
var MO=new module(); //    
var NAME=MO.Name;  //    
var MONEY=MO.money(1);//      
また、方法でグローバル変数を宣言することができますので、内部環境が外部環境に汚染されないようにするために、次の2つの方法で実現できます.
1、グローバル変数の導入
2、匿名のクローズド
グローバル変数と匿名関数を導入
一番いい例はjqueryのソースコードです.簡単に調べてください.
(function($){
    //jquery  
}(jquery));
Moduleモードの高級用法
広く開拓する
私たちは通常、クローズドを使って関連コードを同じ書類の下に書くのですが、プロジェクトが比較的大きいと、多くの人が協力して共同で完成する必要があります.どのように一つのファイルを分離し、多くの人が協力しますか?
var blogModule = (function (my) {
my.AddPhoto = function () {
    //        
};
return my;
} (blogModule));
上のこのコードの動作原理は、BlogModuleグローバル変数を作成し、呼び出しごとにBlogModuleの方法をblogModuleグローバル変数に追加します.このようにして、すべてのファイルのロードが完了するまで、グローバル変数にロードされたメソッドと変数があります.
しかし、このコードは文法的には正しいですが、動作が正しくないとエラーが発生します.この中の理由は、初めて実行した時にBlogMuduleが定義されていますが、初期化されていない変数なので、追加方法に異常が発生します.
したがって、私たちはこのように処理すべきです.判断を加えると、対象は初期化されていません.これで問題を解決できます.
var blogModule = (function (my) {
my.AddPhoto = function () {
    //        
};
return my;
} (blogModule||{}));
すべての呼び出しがこの形式を採用しているということは、どのファイルも最後のblogModuleグローバル変数を先に読み込むということです.このような過程は松結合拡張といいます.
緊密結合展開
松の結合の拡張がある以上は、緊密な結合の広がりがあります.名前の通りに結合を拡張することは、ファイルのロード順序を乱すことはできません.しかし、松の結合の拡大よりも使いにくいですが、方法の重さを実現することができます.
var blogModule = (function (my) {
    my.oldAddPhotoMethod = my.AddPhoto;
    //           oldAddPhotoMethod,         AddPhoto               
    my.AddPhoto = function () {
        //     ,     oldAddPhotoMethod      
    };  
    return my;
} (blogModule));
緊密結合展開は使用時に注意しなければならないのは、グローバル変数の中のvarを必ず加えてください.そうでないとエラーが発生します.この原因は後で説明します.この緊密結合の拡張に対する分析によって、使用者セグメントコードの前に、別のAddPhotooの方法が必要であることが分かります.ここでロード方法の時に前の方法と衝突したら、前の方法を別の変数に割り当てます.(ここでの荷重は強言語の荷重とは少し異なるかもしれません.)もう一つのポイントは、緊密結合された着信パラメータは空かどうかを判断する必要はありませんが、緊密結合に拡張されたファイルのロードにおいて、最初にロードされたファイルの着信パラメータもBlogModule{}
JavaScript継承実現
JavaScriptは他の言語と同じように関係を継承したいとは思いませんが、継承された対象(親類)を継承対象(子類)の原型に渡すことで、サブクラスが定義されていない場合は親の方法を呼び出すことができます.この原理は他の言語の継承の定義とほぼ同じですので、継承も可能です.
function MadDog() {
this.yelp = function() {
      var self = this;          
      setInterval(function() {
            self.wow();      
      }, 500);
  }
}
MadDog.prototype = new Dog();         

//for test
var dog = new Dog();
dog.yelp();
var madDog = new MadDog();
madDog.yelp();
ファイルにまたがってプライベートオブジェクトを共有する
上記の展開の紹介を通して、JSのチーム開発に対して一定の理解ができました.しかし、チーム間でいくつかの方法を共有するなら、どうやって実現すればいいですか?コードの中の変数を共有することができます.
var blogModule = (function (my) {
var _private = my._private = my._private || {},
    //       ,    
    _unseal = my._unseal = my._unseal || function () {
        my._private = _private;
        my._seal = _seal;
        my._unseal = _unseal;
    };
    //       ,      
    _seal = my._seal = my._seal || function () {
        delete my._private;
        delete my._seal;
        delete my._unseal;
        
    },
    
    return my;
} (blogModule || {}));
サブモジュール
上で検討したのは単一モジュールの応用ですが、実際のプロジェクトでは、工事が大きすぎるかもしれないので、もう一つのモジュールをベースに複数のサブモジュールを作る必要があります.
例:
blogModule.test=(function (){
    
}());
ちなみに、後の自動実行の括弧は取れます.これは正常な開発では珍しいので、ここでお話しします.
自己実行
一般的に私たちの自己実行はこのように定義されています.
var foo=function(){/*  */};
この区間のコードは正常に動作しますが、すべてのコードは自動的に実行できます.
function (){/*  */}()
このコードの実行はエラーが発生します.解析器は大域functionまたはfunction内部のFunctionキーワードを解析する際に、デフォルト解析は関数宣言となりますが、前の知識から関数宣言は必ず名前を付けなければならないことが分かります.そうすると、解析器は名前がないfunctionとして解析され、エラーが発生しました.
しかし、コードを下記のように書くと、正常に運行できますか?
function foo(){/*  */}()
答えは正常に動作できません.この部分のコードから見れば、実行された関数声明のように見えますが、関数宣言の後の括弧は関数表現が自己実行の意味ではなく、グループ操作子であり、グループ操作子は空であることが許されないため、このコードが間違っています.
function foo(){ /* code */ }( 1 );
上記のコードはエラーが発生しませんが、実行されません.
上記の問題を解決するために、私達はその外に括弧を入れるべきです.この原理は上に述べられました.つまり、パケット演算子は中の関数声明を関数式に解析します.関数式の後の括弧は自己実行です.
(function foo(){/*  */}())
以下では、例を通して、自己実行と即時呼び出しとは何かを理解します.
//           ,        ,  
    function foo() { foo(); }

//             ,        
//     arguments.callee       
    var foo = function () { arguments.callee(); };

//                ,   foo         
//     foo      ,      used-to-self-execute    
    var foo = function () { foo(); };

//                (     ),         ,         。
    (function () { /* code */ } ());

//               ,    Debug
//       ,            
    (function foo() { /* code */ } ());

//           (IIFE)      ,         
    (function () { arguments.callee(); } ());
    (function foo() { foo(); } ());

//   ,        5      ,              ,     undefined
//   ,  
    (function foo() { foo(); } ());
ここでは、argments.calee()などの方法がありますが、これらは何ですか?arugumentsオブジェクトは実行中の関数とその関数を呼び出すパラメータを表しています.call方法は実行中のオブジェクトに戻ります.他の方法パラメータと使い方は詳細に分かります.
jsの暗黙パラメータ(argments,calee,caler)の使い方
jsの中のcallerとcalee属性
最後にModuleモデルの例を貼り付けて共有します.
//                 
// return    ,                
//            counter,        function  

var counter = (function () {
var i = 0;

return {
    get: function () {
        return i;
    },
    set: function (val) {
        i = val;
    },
    increment: function () {
        return ++i;
    }
};
} ());

// counter            ,                 

counter.get(); // 0
counter.set(3);
counter.increment(); // 4
counter.increment(); // 5

counter.i; // undefined   i         
i; //     : i     (  i      )
はい、この文章の内容はここで終わります.好きな仲間に褒めてもらえば、前に進む力があります.