JavaScriptプラグインの開発は入門からシリーズに精通しています.元のJavaScriptプラグインの開発です.

12438 ワード

なぜjavascriptプラグインの開発をしますか?
 
    これは必然です.時間と空間が違うので、開発者の協力、コードの再利用が必要です.具体的には多く話しません.
 
    js開発白は普通どうやってプログラムを開発しますか?入行したばかりのことを覚えています.
    
var a = 1;
var b = 2;

function add(aaa, bbb) {
    var result= aaa + bbb;
    alert("result == " + result);
}

add(a,b);
     add関数は簡単で、二つの数字が入ってきた和を計算して、そしてalert結果を計算します.需要が来てから、どんどん引き算、掛け算、割り算を加えました.私も対応してレデュース、multiplly、divideの方法を増加しました.
 
    だから私のコードは以下のようになりました.
    
var a = 1;
var b = 2;

//   
function add(aaa, bbb) {
    var result= aaa + bbb;
    alert("result == " + result);
}

//   
function reduce(aaa, bbb) {
    var result= aaa - bbb;
    alert("result == " + result);
}

//   
function multiply(aaa, bbb) {
    var result= aaa * bbb;
    alert("result == " + result);
}

//   
function divide(aaa, bbb) {
    var result = aaa / bbb;
    alert("result == " + result);
}

//    、 、 、 
add(a, b);
reduce(a, b);
multiply(a, b);
divide(a, b);
 
    突然ある日、お兄さんはこれらの関数を私達のプロジェクトでよく使います.コールしてもらえますか?これは簡単です.そこで私は加減乗除の関数を単独で1つのmathUtil.jsファイルに置きました.このファイルの内容は以下の通りです.
    
//     
function add(aaa, bbb) {  
    var result= aaa + bbb;  
    alert("result == " + result);  
}  
  
//     
function reduce(aaa, bbb) {  
    var result= aaa - bbb;  
    alert("result == " + result);  
}  
  
//     
function multiply(aaa, bbb) {  
    var result= aaa * bbb;  
    alert("result == " + result);  
}  
  
//     
function divide(aaa, bbb) {  
    var result = aaa / bbb;  
    alert("result == " + result);  
}
 
    この時は実は一番原始的なプラグインの開発に入りました.私が書いたこのコードは時間をまたいで、異なる開発者と協力して使用されるため、このコードも重用され、重複労働が減少しました.
 
   次はプラグインを完璧にする過程です.
 
    最適化:方法は直接大域作用領域に露出し、衝突と命名しやすく、作用領域による検索性能の消耗が大きい.オブジェクト指向プログラミング、純粋なプログラミングの関数の羅列がありません.ソリューション:オブジェクトパッケージを使用します.
    
    JavaScriptの対象向けのデザイン使用については、これも難点ですので、座ってよく話してください.
 
    javascriptオブジェクトの生成方法は2つあります.
    
//      
var person1 = {
	name: "peter",
	age: 18,
	sayHello: function() {
		alert("hello! I am " + this.name);
	}
};

//   Object     
var person2 = new Object();
person2.name = "william";
person2.age = 19;
person2.sayHello = function() {
	alert("hello! I am " + this.name);
};
 
    以上はオブジェクトを作成できますが、欠点があります.複数のオブジェクトを作成するには、上記のコードを繰り返し書く必要があります.この問題を解決するために私達は使うことができます.
 
    工場モード:
    
//     
function createPerson(name, age) {
	var o = new Object();
	o.name = name;
	o.age = age;
	o.sayHello = function() {
		alert("hello! I am " + this.name);
	};
        return o;
}

var person1 = createPerson("peter", 18);
var person2 = createPerson("william", 19);
    
    工場モデルは普通の開発ニーズを満たすことができますが、これもちょっと問題があります.ネーミングは直接ではなく、実現の面でも簡略化できる.どうしますか?コンストラクタモードを使う:
    
//       
var Person = function(name, age) {
	this.name = name;
	this.age = age;
	this.sayHello = function() {
		alert("hello! I am " + this.name);
	}
};

var person1 = new Person("peter", 18);
var person2 = new Person("william", 19);
 
    工場モードから構造モードに跨り、スパンがちょっと大きいです.ここで説明します.
 
    工場モードを比較すると、構造関数モードは以下のように違っています.
 
    A.オブジェクトを明示的に作成していません.
    B.属性・方法を直接にthisオブジェクトに与えた
    C.returnがありません
 
    これらはnewオペレータのコンストラクターモードを使用する時に以下のような過程を経験するからです.
 
    A.オブジェクトを作成する
    B.コンストラクタのスコープを新しいオブジェクトに割り当てますので、thisはこの新しいオブジェクトを指します.
    C.コンストラクタのコードを実行します.例としては、新しいオブジェクトの属性と方法を付与します.
    D.新しいオブジェクトに戻る
 
    コンストラクタモードは多くのステップを省略していますが、よく分かりません.しかし、使うのは簡単でストレートです.たとえば、私はpersonクラスを作りたいです.new Personは(javaの文法と全く同じです.32個の賞賛をもらいました.)しかし、工場モードを使用する場合は、createPersonを呼び出す必要があります.時には工場のモードの関数は他の人が書いたので、createHumanと書きました.これは強制死に追いやられませんか?
 
    もう一つの重要な利点は、構造関数モードを用いて生成されたオブジェクトがこの関数の例であることである.どう言いますか?工場モードを使用すると,得られたpersonはObjectの例にすぎない.コンストラクターモードで得られたpersonはより具体的なPersonの例です.もちろんObjectの例でもあります.
 
    この利点は、instance ofオペレータを使用して、実例的な判断をする時に、私達に正確な判断を与えることができます.もし工場のモデルから出た製品であれば、測定結果はみんなObjectの例です.
 
    ここでは、コンストラクターモードの詳細を考慮しない場合があります.このプラグインの書き方はもう私達のプロジェクトに応用できます.プロジェクトの中で他の人に会ったことがありますか?だから私達のmathUtil.jsファイルは次のように書くことができます.
    
function MathUtil() {
	//       
	this.add = function(aaa, bbb) {    
	    var result= aaa + bbb;    
	    alert("result == " + result);    
	};  
	    
	//       
	this.reduce = function(aaa, bbb) {    
	    var result= aaa - bbb;    
	    alert("result == " + result);    
	};   
	    
	//       
	this.multiply = function(aaa, bbb) {    
	    var result= aaa * bbb;    
	    alert("result == " + result);    
	};    
	    
	//       
	this.divide = function(aaa, bbb) {    
	    var result = aaa / bbb;    
	    alert("result == " + result);    
	};
}
    
    使用方法:
    
//   mathUtil.js       :

var mathUtil1 = new MathUtil();
mathUtil1.add(1, 2);
 
    これにより、プラグインはオブジェクト指向の抽象的なプロセスを実現し、プラグインに必要な各種の変数をカプセル化しました.
 
    以上のコンストラクターモデルはまだ問題があります.技術に磨きをかける先端開発に対しても、これは我慢できません.問題は、mathUtil関数の体重のaddなどの方法はすべて対象である(関数も特殊な対象であり、一つの関数を定義するのは実用化対象に相当する).newがMathUtilの例を挙げると、インスタンス中の方法は同じですが、繰り返しました.実はこれは必要ないです.どうすればいいですか
 
    最も簡単で乱暴な方法は関連する関数を抽出することです.
    
function MathUtil() {

	//    
	var version = "1.0";

	//       
	this.add = add;  
	    
	//       
	this.reduce = reduce;   
	    
	//       
	this.multiply = multiply;    
	    
	//       
	this.divide = divide;
}

//       
var add = function(aaa, bbb) {    
    var result= aaa + bbb;    
    alert("result == " + result);    
};  
    
//       
var reduce = function(aaa, bbb) {    
    var result= aaa - bbb;    
    alert("result == " + result);    
};   
    
//       
var multiply = function(aaa, bbb) {    
    var result= aaa * bbb;    
    alert("result == " + result);    
};    
    
//       
var divide = function(aaa, bbb) {    
    var result = aaa / bbb;    
    alert("result == " + result);    
};
 
    以上の改造後、newのMathUtilの例が複数ある場合、add関数は一例しかなく、MathUtilと同じレベルのadd関数を指します.他の関数は同じです.
 
    しかし、実際の操作から言えば、機能を少し消耗してプラグインの関数を抽出しないほうがいいです.これによって露見した変数が急激に増加し、制御が難しいからです.
    
    このような問題を解決する案がありますか?すなわち、複数の例の共通の方法、オブジェクトは1つを指し、多重化方法.答えはプロトタイプです.
    
var MathUtil = function() {};

MathUtil.prototype = {

	//        MathUtil,      constructor     MathUtil,     Object     
    constructor: MathUtil,

	//    
	version: "1.0",

	//   
	add: function(aaa, bbb) {    
	    var result= aaa + bbb;    
	    alert("result == " + result);    
	},

	//       
	reduce: function(aaa, bbb) {    
	    var result= aaa - bbb;    
	    alert("result == " + result);    
	},  
    
	//       
	multiply: function(aaa, bbb) {    
	    var result= aaa * bbb;    
	    alert("result == " + result);    
	},  
    
	//       
	divide: function(aaa, bbb) {    
	    var result = aaa / bbb;    
	    alert("result == " + result);    
	}
};
 
    以上のプロトタイプは完璧に見えますが、二つの比較的目立つ問題があります.
 
    A.初期化変数入口なし
    B.属性がArayタイプの場合、属性の改竄が発生します.
 
    MathUtilという関数については、初期化されていない変数の入口という意味は、newがインスタンスを出す時に、直接にversionを導入し、デフォルト値をカバーしたいということです.しかし、以上のデザインは明らかにできません.
 
    また、属性の改竄については、この問題を説明するために、開発者の名前を保存するために、mathUtilの対象にプログラマー変数を追加します.
    
var MathUtil = function() {};  
  
MathUtil.prototype = {  

    //        
    
    //    
    programmer: [] 
};  
    
//      MathUtil,  programmer           
var m1 = new MathUtil();
m1.programmer.push("william");


//      MathUtil,   programmer          ,m2 programmer            "william"
var m2 = new MathUtil();
m2.programmer;
    
    これはm 1,m 2が同一の原型オブジェクトを共有しているため、Arayが引用タイプであるため、m 1のprogrammerはm 2のprogrammerと同一のインスタンスとなっている.ですから、私たちは対象の属性を人為的に分類します.もし関数であれば、プロトタイプの属性を指している例に統一します.もし非引用タイプやアーチェリータイプの属性だけなら、私たちはコンストラクションに入れます.また、構造関数を改造しながらパラメータを受け取ります.
    
var MathUtil = function(version, programmer) {
	this.name = name;
	this.programmer = programmer;
};

MathUtil.prototye = {

	//        MathUtil,      constructor     MathUtil,     Object     
	constructor: MathUtil,

	//   
	add: function(aaa, bbb) {    
	    var result= aaa + bbb;    
	    alert("result == " + result);    
	},

	//       
	reduce: function(aaa, bbb) {    
	    var result= aaa - bbb;    
	    alert("result == " + result);    
	},  
    
	//       
	multiply: function(aaa, bbb) {    
	    var result= aaa * bbb;    
	    alert("result == " + result);    
	},  
    
	//       
	divide: function(aaa, bbb) {    
	    var result = aaa / bbb;    
	    alert("result == " + result);    
	}
};
    テストコードを呼び出す:
    
//   mathUtil.js       :
var m1 = new MathUtil("william",["william"]);
m1.programmer.push("william2");

var m2 = new MathUtil("peter",["peter"]);
m1.programmer.push("peter2");
   
    この時m 1,m 2それぞれのプログラマーが対応するのは違う配列です.また、パラメータを初期化する能力も同時に持つ.
 
    以上の書き方は完璧です.二つの部分だけを分けて書くのはちょっと何ですか?強迫症の患者にとっては、動態原型法も使えます.
    
var MathUtil = function(version, programmer) {
	this.name = name;
	this.programmer = programmer;

	//           ,      。
	if(typeof this.add != "function") {

		//   MathUtil.prototye
		var proto = MathUtil.prototye;

		//   
		proto.add = function(aaa, bbb) {    
		    var result = aaa + bbb;    
		    alert("result == " + result);    
		};

		//   
		proto.reduce = function(aaa, bbb) {    
		    var result = aaa - bbb;    
		    alert("result == " + result);    
		};

		//   
		proto.multiply = function(aaa, bbb) {    
		    var result= aaa * bbb;    
		    alert("result == " + result);    
		};

		//   
		proto.divide = function(aaa, bbb) {    
		    var result= aaa / bbb;    
		    alert("result == " + result);    
		};
	}
};
 
    以上prototype新規方法のコードはnewオペレータを使用して実行すると、判定に入るのは一回だけで、その後MathUtil.prototypeに該当する関数方法を追加しました.
 
    プロトタイプを和コンストラクションレベルに置くか、それともコンストラクタの中に置くかは、間違いなく個人やチームの好みによるものですが、統一した方がいいです.
 
    最後にもう一度強調します.先ほど会った二つのピット:
 
    1.MathUtilのprototypeに関数を追加する場合、MathUtil.prototype={…};そこで、MathUtil.prototypeが指しているオブジェクトを再配置しました.この時、constructはObjectを指しています.手動でMathUtilに戻る必要があります.一番の保険のやり方はMathUtil.prototype.add=function(){…}です.このように追加すると、この方法は、MathUtil.prototypeが指すインスタンスを置換していないので、予期せぬ問題を生じない.
 
    2.MathUtilの属性が配列である場合、絶対にプロタイプの中に定義してはいけません.属性値が問題をカバーします.