http://blog.wolksoftware.com/becoming-a-javascript-ninjajavascript
http://pengisgood.github.io/2016/01/16/becoming-a-javascript-ninja/css
I’m training really hard to become what some people call a 「JavaScript Ninja」. in this post I will share with you some important things that I have learned so far.html
Coding conventions are a set of guidelines for a specific programming language that recommend programming style, practices and methods for each aspect of a piece program written in this language. These conventions usually cover file organization, indentation, comments, declarations, statements, white space, naming conventions, programming practices, programming principles, programming rules of thumb, architectural best practices, etc. These are guidelines for software structural quality. Software programmers are highly recommended to follow these guidelines to help improve the readability of their source code and make software maintenance easier.java
There are tools that will help you to ensure that you and your team follow JavaScript code convections:react
Code convections tool | Description |
---|---|
JSLint | JSLint is a JavaScript program that looks for problems in JavaScript programs. It is a code quality tool. It was developed by Douglas Crockford. JSLint takes a JavaScript source and scans it. If it finds a problem, it returns a message describing the problem and an approximate location within the source. The problem is not necessarily a syntax error, although it often is. JSLint looks at some style conventions as well as structural problems. It does not prove that your program is correct. It just provides another set of eyes to help spot problems. You can download it from www.jslint.com. |
JSHint | JSHint is fork of JSLint that was created by Anton Kovalyov because he believes that a code quality tool should be community-driven and because he thinks that sometimes we should be able to decide if we want to follor or not one code convection. As a result of this JS Hint is much more configurable than JS Lint. You can download it from www.jshint.com. |
I’m sure you are tired of listen to people that tells you that you should document your code.I’m sure you are doing it but sometimes is not that easy to find value on doing it but If after creating the comments you end up with a documentation website, something like MSDN or the Java Documentation it seems to be more valuable, fortunately we also have tools that will generate the documentation for us:jquery
Documentation generation tool | Description |
---|---|
JsDoc Toolkit | Is an application, written in JavaScript, for automatically generating template-formatted, multi-page HTML (or XML, JSON, or any other text-based) documentation from commented JavaScript source code. You can download it from here. |
In computer science, separation of concerns (SoC) is a design principle for separating a computer program into distinct sections, such that each section addresses a separate concern. A concern is a set of information that affects the code of a computer program.git
The value of separation of concerns is simplifying development and maintenance of computer programs. When concerns are well separated, individual sections can be developed and updated independently. Of especial value is the ability to later improve or modify one section of code without having to know the details of other sections, and without having to make corresponding changes to those sections.github
In a JavaScript application your concerns are HTML, CSS, JavaScript configuration code and JavaScript logic code. To keep them separated you just have to stick to the following rules:web
a) Keep your HTML out of JavaScript: Embedding HTML strings inside your JavaScript is a bad practice.express
Embedding HTML strings inside your JavaScript is a bad practice.
var div = document.getElementById("myDiv"); div.innerHTML = "<h3>Error</h3><p>Invalid email adress.</p>";
The best way to avoid this problem is to load the HTML from the server via AJAX ore even better load HTML client-side templates from the server. There are tools like handlebars.js that will help you to generate HTML in the client-side without embedding HTML strings inside your JavaScript.
// rendering logic RenderJson = function(json, template, container) { var compiledTemplate = Handlebars.compile(template); var html = compiledTemplate(json); $(container).html(''); $(container).html(html); }; // remplate var template = "{{#each hero}}<tr><td>{{this.name}}" + "<td></tr>{{/each}}"; // model var json = { hero : [ { name : 'Batman' }, { name : 'Superman' }, { name : 'Spiderman' } ] } // Invoke rendering logic RenderJson(json, template, $('#heroes_tbody')); // DOM where we will insert HTML on rendering <table> <thead><tr><th>Hero</th></tr></thead> <tbody id="heroes_tbody"> <!-- rows added with JS --> </tbody> </table>
b) Keep your CSS out of JavaScript
Don’t change CSS rules from JavaScript, try to only work with CSS classes.
// bad $(this).css( "color", "red" ); // good $(this).addClass('redFont');
c) Keep your JavaScript out of CSS
Don’t use CSS expressions, if you don’t know what is a CSS expression (An IE8 and earlier feature) then you are in the right way.
d) Keep your CSS out of HTML
Don’t use style tags to apply styles, use always class.
e) Keep your configuration code out of your logic code
Try to encapsulate all the hard coded variables and constants in a configuration object..
var CONFIG = { MESSAGE : { SUCCESS :"Success!" }, DOM : { HEROE_LIST : "#heroes_tbody" } }; // bad RenderJson(json, template, $('#heroes_tbody')); // good RenderJson(json, template, $(CONFIG.DOM.HEROE_LIST));
If you do this finding the cause of issues will be much easier, imagine an incorrect background error, if you know that there is no JavaScript or HTML touching your CSS, then you automatically know that the issue must be in one of the CSS files, you just need to find the CSS class affected and you are done.
In computer programming, a global variable is a variable that is accessible in every scope. Global variables are a bad practices because it can lead to situations when one method is overriding and existing global variable and because code is harder to understand and mantein when we don’t know where the variables has been declared. The best JavaScript code is the one where no global variable shas been declared. There are a few techniques that you can use to keep things local:
To avoid global one of the first things that you have to ensure is that all your JavaScript code is wrapped by a function. The easiest way of doing this is by using an inmediate function and placing all of your script inside of the function.
(function(win) { "use strict"; // further avoid creating globals var doc = window.document; // declare your variables here // other code goes here }(window));
The most common approcach to avoid globals is to create one unique global for your entire application think for example the $ in Jquery. You can then use then a technique known as namespacing. Namespacing is simply a logical grouping of functions under a singleproperty of the global.
Sometimes each JavaScript file is sismply adding to a namespace, in this case, you should ensure that the namespace already exists.
var MyApp = { namespace: function(ns) { var parts = ns.split("."), object = this, i, len; for(i = 0, len = parts.lenght; i < len; i ++) { if(!object[parts[i]]) { object[parts[i]] = {}; } object = object[parts[i]]; } return object; } }; // declare a namespace MyApp.namespace("Helpers.Parsing"); // you can now start using the namespace MyApp.Helpers.Parsing.DateParser = function() { //do something };
Another technique used by developers to avoid globals is the encapsulation in modules. A module is a generic pirce of functionality that creates no new globals or namespaces. Instead all the code takes place within a single function that is responsible for executing a task or publishing an interface. The most common type of JavaScript modules is Asynchronous Module Definition (AMD).
//define define( "parsing", //module name [ "dependency1", "dependency2" ], // module dependencies function( dependency1, dependency2) { //factory function // Instead of creating a namespace AMD modules // are expected to return their public interface var Parsing = {}; Parsing.DateParser = function() { //do something }; return Parsing; } ); // load a AMD module with Require.js require(["parsing"], function(Parsing) { Parsing.DateParser(); // use module });
The special value null is often misunderstood and confused with undefined. This value should be used in just a few cases:
a) To initialize a variable that may later be assigned an object value
b) To compare against an initialized variable that may or may not have an object value
c) To pass into a function where an object is expected
d) To return from a function where an object is expected
There are cases in which null should not be used:
a) Do not use null to test whether an argument was supplied.
b) Do not test an uninitialized variable for the value null.
The special value undefined is frequently confused with null. Part of the confusion is that null == undefined is true. However, these two values have two very different uses. Variables that are not initialized have an initial value of undefined.
//bad var person; console.log(person == undefined); //true
The general recommendation is to avoid using undefined at all times.
I guess that you must be know wondering how should you do the following without using undefined or null?
//bad function doSomething(arg){ if (arg != null) { soSomethingElse(); } }
Comparing a variable against null doesn’t give you enough information about the value to determine whether is safe to proceed. Furtunately, JavaScript gives youi a few ways to determine the true value of a variable:
a) Primitive values: If your expecting a value to be a primitive type (sting, number, boolean) then the typeof operator is your best option.
// detect a number if(typeof count === "number") { //do something }
b) Reference values: The instanceof operator is the best way to detect objects of a particular reference type.
// detect a date if(value instanceof Date) { //do something }
**c) Functions: Using typeof is the best way to detect functions.
// detect a function if(MyApp.Helpers.Parsing.DateParser typeof === "function") { MyApp.Helpers.Parsing.DateParser(); }
d) Arrays: The best way to detect arrays is to use the isArray() function. The only problem is that isArray does not work in old versions of internet explorer. But you can sue the following code for cross browser support.
function isArray(value) { if (typeof Array.isArray === "function") { return Array.isArray(value); } else { return Object.prototype.toString.call(value) === "[object array]"; } }
e) Properties: The best way to detect a property is to use the in operator or the hasOwnProperty() function.
var hero = { name : 'superman '}; //chech property if (name in hero) { // do something } //chech NOT inherited property if (hero.hasOwnProperty('name')) { // do something }
Throwing custom errors in JavaScript can help you to decrease your debugging time. It is not easy to know when you should throw a custom error but in general errors should be thrown only in the deepest part of your application stack. Any code that handles application-especific logig should have error-handling capabilities. You can use the following code to create your custom errors:
function MyError(message){ this.message = message; } MyError.prototype = new Error(); //extending base error class
Is also a good idea to chek for specifict error types (Error, EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError) to have a more robust error handling:
try { // Do something } catch(ex) { if(ex instanceof TypeError) { // Handle error } else if (ex instanceof ReferenceError) { // Handle error } else { //Handle all others } }
There are things that you don’t own (objects that has not been written by you or your team)
a ) Native objects (e.g. Object, Array, etc.)
b ) DOM objects (e.g. document)
c ) Browser object model (e.g. window)
d ) Library objects (e.g. Jquery, $, _, Handlebars, etc.)
And thing that you should not try on objects that you don’t own:
a ) Don’t override methods
b ) Don’t add new methods
c ) Don’t remove existing methods
If you really need to extend or modify an object that you don’t own, you should create a class that inherits from it and modify your new object. You can use one of the JavaScript inheritance basic forms:
a) Object-based Inheritance: an object inherits from another without calling a constructor function.
var person = { name : "Bob", sayName : function() { alert(this.name); } } var myPerson = Object.create(person); myPerson.sayName(); // Will display "Bob"
a) Type-based inheritance: tipically requires two steps: prototypal inheritance and then constructor inheritance.
function Person(name) { this.name = name; } function Author(name) { Person.call(this,name); // constructor inheritance } Author.prototype = new Person(); // prototypal inheritance
As the complexity of JavaScript applications grows we must introduce the same design patterns and preactices that we have been using for years in our server-side and desktop applications code to ensure high quality solutions. So it is time to start writting tests (unit, performance, integration…) for your JavaScript code. The good news is that there are several tools that you can use to help you:
a) Jasmine
b) JsTestDrive
c) PhantonJS
d) QUnit
e) Selenium
f) Yeti
g) YUI Test
Continuous Integration is a software development practice where members of a team integrate their work frequently, usually each person integrates at least daily - leading to multiple integrations per day. Each integration is verified by an automated build (including test) to detect integration errors as quickly as possible. Many teams find that this approach leads to significantly reduced integration problems and allows a team to develop cohesive software more rapidly.
Continuous Integrations doesn’t get rid of bugs, but it does make them dramatically easier to find and remove. In this respect it’s rather like self-testing code. If you introduce a bug and detect it quickly it’s far easier to get rid of.
Continuous Integration has been used for a while together with TDD (Test Driven Development). But it was more traditionally linked to server-side code. In the previous point we said that it is time to test our JavasCript code. In this point I want to highlight that it is also time to continuous integrate it.
Build
In a professional development environment you will normaly find the following types of build:
a) Development Build: Run by developers as they are working, it should be as fast as possible to not interrupt productivity.
b) Integration Build: An automated build that run on a regular schedule. These are sometimes run for each commit, but on large projects, they tend to run on intervals for a few minutes.
c) Release Build: an on-deman build that is run prior to production push.
Continuous integration
There are serveral continuous integration servers but the most popular is Jenkings, the most popular build tool is apache ant. The process of building your JavaScript code includes several taks:
a) Test automation As discussed on point 8 you should use test automation tools for testing your JavaScript code.
b) Validation You should add code quality validation to your build process. You can use tools like JSLint or JSHint
c) Concatenation You should join all your JavaScript files in one single file.
d) Baking You can perform tasks like adding a code the license or version code as part of the build.
e) Minification You should integrate as part the build the minification by tools like uglify.js.
f) Compression You should gzip your JavaScript as part of your build.
g) Documentation You should integrate as part of your build the auto-generation id the dosumentation by tools like JS Doc Toolkit.
A real ninja never stop learning, so you better find a great master!
Where can you find one? The answer is of course the Internet. I recommend to read the blogs of some of the chome or mozilla developers about javascript as well as other js libraries like jquery.
我努力地訓練着想成爲你們所說的「JavaScript 忍者」。在這篇文章中我將會分享一些迄今爲止我學到的比較重要的東西。
代碼約定是針對一門特定編程語言的編程規範、實踐和方法等一系列指導方針的集合。這些約定一般包含文件組織,縮進,註釋,定義,聲明,空格,命名,編程實踐,編程原則,編程經驗法則,架構的最佳實踐等。這些是軟件結構質量的指導方針。爲了幫助提升代碼的可讀性和軟件的可維護性,強烈建議軟件開發工程師遵循這些指導方針。
有一些工具能夠幫助你確保你的團隊遵循 JavaScript 的代碼約定:
代碼約定工具 | 描述 |
---|---|
JSLint | JSLint 是一個用於查找 JavaScript 程序問題的 JavaScript 程序。它是由 Douglas Crockford 開發的一個代碼質量工具。JSLint 會掃描 JavaScript 源碼。若是發現問題,它會返回描述問題的信息和在源碼中的大概位置。該問題不必定是語法錯誤,儘管常常確實是。JSLint 也會作一些代碼風格和結構的檢查。它並不證實你的程序是正確的。它只是從另外一個角度幫助發現問題。能夠從這裏下載 JSLint。 |
JSHint | JSHint 是 Anton Kovalyov 從 JSLint 建立的一個分支,由於他相信代碼質量工具應該是社區驅動的而且有時候由咱們本身決定是否要遵循一些代碼約定。所以 JSHint 比 JSLint 更具備可配置性。能夠從這裏下載 JSHint。 |
我確信你會很不賴煩的聽到別人說你須要爲你的代碼編寫文檔。我確信你正在這樣作可是有時候不容易發現它的價值,可是若是你建立的註釋最終能夠造成相似MSDN 或者 Java 文檔這樣的文檔站點,彷佛有更多的價值。幸運的是,咱們也有幫助咱們生成文檔的工具:
文檔生成工具 | 描述 |
---|---|
JsDoc Toolkit | 它是用 JavaScript 編寫的一個應用程序,用於根據 JavaScript 源碼中的註釋自動生成經過模板格式化的多頁面的 HTML(或者 XML, JSON,或者其餘基於文本文件的)文檔。你能夠從這裏下載 JsDoc Toolkit。 |
在計算機科學中,關注點分離(SoC)將計算機程序分開到不一樣部分中的設計原則,像這樣每個部分表示一個單獨的關注點。一個關注點就是一些會影響到計算機程序代碼的信息。
分離關注點的價值在於簡化計算機程序的開發和維護。當關注點很好的分離以後,每個部分都能獨立開發和更新了。還有一個特別的價值就是它賦予了你在之後的改善或修改一個部分的代碼的時候不用關心其餘部分的細節,而且不用修改其餘部分的能力。
在 JavaScript 應用程序中,你的關注點就是 HTML,CSS,JavaScript 配置代碼和 JavaScript 邏輯代碼。爲了將它們保持分離,你只須要堅持下面幾個法則:
a) 從 JavaScript 代碼中移除 HTML:在 JavaScript 中嵌入 HTML 字符串是一種壞的實踐。
1 |
var div = document.getElementById("myDiv"); |
解決這個問題的最佳方式就是經過 AJAX 從服務端加載 HTML 或者甚至從服務端加載客戶端模板。有一些像 handlebars.js
的工具能夠幫助你在客戶端生成 HTML 的問題,並且不用將 HTML 字符串嵌入到 JavaScript 中。
1 |
// 渲染邏輯 |
b) 將 CSS 從 JavaScript 中移除
請勿經過 JavaScript 修改 CSS 的屬性,儘可能只經過 CSS 的類。
1 |
// bad |
c) 從 CSS 中移除 JavaScript
若是你不瞭解 CSS 表達式,不要使用 CSS 表達式(一個 IE8 早期的特性),以避免誤入歧途。
d) 從 HTML 中移除 CSS
老是使用class
,而不是經過style
標籤添加樣式。
e) 從邏輯代碼中移除配置代碼
儘可能把全部的硬編碼變量和常量放到一個配置對象中。
1 |
var CONFIG = { |
若是這樣作你會發現找到問題的根源會更加容易些,想象一個場景,背景顏色不對,若是你知道不會有 JavaScript 或者 HTML 涉及到你的 CSS,你天然而然就知道問題確定處在某一個 CSS 文件中,你只須要找到那個影響到樣式的 CSS Class
,而後就完成了。
在計算機編程中,全局變量指的是在全部做用域中都能訪問的變量。全局變量是一種很差的實踐,由於它會致使一些問題,好比一個已經存在的方法和全局變量的覆蓋,當咱們不知道變量在哪裏被定義的時候,代碼就變得很難理解和維護了。好的 JavaScript 代碼就是沒有定義全局變量的。有一些技術能夠幫助你讓全部的事情都保持在本地:
爲了不全局變量,第一件事情就是要確保全部的代碼都被包在函數中。最簡單的辦法就是把全部的代碼都直接放到一個函數中去:
1 |
(function(win) { |
最經常使用的避免全局變量的方式就是隻爲應用程序建立惟一的全局變量,像 Jquery中的 $
。而後你可使用一種技術叫作命名空間namespacing
。命名空間就是在同一全局做用域下對函數從邏輯上進行分組。
有時候每個 JavaScript 文件都會添加一個本身的命名空間,在這種狀況下,須要確保命名空間已經存在了。
1 |
var MyApp = { |
另外一項開發者用來避免全局變量的技術就是封裝到模塊 Module
中。一個模塊就是不須要建立新的全局變量或者命名空間的通用的功能。不要將全部的代碼都放一個負責執行任務或者發佈接口的函數中。最多見的 JavaScript 模塊類型就是異步模塊定義 Asynchronous Module Definition (AMD)
。
1 |
//定義 |
特殊值 null
常常被錯誤理解而且和 undefined
混淆。這個值應該只能出如今一下幾個場景:
a) 初始化一個可能後面會被賦值的對象
b) 和已經被初始化的但不肯定是否賦過值的變量比較
c) 做爲參數傳入一個期待參數爲對象的函數
d) 做爲一個期待返回對象的函數的返回值
有一些場景是不該該使用 null
的:
a) 測試是否有傳入參數
b) 測試一個未初始化的變量值是否爲 null
特殊值 undefined
常常和 null
混爲一談。部分混淆來自於 null == undefined
的值爲 true
。然而,這兩個值的用途卻不一樣。未被初始化的變量的默認值爲 undefined
。
1 |
//bad |
通常性的建議就是要避免老是使用 undefined
。
我猜測你必定好奇如何不使用 undefined
和 null
來作下面這件事情?
1 |
//bad |
比較一個變量和 null
不會給你足夠的信息判斷是否能夠安全的進行。幸運的是,JavaScript 提供了一些方法幫助你決定一個變量的真實的值:
a) 基本值:若是你期待一個值的類型是基本類型(string,number,boolean),那麼 typeof
操做符就是最佳選擇。
1 |
// detect a number |
b) 引用值:instanceof
操做符是檢測一個對象是否爲特定類型的最佳方式。
1 |
// detect a date |
c) 函數:typeof
操做符是檢測函數的最佳方式。
1 |
// detect a function |
d) 數組:最佳方式是使用 isArray()
函數。惟一的問題是舊版本的 IE 不支持 isArray
,可是你能夠用下面的代碼來支持多瀏覽器。
1 |
function isArray(value) { |
e) 屬性:hasOwnProperty()
函數是檢測屬性的最佳方式。 **
1 |
var hero = { name : 'superman '}; |
在 JavaScript 中拋自定義的錯誤能夠幫助你減小調試的時間。不是那麼容易得出什麼時候應該拋自定義的錯誤,可是常規錯誤通常只有在應用程序最深層才拋。任何處理特定應用邏輯的代碼應該有處理錯誤的能力。你能夠用下面的代碼建立自定義的錯誤:
1 |
function MyError(message){ |
檢查特定的錯誤類型也是個好主意(Error,EvalError,RangeError,ReferenceError,SyntaxError,TypeError,URIError)使得錯誤處理更加健壯:
1 |
try { |
有一些東西是不屬於你的(不是你本身或者團隊寫建立的):
a) Native 對象 (e.g. Object,Array,etc.)
b) DOM 對象 (e.g. document)
c) 瀏覽器對象 (e.g. window)
d) 庫對象 (e.g. Jquery,$,_,Handlebars,etc.)
有一些事情是你不能在不屬於你的對象上作的:
a) 不要複寫方法
b) 不要添加新方法
c) 不要刪除已經存在的方法
若是你確實須要擴展或者修改不屬於你的對象,你應該建立一個類並繼承它而後修改你的新類。你可使用 JavaScript 的一種繼承方式:
a) 基於對象的繼承: 經過調用構造函數繼承。
1 |
var person = { |
b) 基於類型的繼承: 通常須要兩步:先原型繼承而後構造函數繼承。
1 |
function Person(name) { |
隨着 JavaScript 應用複雜度的增加,咱們應該引入和服務端或者桌面端應用使用了多年的同樣的設計模式和實踐,以幫助咱們保證高質量的解決方案。因此是時候開始爲你的 JavaScript 代碼寫測試了(單元測試,性能測試,集成測試……)。好消息是有一些工具能夠幫助咱們作這些:
a) Jasmine
b) JsTestDriver
c) PhantomJS
d) QUnit
e) Selenium
f) Yeti
g) YUI Test
持續集成是一項軟件開發實踐,多個團隊常常集成他們的工做,一般每一個人每人至少一次——以致於天天會有屢次集成。每一次集成都會經過自動化構建(包括測試)儘早檢查發現錯誤。許多團隊發現這種方式能夠顯著地減小集成問題而且幫助團隊快速地開發出內聚的軟件。
持續集成不能避免 bug
,可是它會幫助你更容易發現而且幹掉 bug
。在這方面它更像是自測試代碼。若是你引入了一個 bug
,快速地發現它,更加容易避免它。
持續集成已經和 TDD(測試驅動開發)
一塊兒用了一段時間了。可是它過去老是傳統的和服務端代碼聯繫在一塊兒。在前面的建議中咱們說到是時候爲咱們的 JavaScript 代碼寫測試了。在這個建議中我想強調也是時候去持續集成它了。
構建
在專業的開發環境中你一般會發現如下幾種構建:
a) 開發構建: 由開發者在工做的時候運行,爲了避免中斷生產率它應該儘量快。
b) 集成構建: 會按期運行的自動化構建。可能會在每次提交以後運行一遍,可是通常在大型項目中他們傾向於每一個幾分鐘運行一遍。
c) 發佈構建: 在部署到產品環境以前按需運行的構建。
持續集成
有不少作持續集成的服務器可是 Jenkins
是其中最流行的一個,最流行的構建工具是 Apache Ant
(譯者注:如今像 Maven,Gradle 遠比 Ant 流行)。構建你的 JavaScript 代碼包括如下幾個任務:
a) Test automation 根據第8點中的討論,你應該使用自動化工具幫助你測試你的 JavaScript 代碼。
b) Validation 你應該在你的構建過程當中添加代碼質量的驗證。可使用像 JSLint 或者 JSHint 這樣的工具。
c) Concatenation 你應該把全部的 JavaScript 文件鏈接成爲一個單獨的文件。
d) Baking 你應該讓添加 License 或者 Version 的任務做構建的一部分。
e) Minification 你應該使用像 uglify.js
的工具讓 Minify 成爲集成的一部分。
f) Compression 你應該讓 Gzip JavaScript 代碼成爲夠的一部分。
g) Documentation 你應該使用像 JS Doc Toolkit 這樣的工具讓自動生成文檔做爲集成的一部分。
一個真正的忍者歷來沒有中止過學習,因此你最好找一位大師!
從哪裏能夠找到一位呢?答案是互聯網。我推薦閱讀一些 Chrome 或者 Mozilla 的開發者關於 JavaScript 的博客和一些其餘像 jquery
的 JS 庫。