首頁  >  文章  >  web前端  >  非常詳細的前端JavaScript規範

非常詳細的前端JavaScript規範

黄舟
黄舟原創
2017-03-13 16:54:342720瀏覽

JavaScript規格

目錄

  1. #物件

  2. 陣列

  3. ##函數
  4. #屬性
  5. 變數

  6. #條件
  7. 表達式

    與等號

  8. #區塊

  9. 註解
  10. 空白

  11. 逗號

  12. 分號

  13. #類型轉換
  14. #命名約定

  15. #存取器

  16. #建構器

  17. 事件

  18. ##jQuery
  19. ES5 相容性

    #HTML、CSS、JavaScript分離
  • 使用jsHint前端工具

  • #類型
    • ##原始值<a href="http://www.php.cn/wiki/57.html" target="_blank"> : 相當於</a>傳值(

      JavaScript物件
    • 都提供了字面量),使用字面量
    • 建立物件

    • string

    • <a href="http://www.php.cn/wiki/62.html" target="_blank">number</a>

    • boolean

#null

  • <a href="http://www.php.cn/wiki/60.html" target="_blank"></a>#null

  • <a href="http://www.php.cn/wiki/58.html" target="_blank"></a>

    #undefined
  • var foo = 1,
        bar = foo;
    
    bar = 9;
    
    console.log(foo, bar); // => 1, 9

  • #複雜類型
: 相當於傳引用

  • ##object

  • #array

  • function

    <pre class="brush:js;toolbar:false;">var foo = [1, 2], bar = foo; bar[0] = 9; console.log(foo[0], bar[0]); // =&gt; 9, 9</pre>物件

  • #使用字面上值建立物件

    // bad
    var item = new Object();
    
    // good
    var item = {};

  • #不要使用保留字 reserved words 作為鍵
  • // bad
    var superman = {
      class: &#39;superhero&#39;,
      default: { clark: &#39;kent&#39; },
      private: true
    };
    
    // good
    var superman = {
      klass: &#39;superhero&#39;,
      defaults: { clark: &#39;kent&#39; },
      hidden: true
    };

  • #陣列
  • 使用字面上值建立陣列
// bad
var items = new Array();

// good
var items = [];

    如果你不知道陣列的長度,使用push
  • var someStack = [];
    
    // bad
    someStack[someStack.length] = &#39;abracadabra&#39;;
    
    // good
    someStack.push(&#39;abracadabra&#39;);

    #當你需要拷貝數組時使用slice. jsPerf

    var len = items.length,
        itemsCopy = [],
        i;
    
    // bad
    for (i = 0; i < len; i++) {
      itemsCopy[i] = items[i];
    }
    
    // good
    itemsCopy = items.slice();
  • #使用slice將類別數組的物件轉換成陣列.

    function trigger() {
      var args = [].slice.apply(arguments);
      ...
    }
  • 字串對字串使用單引號 

    ''
  • (因為大多時候我們的字串。特別html會出現
  • "

    )<pre class="brush:js;toolbar:false;">// bad var name = &quot;Bob Parr&quot;; // good var name = &amp;#39;Bob Parr&amp;#39;; // bad var fullName = &quot;Bob &quot; + this.lastName; // good var fullName = &amp;#39;Bob &amp;#39; + this.lastName;</pre>超過80(也有規定140的,專案具體可製定)個字元的字串應該使用字串連接換行

註: 如果過度使用,長字串連接可能會對效能有影響. jsPerf & Discussion

// bad
var errorMessage = &#39;This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.&#39;;

// bad
var errorMessage = &#39;This is a super long error that \
was thrown because of Batman. \
When you stop to think about \
how Batman had anything to do \
with this, you would get nowhere \
fast.&#39;;

// good
var errorMessage = &#39;This is a super long error that &#39; +
  &#39;was thrown because of Batman.&#39; +
  &#39;When you stop to think about &#39; +
  &#39;how Batman had anything to do &#39; +
  &#39;with this, you would get nowhere &#39; +
  &#39;fast.&#39;;

#函數表達式
    :
  • // 匿名函数表达式
    var anonymous = function() {
      return true;
    };
    
    // 有名函数表达式
    var named = function named() {
      return true;
    };
    
    // 立即调用函数表达式
    (function() {
      console.log(&#39;Welcome to the Internet. Please follow me.&#39;);
    })();

    #絕對不要在非函數區塊裡宣告一個函數,把那個函數賦給一個變數。瀏覽器允許你這麼做,但是它們解析不同。函數宣告不是一個語句。函數作用域內傳過來的 arguments

     物件.###
    // bad
    if (currentUser) {
      function test() {
        console.log(&#39;Nope.&#39;);
      }
    }
    
    // good
    if (currentUser) {
      var test = function test() {
        console.log(&#39;Yup.&#39;);
      };
    }
    #########屬性############當使用變數和特殊非法###變數名稱###時,存取屬性時可以使用中括號(###.### 優先).###
    // bad
    function nope(name, options, arguments) {
      // ...stuff...
    }
    
    // good
    function yup(name, options, args) {
      // ...stuff...
    }
    ########變數####### #####總是使用 ###var### 來宣告變量,如果不這麼做將導致產生全域變量,我們要避免污染全域###命名空間###。 ###
    // bad
    superPower = new SuperPower();
    
    // good
    var superPower = new SuperPower();
  • 使用一个 var 以及新行声明多个变量,缩进4个空格。

    // bad
    var items = getItems();
    var goSportsTeam = true;
    var dragonball = &#39;z&#39;;
    
    // good
    var items = getItems(),
        goSportsTeam = true,
        dragonball = &#39;z&#39;;
  • 最后再声明未赋值的变量,当你想引用之前已赋值变量的时候很有用。

    // bad
    var i, len, dragonball,
        items = getItems(),
        goSportsTeam = true;
    
    // bad
    var i, items = getItems(),
        dragonball,
        goSportsTeam = true,
        len;
    
    // good
    var items = getItems(),
        goSportsTeam = true,
        dragonball,
        length,
        i;
  • 在作用域顶部声明变量,避免变量声明和赋值引起的相关问题。

    // bad
    function() {
      test();
      console.log(&#39;doing stuff..&#39;);
    
      //..other stuff..
    
      var name = getName();
    
      if (name === &#39;test&#39;) {
        return false;
      }
    
      return name;
    }
    
    // good
    function() {
      var name = getName();
    
      test();
      console.log(&#39;doing stuff..&#39;);
    
      //..other stuff..
    
      if (name === &#39;test&#39;) {
        return false;
      }
    
      return name;
    }
    
    // bad
    function() {
      var name = getName();
    
      if (!arguments.length) {
        return false;
      }
    
      return true;
    }
    
    // good
    function() {
      if (!arguments.length) {
        return false;
      }
    
      var name = getName();
    
      return true;
    }

条件表达式和等号

  • 合理使用 === 和 !== 以及 == 和 !=.

  • 合理使用表达式逻辑操作运算.

  • 条件表达式的强制类型转换遵循以下规则:

    • 对象 被计算为 true

    • Undefined 被计算为 false

    • Null 被计算为 false

    • 布尔值 被计算为 布尔的值

    • 数字 如果是 +0, -0, or NaN 被计算为 false , 否则为 true

    • 字符串 如果是空字符串 '' 则被计算为 false, 否则为 true

      if ([0]) {
        // true
        // An array is an object, objects evaluate to true
      }
  • 使用快捷方式.

    // bad
    if (name !== &#39;&#39;) {
      // ...stuff...
    }
    
    // good
    if (name) {
      // ...stuff...
    }
    
    // bad
    if (collection.length > 0) {
      // ...stuff...
    }
    
    // good
    if (collection.length) {
      // ...stuff...
    }
  • 阅读 Truth Equality and JavaScript 了解更多

  • 给所有多行的块使用大括号

    // bad
    if (test)
      return false;
    
    // good
    if (test) return false;
    
    // good
    if (test) {
      return false;
    }
    
    // bad
    function() { return false; }
    
    // good
    function() {
      return false;
    }

注释

  • 使用 /** ... */ 进行多行注释,包括描述,指定类型以及参数值和返回值

    // bad
    // make() returns a new element
    // based on the passed in tag name
    //
    // @param <String> tag
    // @return <Element> element
    function make(tag) {
    
      // ...stuff...
    
      return element;
    }
    
    // good
    /**
     * make() returns a new element
     * based on the passed in tag name
     *
     * @param <String> tag
     * @return <Element> element
     */
    function make(tag) {
    
      // ...stuff...
    
      return element;
    }
  • 使用 // 进行单行注释,在评论对象的上面进行单行注释,注释前放一个空行.

    // bad
    var active = true;  // is current tab
    
    // good
    // is current tab
    var active = true;
    
    // bad
    function getType() {
      console.log(&#39;fetching type...&#39;);
      // set the default type to &#39;no type&#39;
      var type = this._type || &#39;no type&#39;;
    
      return type;
    }
    
    // good
    function getType() {
      console.log(&#39;fetching type...&#39;);
    
      // set the default type to &#39;no type&#39;
      var type = this._type || &#39;no type&#39;;
    
      return type;
    }
  • 如果你有一个问题需要重新来看一下或如果你建议一个需要被实现的解决方法的话需要在你的注释前面加上 FIXME 或 TODO 帮助其他人迅速理解

    function Calculator() {
    
      // FIXME: shouldn&#39;t use a global here
      total = 0;
    
      return this;
    }
    function Calculator() {
    
      // TODO: total should be configurable by an options param
      this.total = 0;
    
      return this;
    }
  • 满足规范的文档,在需要文档的时候,可以尝试jsdoc.

空白

  • 缩进、格式化能帮助团队更快得定位修复代码BUG.

  • 将tab设为4个空格

    // bad
    function() {
    ∙∙var name;
    }
    
    // bad
    function() {
    ∙var name;
    }
    
    // good
    function() {
    ∙∙∙∙var name;
    }
  • 大括号前放一个空格

    // bad
    function test(){
      console.log(&#39;test&#39;);
    }
    
    // good
    function test() {
      console.log(&#39;test&#39;);
    }
    
    // bad
    dog.set(&#39;attr&#39;,{
      age: &#39;1 year&#39;,
      breed: &#39;Bernese Mountain Dog&#39;
    });
    
    // good
    dog.set(&#39;attr&#39;, {
      age: &#39;1 year&#39;,
      breed: &#39;Bernese Mountain Dog&#39;
    });
  • 在做长方法链时使用缩进.

    // bad
    $(&#39;#items&#39;).find(&#39;.selected&#39;).highlight().end().find(&#39;.open&#39;).updateCount();
    
    // good
    $(&#39;#items&#39;)
      .find(&#39;.selected&#39;)
        .highlight()
        .end()
      .find(&#39;.open&#39;)
        .updateCount();
    
    // bad
    var leds = stage.selectAll(&#39;.led&#39;).data(data).enter().append(&#39;svg:svg&#39;).class(&#39;led&#39;, true)
        .attr(&#39;width&#39;,  (radius + margin) * 2).append(&#39;svg:g&#39;)
        .attr(&#39;transform&#39;, &#39;translate(&#39; + (radius + margin) + &#39;,&#39; + (radius + margin) + &#39;)&#39;)
        .call(tron.led);
    
    // good
    var leds = stage.selectAll(&#39;.led&#39;)
        .data(data)
      .enter().append(&#39;svg:svg&#39;)
        .class(&#39;led&#39;, true)
        .attr(&#39;width&#39;,  (radius + margin) * 2)
      .append(&#39;svg:g&#39;)
        .attr(&#39;transform&#39;, &#39;translate(&#39; + (radius + margin) + &#39;,&#39; + (radius + margin) + &#39;)&#39;)
        .call(tron.led);

逗号

  • 不要将逗号放前面

    // bad
    var once
      , upon
      , aTime;
    
    // good
    var once,
        upon,
        aTime;
    
    // bad
    var hero = {
        firstName: &#39;Bob&#39;
      , lastName: &#39;Parr&#39;
      , heroName: &#39;Mr. Incredible&#39;
      , superPower: &#39;strength&#39;
    };
    
    // good
    var hero = {
      firstName: &#39;Bob&#39;,
      lastName: &#39;Parr&#39;,
      heroName: &#39;Mr. Incredible&#39;,
      superPower: &#39;strength&#39;
    };
  • 不要加多余的逗号,这可能会在IE下引起错误,同时如果多一个逗号某些ES3的实现会计算多数组的长度。

    // bad
    var hero = {
      firstName: &#39;Kevin&#39;,
      lastName: &#39;Flynn&#39;,
    };
    
    var heroes = [
      &#39;Batman&#39;,
      &#39;Superman&#39;,
    ];
    
    // good
    var hero = {
      firstName: &#39;Kevin&#39;,
      lastName: &#39;Flynn&#39;
    };
    
    var heroes = [
      &#39;Batman&#39;,
      &#39;Superman&#39;
    ];

分号

  • 语句结束一定要加分号

    // bad
    (function() {
      var name = &#39;Skywalker&#39;
      return name
    })()
    
    // good
    (function() {
      var name = &#39;Skywalker&#39;;
      return name;
    })();
    
    // good
    ;(function() {
      var name = &#39;Skywalker&#39;;
      return name;
    })();

类型转换

  • 在语句的开始执行类型转换.

  • 字符串:

    //  => this.reviewScore = 9;
    
    // bad
    var totalScore = this.reviewScore + &#39;&#39;;
    
    // good
    var totalScore = &#39;&#39; + this.reviewScore;
    
    // bad
    var totalScore = &#39;&#39; + this.reviewScore + &#39; total score&#39;;
    
    // good
    var totalScore = this.reviewScore + &#39; total score&#39;;
  • 对数字使用 parseInt 并且总是带上类型转换的基数.,如parseInt(value, 10)

  • var inputValue = &#39;4&#39;;
    
    // bad
    var val = new Number(inputValue);
    
    // bad
    var val = +inputValue;
    
    // bad
    var val = inputValue >> 0;
    
    // bad
    var val = parseInt(inputValue);
    
    // good
    var val = Number(inputValue);
    
    // good
    var val = parseInt(inputValue, 10);
    
    // good
    /**
     * parseInt was the reason my code was slow.
     * Bitshifting the String to coerce it to a
     * Number made it a lot faster.
     */
    var val = inputValue >> 0;
  • 布尔值:

    var age = 0;
    
    // bad
    var hasAge = new Boolean(age);
    
    // good
    var hasAge = Boolean(age);
    
    // good
    var hasAge = !!age;

命名约定

  • 避免单个字符名,让你的变量名有描述意义。

    // bad
    function q() {
      // ...stuff...
    }
    
    // good
    function query() {
      // ..stuff..
    }
  • 当命名对象、函数和实例时使用驼峰命名规则

    // bad
    var OBJEcttsssss = {};
    var this_is_my_object = {};
    var this-is-my-object = {};
    function c() {};
    var u = new user({
      name: &#39;Bob Parr&#39;
    });
    
    // good
    var thisIsMyObject = {};
    function thisIsMyFunction() {};
    var user = new User({
      name: &#39;Bob Parr&#39;
    });
  • 当命名构造函数或类时使用驼峰式大写

    // bad
    function user(options) {
      this.name = options.name;
    }
    
    var bad = new user({
      name: &#39;nope&#39;
    });
    
    // good
    function User(options) {
      this.name = options.name;
    }
    
    var good = new User({
      name: &#39;yup&#39;
    });
  • 命名私有属性时前面加个下划线 _:

    // bad
    this.firstName = &#39;Panda&#39;;
    this.firstName_ = &#39;Panda&#39;;
    
    // good
    this._firstName = &#39;Panda&#39;;
  • 当保存对 this 的引用时使用 self(<a href="http://www.php.cn/wiki/1514.html" target="_blank">python</a> 风格),避免this issue.Angular建议使用vm(MVVM模式中view-model):

    // good
    function() {
      var self = this;
      return function() {
        console.log(self);
      };
    }

存取器

  • 属性的存取器函数不是必需的

  • 如果你确实有存取器函数的话使用getVal() 和 setVal(‘hello’),java getter、setter风格或者jQuery风格

  • 如果属性是布尔值,使用isVal() 或 hasVal()

    // bad
    if (!dragon.age()) {
      return false;
    }
    
    // good
    if (!dragon.hasAge()) {
      return false;
    }
  • 可以创建get()和set()函数,但是要保持一致

    function Jedi(options) {
      options || (options = {});
      var lightsaber = options.lightsaber || &#39;blue&#39;;
      this.set(&#39;lightsaber&#39;, lightsaber);
    }
    
    Jedi.prototype.set = function(key, val) {
      this[key] = val;
    };
    
    Jedi.prototype.get = function(key) {
      return this[key];
    };

构造器

  • 给对象原型分配方法,而不是用一个新的对象覆盖原型,覆盖原型会使继承出现问题。

    function Jedi() {
      console.log(&#39;new jedi&#39;);
    }
    
    // bad
    Jedi.prototype = {
      fight: function fight() {
        console.log(&#39;fighting&#39;);
      },
    
      block: function block() {
        console.log(&#39;blocking&#39;);
      }
    };
    
    // good
    Jedi.prototype.fight = function fight() {
      console.log(&#39;fighting&#39;);
    };
    
    Jedi.prototype.block = function block() {
      console.log(&#39;blocking&#39;);
    };
  • 方法可以返回 this 帮助方法可链。

    // bad
    Jedi.prototype.jump = function() {
      this.jumping = true;
      return true;
    };
    
    Jedi.prototype.setHeight = function(height) {
      this.height = height;
    };
    
    var luke = new Jedi();
    luke.jump(); // => true
    luke.setHeight(20) // => undefined
    
    // good
    Jedi.prototype.jump = function() {
      this.jumping = true;
      return this;
    };
    
    Jedi.prototype.setHeight = function(height) {
      this.height = height;
      return this;
    };
    
    var luke = new Jedi();
    
    luke.jump()
      .setHeight(20);
  • 可以写一个自定义的toString()方法,但是确保它工作正常并且不会有副作用。

    function Jedi(options) {
      options || (options = {});
      this.name = options.name || &#39;no name&#39;;
    }
    
    Jedi.prototype.getName = function getName() {
      return this.name;
    };
    
    Jedi.prototype.toString = function toString() {
      return &#39;Jedi - &#39; + this.getName();
    };

事件

  • 当给事件附加数据时,传入一个哈希而不是原始值,这可以让后面的贡献者加入更多数据到事件数据里而不用找出并更新那个事件的事件处理

    // bad
    $(this).trigger(&#39;listingUpdated&#39;, listing.id);
    
    ...
    
    $(this).on(&#39;listingUpdated&#39;, function(e, listingId) {
      // do something with listingId
    });

    更好:

    // good
    $(this).trigger(&#39;listingUpdated&#39;, { listingId : listing.id });
    
    ...
    
    $(this).on(&#39;listingUpdated&#39;, function(e, data) {
      // do something with data.listingId
    });

模块

  • 这个文件应该以驼峰命名,并在同名文件夹下,同时导出的时候名字一致

  • 对于公开API库可以考虑加入一个名为noConflict()的方法来设置导出的模块为之前的版本并返回它

  • 总是在模块顶部声明 'use strict';,引入[JSHint规范](http://www.php.cn/):

    // fancyInput/fancyInput.js
    
    (function(global) {
      &#39;use strict&#39;;
    
      var previousFancyInput = global.FancyInput;
    
      function FancyInput(options) {
        this.options = options || {};
      }
    
      FancyInput.noConflict = function noConflict() {
        global.FancyInput = previousFancyInput;
        return FancyInput;
      };
    
      global.FancyInput = FancyInput;
    })(this);

jQuery

  • 对于jQuery对象以$开头,以和原生DOM节点区分。

    // bad
    var menu = $(".menu");
    
    // good
    var $menu = $(".menu");
  • 缓存jQuery查询

    // bad
    function setSidebar() {
      $(&#39;.sidebar&#39;).hide();
    
      // ...stuff...
    
      $(&#39;.sidebar&#39;).css({
        &#39;background-color&#39;: &#39;pink&#39;
      });
    }
    
    // good
    function setSidebar() {
      var $sidebar = $(&#39;.sidebar&#39;);
      $sidebar.hide();
    
      // ...stuff...
    
      $sidebar.css({
        &#39;background-color&#39;: &#39;pink&#39;
      });
    }
  • 对DOM查询使用级联的 $('.sidebar ul') 或 $('.sidebar ul'),jsPerf

  • 对有作用域的jQuery对象查询使用 find:

    // bad
    $(&#39;.sidebar&#39;, &#39;ul&#39;).hide();
    
    // bad
    $(&#39;.sidebar&#39;).find(&#39;ul&#39;).hide();
    
    // good
    $(&#39;.sidebar ul&#39;).hide();
    
    // good
    $(&#39;.sidebar > ul&#39;).hide();
    
    // good (slower)
    $sidebar.find(&#39;ul&#39;);
    
    // good (faster)
    $($sidebar[0]).find(&#39;ul&#39;);
  • 每个页面只使用一次document的ready事件,这样便于调试与行为流跟踪。

    $(function(){
       //do your page init.  
    });
  • 事件利用jQuery.on从页面分离到JavaScript文件。

    // bad
    <a id="myLink" href="#" onclick="myEventHandler();"></a>
    
    // good
    <a id="myLink" href="#"></a>
    
    $("#myLink").on("click", myEventHandler);
  • 对于Ajax使用promise方式。

     // bad
        $.ajax({
            ...
            success : function(){
            },
            error : function(){
            } 
        })
    
        // good
        $.ajax({.
            ..
        }).then( function( ){
            // success
        }, function( ){
            // error
        })
  • 利用promise的deferred对象解决延迟注册问题。

    var dtd = $.Deferred(); // 新建一个deferred对象
      var wait = function(dtd){
        var tasks = function(){
          alert("执行完毕!");
          dtd.resolve(); // 改变deferred对象的执行状态
        };
        setTimeout(tasks,5000);
        return dtd;
      };
  • HTML中Style、以及JavaScript中style移到CSS中class,在HTML、JavaScript中引入class,而不是直接style。

ECMAScript 5兼容性

尽量采用ES5方法,特别数组map、filter、forEach方法简化日常开发。在老式IE浏览器中引入ES5-shim。或者也可以考虑引入underscore、lodash 常用辅助库.
- 参考Kangax的 ES5 compatibility table

HTML、CSS、JavaScript分离

  • 页面DOM结构使用HTML,样式则采用CSS,动态DOM操作JavaScript。不要混用在HTML中

  • 分离在不同类型文件,文件link。

  • HTML、CSS、JavaScript变量名都需要有业务价值。CSS以中划线分割的全小写命名,JavaScript则首字母小写的驼峰命名。

  • CSS可引入Bootstrap、Foundation等出名响应式设计框架。以及SASS、LESS工具书写CSS。

  • 对于CSS、JavaScript建议合并为单文件,减少Ajax的连接数。也可以引入AMD(Require.js)加载方式。

  • 对于内部大部分企业管理系统,可以尝试采用前端 MVC框架组织代码。如Angular、React + Flux架构、Knockout等。

  • 对于兼容性可用Modernizr规范库辅助。

使用jsHint

  • 前端项目中推荐引入jshint插件来规范项目编码规范。以及一套完善的IDE配置。

  • 注意:jshint需要引入nodejs 工具grunt或gulp插件,建议企业级nodejs npm私服。

前端工具

  • 前端第三方JavaScript包管理工具bower(bower install jQuery),bower可以实现第三方库的依赖解析、下载、升级管理等。建议建立企业级bower私服。

  • 前端构建工具,可以采用grunt或者gulp工具,可以实现html、css、js压缩、验证、测试,文件合并、watch和liveload等所有前端任务。建议企业级nodejs npm私服。

  • 前端开发IDE: WebStorm( Idea )、Sublime为最佳 。项目组统一IDE。IDE统一配置很重要。


以上是非常詳細的前端JavaScript規範的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn