-高級Javascriptプログラミング学習ノート----Javascriptプログラミングとアーキテクチャ設計に最も注意すべき基本点

13635 ワード

最小グローバル変数
JavaScriptは関数によってスコープを管理します.関数の内部にある生命の変数はこの関数の内部だけで、他の場所では使えません.大域変数とは、関数の外や非宣言で直接に簡単に使用される変数のことです.すべてのJavascipt環境にはグローバルオブジェクトがあります.どの関数以外でもthisを使ってアクセスできます.あなたが作成したすべての変数がこのグローバルオブジェクトの属性になります.ブラウザでは、便利のために、この全体のオブジェクトに付属のプロパティがあります.windowはこの全体のオブジェクト自体を指します.
myglobal = "hello"; //      
console.log(myglobal); // "hello"
console.log(window.myglobal); // "hello"
console.log(window["myglobal"]); // "hello"
console.log(this.myglobal); // "hello"
グローバル変数問題
グローバル変数はなるべく少なくし、var宣言を使用しなければなりません.
書き方を勧めない:
function sum(x, y) {

   //      :        

   result = x + y;

   return result;

}
//

function foo() {

   var a = b = 0;

   // ...

}
おすすめの書き方:
function foo() {

   var a, b;

   // ... a = b = 0; //        

}
Varのメリット
1.varによって作成されたグローバル変数は削除されません.
2.varなしで作成された暗黙的なグローバル変数は削除されます.
コードの例:
 
//         

var global_var = 1;

global_novar = 2; //     

(function () {

   global_fromfunc = 3; //     

}());



//     

delete global_var; // false

delete global_novar; // true

delete global_fromfunc; // true



//      

typeof global_var; // "number"

typeof global_novar; // "undefined"

typeof global_fromfunc; // "undefined"
 
グローバルオブジェクトにアクセス
ブラウズでは、グローバルオブジェクトは、コードのどこにでもwindow属性を介してアクセスできます.しかし、他の環境では、この便利な属性は他のものと呼ばれてもよく、プログラムでは利用できません.ハードコードのwindowタグなしでグローバルオブジェクトにアクセスする必要がある場合、任意の階層の関数領域で次のように操作できます.
var global = (function () {

   return this;

}());
この方法は、関数内で関数として呼び出され(new操作ではない)、thisは常にグローバルオブジェクトを指すので、グローバルオブジェクトをいつでも得ることができる.
シングルVarモード
関数の上に単Var文を使うのは、比較的に有用な形式であり、その利点は:
1.機能を探すために必要なローカル変数を提供します.
2.変数が定義される前に論理エラーを使用することを防止します.
3.宣言のグローバル変数を覚えてくれるので、グローバル変数が少なくなりました.
4.コードが少ない
function func() {

   var a = 1,

       b = 2,

       sum = a + b,

       myobject = {},

       i,

       j;

   // function body...

}
複数の変数をvar文で宣言し、分割しやすいようにしてもいいです.このような初期化変数は同時に値を初期化するのが良い.このようにして、論理エラーを防止し、コードの可読性を高めることができる.
前解析:var散布の問題
Javascriptでは、関数内の任意の位置で複数のvar文を声明できます.そして、彼らは関数の上部声明のように機能します.このような行為はhoistingといいます.変数を使って、すぐに関数で再宣言すると、論理エラーが発生します.Javascriptについては、あなたの変数が同じスコープにいる限り、彼は声明として扱われます.彼がvar声明の前に使用している場合でも.
//   

myname = "global"; //     

function func() {

    alert(myname); // "undefined"

    var myname = "local";

    alert(myname); // "local"

}

func();
varは事前解析で、実際にここに来た時だけ、varの後の定数をスタックに入れます.しかし、varはまた解析を制定し、前方に宣言されている変数を後方に置き換えるときに、上のundefiendがあります.
forサイクル
forサイクルに対しては、特に配列性能損失の問題に注意してください.
//      

for (var i = 0; i < myarray.length; i++) {

   //   myarray[i]    

}
毎回循環するmyarray.lengthは配列に一回遍歴します.このような性能損失は大きいです.
for (var i = 0, max = myarray.length; i < max; i++) {

   //   myarray[i]    

}
このように書くのが一番いいです.lengthを取得したのは一回だけです.また、このような書き方はシングルバーモードをよく表しています.
for-i nサイクルfor-inサイクルは、非配列オブジェクトのエルゴード上で使用されるべきであり、for-inを使用してループすることも「エニュメレーション」と呼ばれる.
技術的には、for-in巡回配列(JavaScriptの配列も対象ですので)が使えますが、これはおすすめできません.配列オブジェクトがカスタマイズされている機能が強化されていると、論理エラーが発生する可能性があります.なお、for-innでは、属性リストの順序(シーケンス)は保証されません.したがって、最も良い配列は正常なforサイクルを使用し、オブジェクトはfor-iループを使用します.
重要なhasOwnProperty()方法があります.オブジェクト属性を遍歴すると、プロトタイプチェーンから降りてきた属性をフィルタすることができます.
次のコードを考える:
//   
var man = {
hands: 2,
legs: 2,
heads: 1
};

//
//

if (typeof Object.prototype.clone === "undefined") {
Object.prototype.clone = function () {};
}
 
この例では、対象の字面量を使って定義されたmanというオブジェクトがあります.マン定義が完了した後のあるところに、オブジェクトの原型に、clone(という)という有用な方法が追加されました.このプロトタイプチェーンはリアルタイムであり、これはすべてのオブジェクトが自動的に新しい方法にアクセスできることを意味する.エニュメレーションマンの時にclone()の方法が現れることを避けるためには、hasOwnProperty()法を適用してプロトタイプの属性をフィルタリングする必要があります.フィルタリングをしないと、clone()関数が表示されます.ほとんどの場合、これは望ましくないです.
// 1.
//
for-in
for (var i in man) {
if (man.hasOwnProperty(i)) { //
console.log(i, ":", man[i]);
}
}
/*
hands : 2
legs : 2
heads : 1
*/
// 2.
//
:
//
for-in loop without checking hasOwnProperty()
for (var i in man) {
console.log(i, ":", man[i]);
}
/*

hands : 2
legs : 2
heads : 1
clone: function()
*/
 
もう一つの使用形態は、Object.prototype上のキャンセル方法である.イメージ:
for (var i in man) {
if (Object.prototype.hasOwnProperty.call(man, i)) { //
console.log(i, ":", man[i]);
}
}
 
その利点は、manオブジェクトがハスOwnPropertyを再定義する場合、ネーミング競合を回避することにある.長い属性の検索オブジェクトを回避するすべての方法で、ローカル変数「キャッシュ」を使用できます.
var i, hasOwn = Object.prototype.hasOwnProperty;
for (i in man) {
if (hasOwn.call(man, i)) { //
console.log(i, ":", man[i]);
}
}
 
厳密には、hasOwnProperty()を使用しないのは間違いではない.ミッションやコードに対する自信度によって、少しずつサイクルを上げていくことができます.しかし、現在のオブジェクトの内容(およびそのプロトタイプチェーン)が確定していない場合は、hasOwnProperty()を追加してもっと安全です.
フォーマットの変化(JSLintには通りません)は、かっこを抜き、if文を同じ行に置きます.その長所は循環文を読むと完全な考えのようになることです.
//   :    JSLint  
var i, hasOwn = Object.prototype.hasOwnProperty;
for (i in man) if (hasOwn.call(man, i)) { //
console.log(i, ":", man[i]);
}
 
エヴァは悪魔、
この方法は任意の文字列を受け取り、JavaScriptコードとして処理します.
//     

var property = "name";

alert(eval("obj." + property));



//    

var property = "name";

alert(obj[property]);
eval()を使用すると、実行されているコード(例えば、ネットワークから)が改竄されている可能性があります.これはよくある反面教師で、Ajax要求を処理して得られたJSONに対応する時.これらの場合、JavaScript内蔵方法を用いてJSON対応を解析し、安全と効果を確保することが望ましい.ブラウザがJSON.parse()をサポートしていない場合、JSON.orgからのライブラリを使用することができます.
同様に重要なのは、set Interval()、setTimeout()とFunction()の構造関数伝達文字列を記憶することであり、ほとんどの場合、eval()を使うのと似ているので避けるべきである.舞台裏では、JavaScriptはまだ評価と実行が必要です.
//     
setTimeout("myFunc()", 1000);
setTimeout("myFunc(1, 2, 3)", 1000);

//
setTimeout(myFunc, 1000);
setTimeout(function () {
myFunc(1, 2, 3);
}, 1000);
 
 
新しいFunction()構造を使うとエヴァ()に似ていますので、注意して接近してください.これは強力な構造かもしれませんが、しばしば誤用されます.絶対にeval()を使用しなければならないならば、new Function()を使って代用することも考えられます.新しいFunction()でコード評価を行うことは、ローカル関数のスコープで実行されるため、コードの中で評価された任意のvarで定義された変数は、自動的にグローバル変数に変わりません.別の方法は、自動グローバル変数がインパッケージeval()であることを阻止するためのインスタント関数に呼び出される.
以下の例を考えると、ここではhasOwnProperty()だけがグローバル変数として名前空間を汚染している.
console.log(typeof un);    // "undefined"
console.log(typeof deux); // "undefined"
console.log(typeof trois); // "undefined"

var jsstring = "var un = 1; console.log(un);";
eval(jsstring); // logs "1"

jsstring = "var deux = 2; console.log(deux);";
new Function(jsstring)(); // logs "2"

jsstring = "var trois = 3; console.log(trois);";
(function () {
eval(jsstring);
}()); // logs "3"

console.log(typeof un); // number
console.log(typeof deux); // "undefined"
console.log(typeof trois); // "undefined"
 
もう一つのeval()とFunctionの構造が違っているのはeval()が作用ドメインチェーンを妨害し、Function()がもっと安定していることです.どこでFunctionを実行しても、グローバルスコープしか見られません.そのため、ローカル変数の汚染をよく避けることができます.以下の例では、eval()は、その外部作用領域における変数にアクセスして修正することができ、これはFunctionではできない(Functionとnew Functionを使用するのは同じであることに留意される).
(function () {
var local = 1;
eval("local = 3; console.log(local)"); // logs "3"
console.log(local); // logs "3"
}());

(function () {
var local = 1;
Function("console.log(typeof local);")(); // logs undefined
}());