『メンテナンスできるjavascriptを書く』のノートを読みます.
36683 ワード
第一章基本的なフォーマットインデント層:おすすめtab:4; 改行:演算子の後で改行し、2行目に2つのインデントを追加します. 空き行を追加する:方法の間;方法の局所変数と最初のステートメントの間に.複数行または単一行のコメントの前に.方法内の論理セグメントを空の行に挿入すると、読み取り可能性が向上する(例えば、for、if). 定数:大文字でアンダースコアを付けた方式(var MAXUCOUNT); 表示の構築配列とオブジェクトを推奨しない(new方式を採用する); 文字列:二重引用符の使用を推奨します. 「\」を使って文字列を接続しないで、「+」を使うことをおすすめします. 第二章コメント注釈:前の行が空いていて、次の行が正しい;プログラムコードが比較的明瞭な場合は、コメントの追加は推奨されません.間違っていると思われるコードは勝手に修正しないように注釈してもいいです. ブロック文間のスペースは、以下のような for inを使って配列を循環しないでください.indexは文字列形式であり、数字形式ではなく、問題が発生しやすいからです.オブジェクトを循環させるために使用できます. 第四章変数、関数、演算子厳格モード:必要なところだけを追加して、全体的に使用しないようにしてください. 等しい:「==」と「!==」を使うことを推奨します. eval、Functionを適用しないようにし、setTimeoutを与えないようにし、set Intervalを文字列に入力しないようにする. 第五章UIの松結合css表現expressionの使用を避ける; jsでスタイルを変更する場合は、直接使うのではなく、クラス名を追加または削除する方式を採用する.style.co lor.style.cssText. HTMLではjavascriptを使用しない;例えばHTMLに埋め込まれたオンロック JavaScriptからHTMLを抜き出す. 解決方法は3つあります.1、サーバーからロードします. 2、簡易クライアントテンプレートを使用する. %s function sprintf(text){
var i=1、args=argments;
return text.replace(/%s/g,function()
return(i<args.length)?args[i+]:“”;
}
)
//usage
var reult=sprintf(templateText、「/item/4」、「Fourth item」);3、複合クライアントテンプレート;例えば、Handlebars グローバル変数の使用を避けるため、問題がある:命名衝突;コードの脆弱性テスト困難 意外なグローバル変数:varを忘れました. 解決方法:JSLintまたはJSHintを使用する. シングルグローバル変数:YUIがYUIグローバル変数を定義しています.jQueryは二つのグローバル変数を定義しました. 名前空間:例えばYUI.イベントでのあらゆる方法はイベントに関連しています. モジュール:AMDモジュールとYUIモジュール; ゼログローバル変数:内部コードが外部コードと無関係であることが前提です. 事件処理の典型的な使い方 ルール1:隔離応用ロジック ルール2:イベントの対象者は配布しない;上記の問題はイベントが無制限に配布されていることです.匿名イベントハンドラ関数から別の関数に、もう一つの関数に移動します.最善の方法:イベントハンドラをイベントオブジェクトでイベントを処理し、必要なすべてのデータをアプリケーションロジックに渡す. イベントを処理する際には、イベントハンドラをイベントオブジェクトに接触する唯一の関数にした方が良い. 以下は悪い例です.nullとは同じではないことが多いです.数字、文字列、オブジェクトなどを含めて、隠しエラーをもたらすことがあります.期待の値がnullの場合だけ、nullと比較することができます. 基本タイプがtypeofを使用していることを検出し、引用タイプがinstance ofを使用しているほか、対象特有の方法や属性が存在するかどうかを判断して、例えばarray.sort()、正則のtestメソッドを使用している.共通の方法は、他のタイプが類似していることである. 属性を検出し、属性を判断する最も良い方法はin 配置データは何ですか?JavaScriptコードで変更される可能性があります.例えば、urlは、ユーザーに見せる文字列、重複する値、設定、変化の可能性がある値を設定します.以下は良くない例です.invalid value、hrefの値、selctedは配置データです. 抽出配置データ エラーメッセージに関数名が含まれていることと、関数が失敗した理由を紹介します. いつエラーを出しますか?コードの中でどの部分が特定の場合に最適で失敗につながるかを識別し、どの部分だけエラーを出すかがポイントです.私たちの目的はエラー防止ではなく、エラーが発生した時にもっと調整しやすいです. try catch文を使って、tryでエラーが発生したら、すぐにcatch文にジャンプして、エラーの対象に入ります.finallyモジュールを追加してもいいです.エラーが発生しても発生しなくても実行します. これらのオブジェクトは、元のオブジェクト(Object、Aray)、DOMオブジェクト(document)、ブラウザオブジェクトモデル(BOM)オブジェクト(window)がすでに存在しているので、彼らを修正しないでください.クラスの対象.彼らに対する原則としては、上書きしない方法、追加しない方法、削除しない方法、以下のような良くない例があります. User agent検出 特性検出、推奨使用特性検出 特性推定回避 ブラウザからの推測を避けるために、何らかの方法で存在していると判断できないブラウザ
もしいいと思いましたら、下のオススメをクリックしてください.読んでくれてありがとうございます.
// Good: Break after operator, following line indented two levels
callAFunction(document, element, window, "some string value", true, 123,
navigator);
// Bad: Following line indented only one level
callAFunction(document, element, window, "some string value", true, 123,
navigator);
// Bad: Break before operator
callAFunction(document, element, window, "some string value", true, 123
, navigator);
// good
if (wl && wl.length) {
for (i = 0, l = wl.length; i < l; ++i) {
p = wl[i];
type = Y.Lang.type(r[p]);
if (s.hasOwnProperty(p)) {
if (merge && type == 'object') {
Y.mix(r[p], s[p]);
} else if (ov || !(p in r)) {
r[p] = s[p];
}
}
}
}
var MAX_COUNT = 10;
var URL = "http://www.nczonline.net/";
if (count < MAX_COUNT) {
doSomething();
}
// Good
var name = "Nicholas";
// Bad: Single quotes
var name = 'Nicholas';
// Bad: Wrapping to second line
var longString = "Here's the story, of a man \
named Brady.";
/*
* ( )
* ( )
*/
第三章文と表現if (condition) {
doSomething();
}
//
function fn() {
"use strict";
//
}
//
(function() {
"use strict";
function fn1() {
}
function fn2() {
}
})();
// Bad
element.style.color = "red";
element.style.left = "10px";
element.style.top = "100px";
element.style.visibility = "visible";
element.style.cssText = "color: red; left: 10px; top: 100px; visibility: hidden";
//
.reveal {
color: red;
left: 10px;
top: 100px;
visibility: visible;
}
// Good - Native
element.className += " reveal";
// Good - HTML5
element.classList.add("reveal");
// Good - YUI
Y.one(element).addClass("reveal");
// Good - jQuery
$(element).addClass("reveal");
// Good - Dojo
dojo.addClass(element, "reveal");
// Bad
var div = document.getElemenetById("my-div");
div.innerHTML = "Erroe
";
function loadDialog(name, oncomplete) {
var xhr = new XMLHttpRequest();
xhr.open("get", "/js/dialog/" + name, true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
var div = document.getElementById("dlg-holder");
div.innerHTML = xhr.responseText;
oncomplete();
} else {
// handle error
}
};
xhr.send(null);
}
//
var i=1、args=argments;
return text.replace(/%s/g,function()
return(i<args.length)?args[i+]:“”;
}
)
//usage
var reult=sprintf(templateText、「/item/4」、「Fourth item」);
// script
<li><a href="{{url}}">{{text}}</a></li>
function addItem(url, text) {
var mylist = document.getElementById("mylist"),
script = document.getElementById("list-item"),
templateText = script.text,
template = Handlebars.compile(script.text),
div = document.createElement("div"),
result;
result = template({
text: text,
url: url
});
div.innerHTML = result;
list.appendChild(div.firstChild);
}
//
addItem("/item/4", "Fourth item");
第六章グローバル変数の使用を避ける// AMD
define("my-books", [ "dependency1", "dependency2" ],
function(dependency1, dependency2) {
var Books = {};
Books.MaintainableJavaScript = {
author: "Nicholas C. Zakas"
};
return Books;
});
(function(win) {
var doc = win.document;
})(window)
第七章事件処理//
function handleClick(event) {
var popup = document.getElementById("popup");
popup.style.left = event.clientX + "px";
popup.style.top = event.clientY + "px";
popup.className = "reveal";
}
// addListener() from Chapter 7
addListener(element, "click", handleClick);
// - separate application logic
var MyApplication = {
handleClick: function(event) {
this.showPopup(event);
},
showPopup: function(event) {
var popup = document.getElementById("popup");
popup.style.left = event.clientX + "px";
popup.style.top = event.clientY + "px";
popup.className = "reveal";
}
};
addListener(element, "click", function(event) {
MyApplication.handleClick(event);
});
// Good
var MyApplication = {
handleClick: function(event) {
this.showPopup(event.clientX, event.clientY);
},
showPopup: function(x, y) {
var popup = document.getElementById("popup");
popup.style.left = x + "px";
popup.style.top = y + "px";
popup.className = "reveal";
}
};
addListener(element, "click", function(event) {
MyApplication.handleClick(event); // this is okay
});
// Good
var MyApplication = {
handleClick: function(event) {
// assume DOM Level 2 events support
event.preventDefault();
event.stopPropagation();
// pass to application logic
this.showPopup(event.clientX, event.clientY);
},
showPopup: function(x, y) {
var popup = document.getElementById("popup");
popup.style.left = x + "px";
popup.style.top = y + "px";
popup.className = "reveal";
}
};
addListener(element, "click", function(event) {
MyApplication.handleClick(event); // this is okay
});
第八章「空の比較」を避ける.var Controller = {
process: function(items) {
if (items !== null) { // Bad
items.sort();
items.forEach(function(item) {
// do something
});
}
}
};
function isArray(value) {
return Object.prototype.toString.call(value) === "[object Array]";
}
// , 0, "", false, null undefined
if (object[propertyName]) {
// do something
}
// Bad: Compare against null
if (object[propertyName] != null) {
// do something
}
// Bad: Compare against undefined
if (object[propertyName] != undefined) {
/ do something
}
var object = {
count: 0,
related: null
};
// Good
if ("count" in object) {
// this executes
}
if ("related" in object) {
// this executes
}
// hasOwnProperty()
// Good for all non-DOM objects
if (object.hasOwnProperty("related")) {
//this executes
}
// Good when you're not sure
if ("hasOwnProperty" in object && object.hasOwnProperty("related")) {
//this executes
}
第九章配置データをコードから分離する// Configuration data embedded in code
function validate(value) {
if (!value) {
alert("Invalid value");
location.href = "/errors/invalid.php";
}
}
function toggleSelected(element) {
if (hasClass(element, "selected")) {
removeClass(element, "selected");
} else {
addClass(element, "selected");
}
}
// Configuration data externalized
var config = {
MSG_INVALID_VALUE: "Invalid value",
URL_INVALID: "/errors/invalid.php",
CSS_SELECTED: "selected"
};
function validate(value) {
if (!value) {
alert(config.MSG_INVALID_VALUE);
location.href = config.URL_INVALID;
}
}
function toggleSelected(element) {
if (hasClass(element, config.CSS_SELECTED)) {
removeClass(element, config.CSS_SELECTED);
} else {
addClass(element, config.CSS_SELECTED);
}
}
第十章カスタムエラーを打ち出すfunction getDivs(element) {
if (element && element.getElementsByTagName) {
return element.getElementsByTagName("div");
} else {
throw new Error("getDivs(): Argument must be a DOM element.");
}
}
// ,
function addClass(element, className) {
if (!element || typeof element.className != "string") {
throw new Error("addClass(): First argument must be a DOM element.");
}
if (typeof className != "string") {
throw new Error("addClass(): Second argument must be a string.");
}
element.className += " " + className;
}
// null
function addClass(element, className) {
if (!element || typeof element.className != "string") {
throw new Error("addClass(): First argument must be a DOM element.");
}
element.className += " " + className;
}
try {
somethingThatMightCauseAnError();
} catch (ex) {
handleError(ex);
} finally {
continueDoingOtherStuff();
}
第十一章はあなたの相手ではないから動かないでください.document.getElementById = function() {
return null; // talk about confusing
};
document._originalGetElementById = document.getElementById;
document.getElementById = function(id) {
if (id == "window") {
return window;
} else {
return document._originalGetElementById(id);
}
};
document.sayImAwesome = function() {
alert("You're awesome.");
};
Array.prototype.reverseSort = function() {
return this.sort().reverse();
};
YUI.doSomething = function() {
// code
};
document.getElementById = null;
より良い方法:三つのコードがあります.//
var person = {
name: "Nicholas",
sayName: function() {
alert(this.name);
}
};
var myPerson = Object.create(person);
myPerson.sayName(); // pops up "Nicholas"
//
function MyError(message) {
this.message = message;
}
MyError.prototype = new Error();
var error = new MyError("Something bad happened.");
console.log(error instanceof Error); // true
console.log(error instanceof MyError); // true
// ,
function DOMWrapper(element) {
this.element = element;
}
DOMWrapper.prototype.addClass = function(className) {
this.element.className += " " + className;
};
DOMWrapper.prototype.remove = function() {
this.element.parentNode.removeChild(this.element);
};
// Usage
var wrapper = new DOMWrapper(document.getElementById("my-div"));
// add a CSS class
wrapper.addClass("selected");
// remove the element
wrapper.remove();
第十二章ブラウザの嗅ぎ込み// Bad
if (navigator.userAgent.indexOf("MSIE") > -1) {
// it's Internet Explorer
} else {
// it's not
}
// good IE 9 , IE8
if (isInternetExplorer8OrEarlier) {
// handle IE8 and earlier
} else {
// handle all other browsers
}
// Bad
if (navigator.userAgent.indexOf("MSIE 7") > -1) {
// do something
}
// Good
if (document.getElementById) {
// do something
}
// Bad - uses feature inference
//
function getById (id) {
var element = null;
if (document.getElementsByTagName) { // DOM
element = document.getElementById(id);
} else if (window.ActiveXObject) { // IE
element = document.all[id];
} else { // Netscape <= 4
element = document.layers[id];
}
return element;
}
// Bad
if (document.all) { // IE
id = document.uniqueID;
} else {
id = Math.random();
}
var isIE = !!document.all;
var isIE = !!document.all && document.uniqueID;
後の章は別の部分です.例えば、ファイルリスト、自動化など、まとめにくいです.もしいいと思いましたら、下のオススメをクリックしてください.読んでくれてありがとうございます.