JavaScriptは世界的に最も優れたプログラミング言語であり、Web開発、モバイルアプリ開発(PhoneGap、Appcelerator)、サーバーサイド開発(Node.jsやWakanda)などに利用できます。JavaScriptはまた、多くの初心者がプログラミングの世界に足を踏み入れる最初の言語でもあります。ブラウザで簡単なアラートボックスを表示するだけでなく、nodebotやnodruinoを介してロボットを制御することもできます。構造が明確で高性能なJavaScriptコードを書ける開発者は、現在、採用市場で最も求められる存在となっています。
この記事では、いくつかのJavaScriptのテクニック、秘訣、ベストプラクティスを紹介します。ごく一部を除き、ブラウザのJavaScriptエンジンでも、サーバーサイドのJavaScriptインタプリタでも、すべてに適用できます。
この記事のサンプルコードは、Google Chrome 30(最新版)(V8 3.20.17.15)でテスト済みです。
1、変数に初めて値を代入する際は必ず使用するvarキーワード
変数を宣言せずに直接代入すると、デフォルトで新しいグローバル変数になります。グローバル変数の使用はできるだけ避けるべきです。
2、使用する===の代わりに==
==と!=演算子は必要に応じてデータ型を自動変換します。しかし===と!==はそうではなく、値とデータ型の両方を比較します。そのため、より==と!=速いです。
[10] === 10 // is false [10] == 10 // is true '10' == 10 // is true '10' === 10 // is false [] == 0 // is true [] === 0 // is false '' == false // is true but true == "a" is false '' === false // is false
3、undefined、null、0、false、NaN、空文字列の論理結果はすべてfalse
4、行末にはセミコロンを使用する
実際にはセミコロンを使うのが最善です。書き忘れても大丈夫な場合が多く、ほとんどの場合JavaScriptインタプリタが自動的に追加します。なぜセミコロンを使うべきかについては、記事を参照してください。JavaScriptにおけるセミコロンの真実。
5、オブジェクトコンストラクタを使用する
function Person(firstName, lastName){
this.firstName = firstName;
this.lastName = lastName;
}
var Saad = new Person("Saad", "Mousliki");
6、注意して使用するtypeof、instanceofとcontructor
typeof:JavaScriptの単項演算子で、変数のプリミティブ型を文字列として返します。注意:typeof nullも返しますobject、ほとんどのオブジェクト型(配列Array、日付Dateなど)も返しますobjectcontructor:内部プロトタイププロパティ。コードで書き換えることができますinstanceof:JavaScriptの演算子で、プロトタイプチェーン内のコンストラクタを検索し、見つかれば返しますtrue、見つからなければ返しますfalse
var arr = ["a", "b", "c"]; typeof arr; // 返回 "object" arr instanceof Array // true arr.constructor(); //[]
7、自己呼び出し関数を使用する
関数は作成後すぐに自動実行されます。通常、自己呼び出し匿名関数(Self-Invoked Anonymous Function)または即時実行関数式(Immediately Invoked Function Expression)と呼ばれます。形式は次のとおりです:
(function(){
// 置于此处的代码将自动执行
})();
(function(a,b){
var result = a+b;
return result;
})(10,20)
8、配列からランダムにメンバーを取得する
var items = [12, 548 , 'a' , 2 , 5478 , 'foo' , 8852, , 'Doe' , 2145 , 119]; var randomItem = items[Math.floor(Math.random() * items.length)];
9、指定範囲内の乱数を取得する
この機能は、テスト用のダミーデータを生成するときに特に便利です。たとえば、指定範囲内の給与額などです。
var x = Math.floor(Math.random() * (max - min + 1)) + min;
10、0から指定値までの数値配列を生成する
var numbersArray = [] , max = 100; for( var i=1; numbersArray.push(i++) < max;); // numbers = [1,2,3 ... 100]
11、ランダムな英数字文字列を生成する
function generateRandomAlphaNum(len) {
var rdmString = "";
for( ; rdmString.length < len; rdmString += Math.random().toString(36).substr(2));
return rdmString.substr(0, len);
}
12、数値配列の順序をシャッフルする
var numbers = [5, 458 , 120 , -215 , 228 , 400 , 122205, -85411];
numbers = numbers.sort(function(){ return Math.random() - 0.5});
/* numbers 数组将类似于 [120, 5, 228, -215, 400, 458, -85411, 122205] */
ここではJavaScript組み込みの配列ソート関数を使用していますが、より良い方法は専用のコード(Fisher-Yatesアルゴリズムなど)で実装することです。StackOverFlowのこの議論を参照してください。。
13、文字列の空白を取り除く
Java、C#、PHPなどの言語には専用の文字列空白除去関数がありますが、JavaScriptにはありません。次のコードでStringオブジェクトにtrim関数を追加できます:
String.prototype.trim = function(){return this.replace(/^\s+|\s+$/g, "");};
新しいJavaScriptエンジンにはすでにtrim()のネイティブ実装があります。
14、配列同士を連結する
var array1 = [12 , "foo" , {name "Joe"} , -2458];
var array2 = ["Doe" , 555 , 100];
Array.prototype.push.apply(array1, array2);
/* array1 值为 [12 , "foo" , {name "Joe"} , -2458 , "Doe" , 555 , 100] */
15、オブジェクトを配列に変換する
var argArray = Array.prototype.slice.call(arguments);
16、数値かどうかを検証する
function isNumber(n){
return !isNaN(parseFloat(n)) && isFinite(n);
}
17、配列かどうかを検証する
function isArray(obj){
return Object.prototype.toString.call(obj) === '[object Array]' ;
}
しかし、もしtoString()メソッドが書き換えられている場合は、うまくいきません。次の方法も使用できます:
Array.isArray(obj); // its a new Array method
ブラウザでframeを使用していない場合は、次も使えます:instanceof、ただしコンテキストが複雑すぎると、エラーが発生する可能性もあります。
var myFrame = document.createElement('iframe');
document.body.appendChild(myFrame);
var myArray = window.frames[window.frames.length-1].Array;
var arr = new myArray(a,b,10); // [a,b,10]
// myArray 的构造器已经丢失,instanceof 的结果将不正常
// 构造器是不能跨 frame 共享的
arr instanceof Array; // false
18、配列の最大値と最小値を取得する
var numbers = [5, 458 , 120 , -215 , 228 , 400 , 122205, -85411]; var maxInNumbers = Math.max.apply(Math, numbers); var minInNumbers = Math.min.apply(Math, numbers);
19、配列を空にする
var myArray = [12 , 222 , 1000 ]; myArray.length = 0; // myArray will be equal to [].
20、配列から直接削除しないdelete或remove要素
配列要素に直接deleteを使用しても、実際には削除されず、要素がundefinedに設定されるだけです。配列要素の削除にはsplice。
を使用すべきです。注意:
var items = [12, 548 ,'a' , 2 , 5478 , 'foo' , 8852, , 'Doe' ,2154 , 119 ]; items.length; // return 11 delete items[3]; // return true items.length; // return 11 /* items 结果为 [12, 548, "a", undefined × 1, 5478, "foo", 8852, undefined × 1, "Doe", 2154, 119] */
ではなく:
var items = [12, 548 ,'a' , 2 , 5478 , 'foo' , 8852, , 'Doe' ,2154 , 119 ]; items.length; // return 11 items.splice(3,1) ; items.length; // return 10 /* items 结果为 [12, 548, "a", 5478, "foo", 8852, undefined × 1, "Doe", 2154, 119]
オブジェクトのプロパティを削除する際はdelete。
21、使用するlength属性で配列を切り詰める
前述の例ではlength属性で配列を空にしましたが、同じように配列を切り詰めることもできます:
var myArray = [12 , 222 , 1000 , 124 , 98 , 10 ]; myArray.length = 4; // myArray will be equal to [12 , 222 , 1000 , 124].
それと同時に、もしlength属性を大きくすると、配列の長さが増加し、undefinedが新しい要素として埋められます。lengthは書き込み可能なプロパティです。
myArray.length = 10; // the new array length is 10 myArray[myArray.length - 1] ; // undefined
22、条件で論理AND/ORを使用する
var foo = 10; foo == 10 && doSomething(); // is the same thing as if (foo == 10) doSomething(); foo == 5 || doSomething(); // is the same thing as if (foo != 5) doSomething();
論理ORはデフォルト値の設定にも使用できます。たとえば関数パラメータのデフォルト値などです。
function doSomething(arg1){
arg1 = arg1 || 10; // arg1 will have 10 as a default value if it’s not already set
}
23、~を可能にするmap()関数メソッドでデータをループ処理する
var squares = [1,2,3,4].map(function (val) {
return val * val;
});
// squares will be equal to [1, 4, 9, 16]
24、指定した小数桁数を保持する
var num =2.443242342; num = num.toFixed(4); // num will be equal to 2.4432
注意:toFixec()は文字列を返します。数値ではありません。
25、浮動小数点計算の問題
0.1 + 0.2 === 0.3 // is false 9007199254740992 + 1 // is equal to 9007199254740992 9007199254740992 + 2 // is equal to 9007199254740994
なぜでしょうか?0.1 + 0.2 は 0.30000000000000004 になるからです。JavaScriptの数値はすべてIEEE 754標準に従って構築されており、内部では64ビット浮動小数点数として表現されています。詳細はJavaScriptにおける数値のエンコード方法.
を使用することでtoFixed()とtoPrecision()この問題を解決できます。
26、for-inループでオブジェクトのプロパティを調べる
次のような使い方で、反復処理の際にオブジェクトのプロトタイププロパティに入るのを防ぐことができます。
for (var name in object) {
if (object.hasOwnProperty(name)) {
// do something with name
}
}
27、カンマ演算子
var a = 0; var b = ( a++, 99 ); console.log(a); // a will be equal to 1 console.log(b); // b is equal to 99
28、計算や検索に使う変数を一時的に保存する
jQueryセレクターでは、DOM要素全体を一時的に格納することができます。
var navright = document.querySelector('#right');
var navleft = document.querySelector('#left');
var navup = document.querySelector('#up');
var navdown = document.querySelector('#down');
29、渡される引数を事前にチェックするisFinite()のパラメータ
isFinite(0/0) ; // false
isFinite("foo"); // false
isFinite("10"); // true
isFinite(10); // true
isFinite(undefined); // false
isFinite(); // false
isFinite(null); // true,这点当特别注意
30、配列で負数をインデックスとして使用するのを避ける
var numbersArray = [1,2,3,4,5];
var from = numbersArray.indexOf("foo") ; // from is equal to -1
numbersArray.splice(from,2); // will return [5]
渡す際に注意spliceのインデックス引数を負数にしないでください。負数の場合、配列の末尾から要素が削除されます。
31、JSONを使用してシリアライズとデシリアライズを行う
var person = {name :'Saad', age : 26, department : {ID : 15, name : "R&D"} };
var stringFromPerson = JSON.stringify(person);
/* stringFromPerson 结果为 "{"name":"Saad","age":26,"department":{"ID":15,"name":"R&D"}}" */
var personFromString = JSON.parse(stringFromPerson);
/* personFromString 的值与 person 对象相同 */
32、使用しないeval()または関数コンストラクタ
eval()と関数コンストラクタ(Functionconsturctor)のオーバーヘッドは大きいです。呼び出すたびに、JavaScriptエンジンはソースコードを実行可能なコードに変換する必要があります。
var func1 = new Function(functionCode); var func2 = eval(functionCode);
33、使用を避けるwith()
使用with()変数をグローバルスコープに追加できるため、他に同じ名前の変数があると、混乱しやすく、値も上書きされます。
34、配列にfor-inを使用しない
回避:
var sum = 0;
for (var i in arrayNumbers) {
sum += arrayNumbers[i];
}
代わりに:
var sum = 0;
for (var i = 0, len = arrayNumbers.length; i < len; i++) {
sum += arrayNumbers[i];
}
もう一つの利点は、iとlen2つの変数はforループの最初の宣言にあり、両方は一度だけ初期化されるため、次の書き方よりも速い:
for (var i = 0; i < arrayNumbers.length; i++)
35、~に渡すsetInterval()とsetTimeout()ときは、文字列ではなく関数を使用する
もし渡すものがsetTimeout()とsetInterval()文字列の場合、彼らは次のような方法で変換されますeval方法で変換されるため、確実に遅くなります。したがって、使用しないでください:
setInterval('doSomethingPeriodically()', 1000);
setTimeout('doSomethingAfterFiveSeconds()', 5000);
代わりに次を使用:
setInterval(doSomethingPeriodically, 1000); setTimeout(doSomethingAfterFiveSeconds, 5000);
36、使用するswitch/caseの代わりに多数のif/else
判定に2つ以上の分岐がある場合は使用するswitch/caseより速く、よりエレガントで、コードの整理にも役立ちます。もちろん、10以上の分岐がある場合は、使用しないでくださいswitch/caseください。
37、~の中にswitch/caseで数値の範囲を使用する
実は、switch/caseの中のcase条件は、次のように書くこともできます:
function getCategory(age) {
var category = "";
switch (true) {
case isNaN(age):
category = "not an age";
break;
case (age >= 50):
category = "Old";
break;
case (age <= 20):
category = "Baby";
break;
default:
category = "Young";
break;
};
return category;
}
getCategory(5); // 将返回 "Baby"
38、オブジェクトをオブジェクトのプロトタイプとして使用する
次のようにすると、指定したオブジェクトをパラメータとして、それをプロトタイプとする新しいオブジェクトを作成できます:
function clone(object) {
function OneShotConstructor(){};
OneShotConstructor.prototype = object;
return new OneShotConstructor();
}
clone(Array).prototype ; // []
39、HTMLフィールド変換関数
function escapeHTML(text) {
var replacements= {"<": "<", ">": ">","&": "&", "\"": """};
return text.replace(/[<>&"]/g, function(character) {
return replacements[character];
});
}
40、ループ内でtry-catch-finallyを使用しない
try-catch-finallyのcatch部分は実行時に例外を変数に割り当て、この変数は実行時スコープ内の新しい変数として構築されます。
絶対に避ける:
var object = ['foo', 'bar'], i;
for (i = 0, len = object.length; i <len; i++) {
try {
// do something that throws an exception
}
catch (e) {
// handle exception
}
}
そうではなく、次のようにすべき:
var object = ['foo', 'bar'], i;
try {
for (i = 0, len = object.length; i <len; i++) {
// do something that throws an exception
}
}
catch (e) {
// handle exception
}
41、XMLHttpRequestsを使用する際はタイムアウトの設定に注意する
XMLHttpRequestsの実行中に、長時間応答がない場合(ネットワーク問題など)は、接続を中止する必要があります。これには次を使用できます:setTimeout()この処理を実行します:
var xhr = new XMLHttpRequest ();
xhr.onreadystatechange = function () {
if (this.readyState == 4) {
clearTimeout(timeout);
// do something with response data
}
}
var timeout = setTimeout( function () {
xhr.abort(); // call error callback
}, 60*1000 /* timeout after a minute */ );
xhr.open('GET', url, true);
xhr.send();
同時に、複数のXMLHttpRequestsリクエストを同時に発行しないように注意してください。
42、WebSocketのタイムアウトを処理する
通常、WebSocket接続が作成された後、30秒以内にアクティビティがない場合、サーバー側は接続に対してタイムアウト処理を行います。ファイアウォールも、一定周期内にアクティビティのない接続をタイムアウト処理することができます。
このような事態を防ぐために、一定時間ごとにサーバーへ空のメッセージを送信できます。この要件を実現するには、次の2つの関数を使用できます。1つは接続をアクティブな状態に保つためのもので、もう1つはその状態を終了するためのものです。
var timerID = 0;
function keepAlive() {
var timeout = 15000;
if (webSocket.readyState == webSocket.OPEN) {
webSocket.send('');
}
timerId = setTimeout(keepAlive, timeout);
}
function cancelKeepAlive() {
if (timerId) {
cancelTimeout(timerId);
}
}
keepAlive()関数はWebSocket接続の ... に置くことができますonOpen()メソッドの最後に、cancelKeepAlive()... に置くonClose()メソッドの末尾に。
43、時間に関する注意:プリミティブ演算子は関数呼び出しより速い。VanillaJSを使用する
例えば、一般的に次のようにしないでください:
var min = Math.min(a,b); A.push(v);
代わりに次のようにできます:
var min = a < b ? a : b; A[A.length] = v;
44、開発時はコード構造に注意し、公開前にJavaScriptコードをチェックして圧縮する
コードを書くときにコード整形ツールを使用することを忘れないでください。JSLint(構文チェックツール)を使用し、リリース前にコードを圧縮します(例:JSMinを使用)。注:現在、コード圧縮には一般的にUglifyJS(https://github.com/mishoo/UglifyJS2)が推奨されています。
45、JavaScriptは非常に奥深い。ここにいくつか良い学習リソースがある
- Code Academyリソース:http://www.codecademy.com/tracks/javascript
- Marjin Haverbekexによって書かれたEloquent JavaScript:http://eloquentjavascript.net/
- John Resigによって書かれたAdvanced JavaScript:http://ejohn.org/apps/learn/
出典:http://www.codeceo.com/article/javascript-45-tips.html