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 库。