• JS 语言规范


    JS 语言规范

    语言规范

    JavaScript 是一种客户端脚本语言,这里列出了编写 JavaScript 时需要遵守的规则。

    类型

    • 基本类型

      • 字符串
      • 数值
      • 布尔类型
      • null
      • undefined
      const foo = 1
      let bar = foo
      
      bar = 9
      
      console.log(foo, bar) // 1, 9
      
    • 复杂类型

      • object
      • array
      • function
      const foo = [1, 2, 3]
      const bar = foo
      
      bar[0] = 9
      
      console.log(foo[0], bar[0]) // 9, 9
      

    引用

    const 和 let 都是块级作用域,var 是函数级作用域

    • 对所有引用都使用 const,不要使用 var

      // bad
      var a = 1
      var b = 2
      
      // good
      const a = 1
      const b = 2
      
    • 如果引用是可变动的,则使用 let

      // bad
      var count = 1
      if (count < 10) {
        count += 1
      }
      
      // good
      let count = 1
      if (count < 10) {
        count += 1
      }
      

    对象

    • 请使用字面量值创建对象

      // bad
      const a = new Object{}
      
      // good
      const a = {}
      
    • 别使用保留字作为对象的键值,这样在 IE8 下不会运行

      // bad
      const a = {
        default: {},  // default 是保留字
        common: {}
      }
      
      // good
      const a = {
        defaults: {},
        common: {}
      }
      
    • 请使用对象方法的简写方式

      // bad
      const item = {
        value: 1,
      
        addValue: function (val) {
          return item.value + val
        }
      }
      
      // good
      const item = {
        value: 1,
      
        addValue(val) {
          return item.value + val
        }
      }
      
    • 请使用对象属性值的简写方式

      const job = 'FrontEnd'
      
      // bad
      const item = {
        job: job
      }
      
      // good
      const item = {
        job
      }
      
    • 对象属性值的简写方式要和声明式的方式分组

      const job = 'FrontEnd'
      const department = 'JDC'
      
      // bad
      const item = {
        sex: 'male',
        job,
        age: 25,
        department
      }
      
      // good
      const item = {
        job,
        department,
        sex: 'male',
        age: 25
      }
      

    数组

    • 请使用字面量值创建数组

      // bad
      const items = new Array()
      
      // good
      const items = []
      
    • 向数组中添加元素时,请使用 push 方法

      const items = []
      
      // bad
      items[items.length] = 'test'
      
      // good
      items.push('test')
      
    • 使用拓展运算符 ... 复制数组

      // bad
      const items = []
      const itemsCopy = []
      const len = items.length
      let i
      
      // bad
      for (i = 0; i < len; i++) {
        itemsCopy[i] = items[i]
      }
      
      // good
      itemsCopy = [...items]
      
    • 使用数组的 map 等方法时,请使用 return 声明,如果是单一声明语句的情况,可省略 return

      // bad
      [1, 2, 3].map(x => {
        const y = x + 1
        return x * y
      })
      
      // good
      [1, 2, 3].map(x => x + 1)
      
      // bad
      const flat = {}
      [[0, 1], [2, 3], [4, 5]].reduce((memo, item, index) => {
        const flatten = memo.concat(item)
        flat[index] = flatten
      })
      
      // good
      const flat = {}
      [[0, 1], [2, 3], [4, 5]].reduce((memo, item, index) => {
        const flatten = memo.concat(item)
        flat[index] = flatten
        return flatten
      })
      
      // bad
      inbox.filter((msg) => {
        const { subject, author } = msg
        if (subject === 'Mockingbird') {
          return author === 'Harper Lee'
        } else {
          return false
        }
      })
      
      // good
      inbox.filter((msg) => {
        const { subject, author } = msg
        if (subject === 'Mockingbird') {
          return author === 'Harper Lee'
        }
      
        return false
      })
      

    解构赋值

    • 当需要使用对象的多个属性时,请使用解构赋值

      // bad
      function getFullName (user) {
        const firstName = user.firstName
        const lastName = user.lastName
      
        return `${firstName} ${lastName}`
      }
      
      // good
      function getFullName (user) {
        const { firstName, lastName } = user
      
        return `${firstName} ${lastName}`
      }
      
      // better
      function getFullName ({ firstName, lastName }) {
        return `${firstName} ${lastName}`
      }
      
    • 当需要使用数组的多个值时,请同样使用解构赋值

      const arr = [1, 2, 3, 4]
      
      // bad
      const first = arr[0]
      const second = arr[1]
      
      // good
      const [first, second] = arr
      
    • 函数需要回传多个值时,请使用对象的解构,而不是数组的解构

      // bad
      function doSomething () {
        return [top, right, bottom, left]
      }
      
      // 如果是数组解构,那么在调用时就需要考虑数据的顺序
      const [top, xx, xxx, left] = doSomething()
      
      // good
      function doSomething () {
        return { top, right, bottom, left }
      }
      
      // 此时不需要考虑数据的顺序
      const { top, left } = doSomething()
      

    字符串

    • 字符串统一使用单引号的形式 ''

      // bad
      const department = "JDC"
      
      // good
      const department = 'JDC'
      
    • 字符串太长的时候,请不要使用字符串连接符换行 \,而是使用 +

      const str = '凹凸实验室 凹凸实验室 凹凸实验室' +
        '凹凸实验室 凹凸实验室 凹凸实验室' +
        '凹凸实验室 凹凸实验室'
      
    • 程序化生成字符串时,请使用模板字符串

      const test = 'test'
      
      // bad
      const str = ['a', 'b', test].join()
      
      // bad
      const str = 'a' + 'b' + test
      
      // good
      const str = `ab${test}`
      

    函数

    • 请使用函数声明,而不是函数表达式

      // bad
      const foo = function () {
        // do something
      }
      
      // good
      function foo () {
        // do something
      }
      
    • 不要在非函数代码块中声明函数

      // bad
      if (isUse) {
        function test () {
          // do something
        }
      }
      
      // good
      let test
      if (isUse) {
        test = () => {
          // do something
        }
      }
      
    • 不要使用 arguments,可以选择使用 ...

      arguments 只是一个类数组,而 ... 是一个真正的数组

      // bad
      function test () {
        const args = Array.prototype.slice.call(arguments)
        return args.join('')
      }
      
      // good
      function test (...args) {
        return args.join('')
      }
      
    • 不要更改函数参数的值

      // bad
      function test (opts) {
        opts = opts || {}
      }
      
      // good
      function test (opts = {}) {
        // ...
      }
      

    原型

    • 使用 class,避免直接操作 prototype

      // bad
      function Queue (contents = []) {
        this._queue = [..contents]
      }
      Queue.prototype.pop = function () {
        const value = this._queue[0]
        this._queue.splice(0, 1)
        return value
      }
      
      // good
      class Queue {
        constructor (contents = []) {
          this._queue = [...contents]
        }
      
        pop () {
          const value = this._queue[0]
          this._queue.splice(0, 1)
          return value
        }
      }
      

    模块

    • 使用标准的 ES6 模块语法 import 和 export

      // bad
      const util = require('./util')
      module.exports = util
      
      // good
      import Util from './util'
      export default Util
      
      // better
      import { Util } from './util'
      export default Util
      
    • 不要使用 import 的通配符 *,这样可以确保你只有一个默认的 export

      // bad
      import * as Util from './util'
      
      // good
      import Util from './util'
      

    迭代器

    • 不要使用 iterators

      const numbers = [1, 2, 3, 4, 5]
      
      // bad
      let sum = 0
      for (let num of numbers) {
        sum += num
      }
      
      // good
      let sum = 0
      numbers.forEach(num => sum += num)
      
      // better
      const sum = numbers.reduce((total, num) => total + num, 0)
      

    对象属性

    • 使用 . 来访问对象属性

      const joke = {
        name: 'haha',
        age: 28
      }
      
      // bad
      const name = joke['name']
      
      // good
      const name = joke.name
      

    变量声明

    • 声明变量时,请使用 constlet 关键字,如果没有写关键字,变量就会暴露在全局上下文中,这样很可能会和现有变量冲突,另外,也很难明确该变量的作用域是什么。这里推荐使用 const 来声明变量,我们需要避免全局命名空间的污染。

      // bad
      demo = new Demo()
      
      // good
      const demo = new Demo()
      
    • 将所有的 const 和 let 分组

      // bad
      let a
      const b
      let c
      const d
      let e
      
      // good
      const b
      const d
      let a
      let c
      let e
      

    注释:

    1.单行注释:

      两个斜杠 // 可以创建一个单行注释,斜杠后面要增加一个空格,紧接着是注释内容。

      注释的缩进需要与所注释的代码一致,且要位于被注释代码的上面。

      代码演示如下:

    // w3cschool教程测试函数
    function func() {
    // 用来存储定时器函数标识
    let flag = null;
    }

    2.多行注释:

      /*/ 可以创建多行注释,也就是以 "/" 开始,"*/" 结束,中间是注释内容。

      既然是多行注释,自然被注释的内容是可以换行的。

      尽量使用单行注释替代多行注释,如果注释函数,推荐使用多行注释。

    3.函数的注释:

      函数是使用最为频繁的语法结构,相对较为复杂,所以良好的注释对于理解函数的功能非常有必要。

      注释格式如下:

    /*方法说明
    *@method 方法名
    *@for 所属类名
    *@param{参数类型}参数名 参数说明
    *@return {返回值类型} 返回值说明
    */

      可以看到在注释的开始于结尾分别是 / 与 /,具体的注释内容前面也带有一个星号,看起来更加整齐。

      看一段简单的注释代码实例:

    /*函数说明
    * @param {string} p1 参数1的说明
    * @param {string} p2 参数2的说明,比较长
    *     那就换行了.
    * @param {number=} p3 参数3的说明(可选)
    * @return {Object} 返回值描述
    */
    function foo(p1, p2, p3) {
    var p3 = p3 || 10;
    return {
      p1: p1,
      p2: p2,
      p3: p3
    };
    }

    4.模块注释:

      模块注释格式如下:

    /* 模块说明
    * @module 模块名
    */
    /* 类说明
    * @class 类名
    * @constructor
    */

      由于类分为静态类与非静态类,所以 class 需要与 constructor 或者 static 配合使用。

    5.注释内容:

      知道为什么需要注释,那么也就知道注释应该怎么写。

      注释的目的是告诉阅读者不宜察觉或者不易获取到的信息,而不是一目了然的东西。

    // 声明一个变量timer
    let timer=null;

    Hoisting

    • var 存在变量提升的情况,即 var 声明会被提升至该作用域的顶部,但是他们的赋值并不会。而 const 和 let 并不存在这种情况,他们被赋予了 Temporal Dead Zones, TDZ

      function example () {
        console.log(notDefined)   // => throws a ReferenceError
      }
      
      function example () {
        console.log(declareButNotAssigned)  // => undefined
        var declaredButNotAssigned = true
      }
      
      function example () {
        let declaredButNotAssigned
        console.log(declaredButNotAssigned)   // => undefined
        declaredButNotAssigned = true
      }
      
      function example () {
        console.log(declaredButNotAssigned)   // => throws a ReferenceError
        console.log(typeof declaredButNotAssigned)  // => throws a ReferenceError
        const declaredButNotAssigned = true
      }
      
    • 匿名函数的变量名会提升,但函数内容不会

      function example () {
        console.log(anonymous)  // => undefined
      
        anonymous()
      
        var anonymous = function () {
          console.log('test')
        }
      }
      
    • 命名的函数表达式的变量名会被提升,但函数名和函数函数内容并不会

      function example() {
        console.log(named)  // => undefined
      
        named()   // => TypeError named is not a function
      
        superPower()  // => ReferenceError superPower is not defined
      
        var named = function superPower () {
          console.log('Flying')
        }
      }
      
      function example() {
        console.log(named)  // => undefined
      
        named()   // => TypeError named is not a function
      
        var named = function named () {
          console.log('named')
        }
      }
      

    分号

    • 我们遵循 Standard 的规范,不使用分号。

      关于应不应该使用分号的讨论有很多,本规范认为非必要的时候,应该不使用分号,好的 JS 程序员应该清楚场景下是一定要加分号的,相信你也是名好的开发者。

      // bad
      const test = 'good';
      (function () {
        const str = 'hahaha';
      })()
      
      // good
      const test = 'good'
      ;(() => {
        const str = 'hahaha'
      })();
      

    标准特性

    为了代码的可移植性和兼容性,我们应该最大化的使用标准方法,例如优先使用 string.charAt(3) 而不是 string[3]

    eval()

    由于 eval 方法比较 evil,所以我们约定禁止使用该方法

    with() {}

    由于 with 方法会产生神奇的作用域,所以我们也是禁止使用该方法的

    for-in 循环

    推荐使用 for in 语法,但是在对对象进行操作时,容易忘了检测 hasOwnProperty(key),所以我们启用了 ESLint 的 guard-for-in 选项

    对数组进行 for in 的时候,顺序是不固定的

    修改内置对象的原型

    不要修改内置对象,如 Object 和 Array

    编码规范

    统一团队的编码规范,有助于代码的维护。本章是传统意义上的 Style Guideline,目的是统一一些相对主观化的代码风格。

    单行代码块

    在单行代码块中使用空格

    不推荐

    function foo () {return true}
    if (foo) {bar = 0}
    

    推荐

    function foo () { return true }
    if (foo) { bar = 0 }
    

    大括号风格

    在编程过程中,大括号风格与缩进风格紧密联系,用来描述大括号相对代码块位置的方法有很多。在 JavaScript 中,主要有三种风格,如下:

    • One True Brace Style

      if (foo) {
        bar()
      } else {
        baz()
      }
      
    • Stroustrup

      if (foo) {
        bar()
      }
      else {
        baz()
      }
      
    • Allman

      if (foo)
      {
        bar()
      }
      else
      {
        baz()
      }
      

    我们团队约定使用 One True Brace Style 风格

    变量命名

    当命名变量时,主流分为驼峰式命名(variableName)和下划线命名(variable_name)两大阵营。

    团队约定使用驼峰式命名

    拖尾逗号

    在 ECMAScript5 里面,对象字面量中的拖尾逗号是合法的,但在 IE8(非 IE8 文档模式)下,当出现拖尾逗号,则会抛出错误。

    拖尾逗号的例子:

    var foo = {
      name: 'foo',
      age: '22',
    }
    

    拖尾逗号的好处是,简化了对象和数组添加或删除元素,我们只需要修改新增的行即可,并不会增加差异化的代码行数。

    因为拖尾逗号有好也有不好,所以团队约定允许在最后一个元素或属性与闭括号 ] 或 } 在不同行时,可以(但不要求)使用拖尾逗号。当在同一行时,禁止使用拖尾逗号。

    逗号空格

    逗号前后的空格可以提高代码的可读性,团队约定在逗号后面使用空格,逗号前面不加空格。

    不推荐

    var foo = 1,bar = 2
    var foo = 1 , bar = 2
    var foo = 1 ,bar = 2
    

    推荐

    var foo = 1, bar = 2
    

    逗号风格

    逗号分隔列表时,在 JavaScript 中主要有两种逗号风格:

    • 标准风格,逗号放置在当前行的末尾
    • 逗号前置风格,逗号放置在下一行的开始位置

    团队约定使用标准风格

    不推荐

    var foo = 1
    ,
    bar = 2
    
    var foo = 1
    , bar = 2
    
    var foo = ['name'
              , 'age']
    

    推荐

    var foo = 1,
        bar = 2
    
    var foo = ['name',
                'age']
    

    计算属性的空格

    团队约定在对象的计算属性内,禁止使用空格

    不推荐

    obj['foo' ]
    obj[ 'foo']
    obj[ 'foo' ]
    

    推荐

    obj['foo']
    

    拖尾换行

    在非空文件中,存在拖尾换行是一个常见的 UNIX 风格,它的好处是可以方便在串联和追加文件时不会打断 Shell 的提示。在日常的项目中,保留拖尾换行的好处是,可以减少版本控制时的代码冲突。

    不推荐

    function func () {
      // do something
    }
    

    推荐

    function func () {
      // do something
    }
      // 此处是新的一行
    

    可以通过 .editorconfig 添加 EOL

    函数调用

    为了避免语法错误,团队约定在函数调用时,禁止使用空格

    不推荐

    fn ()
    fn
    ()
    

    推荐

    fn()
    

    缩进

    代码保持一致的缩进,是作为工程师的职业素养。但缩进用两个空格,还是四个空格,是用 Tab 还是空格呢?这样的争论太多了,也得不出答案。本规范结合了市面上优秀的开源项目,姑且约定使用 空格 来缩进,而且缩进使用两个空格。

    那是不是不能使用 Tab 进行缩进了?我们可以通过配置 .editorconfig ,将 Tab 自动转换为空格。

    对象字面量的键值缩进

    团队约定对象字面量的键和值之间不能存在空格,且要求对象字面量的冒号和值之间存在一个空格

    不推荐

    var obj = { 'foo' : 'haha' }
    

    推荐

    var obj = { 'foo': 'haha' }
    

    构造函数首字母大写

    在 JavaScript 中 new 操作符用来创建某个特定类型的对象的一个实例,该类型的对象是由一个构造函数表示的。由于构造函数只是常规函数,唯一区别是使用 new 来调用。所以我们团队约定构造函数的首字母要大小,以此来区分构造函数和普通函数。

    不推荐

    var fooItem = new foo()
    

    推荐

    var fooItem = new Foo()
    

    构造函数的参数

    在 JavaScript 中,通过 new 调用构造函数时,如果不带参数,可以省略后面的圆括号。但这样会造成与整体的代码风格不一致,所以团队约定使用圆括号

    不推荐

    var person = new Person
    

    推荐

    var person = new Person()
    

    链式调用

    链式调用如果放在同一行,往往会造成代码的可读性差,但有些时候,短的链式调用并不会影响美观。所以本规范约定一行最多只能有四个链式调用,超过就要求换行。

    空行

    空白行对于分离代码逻辑有帮助,但过多的空行会占据屏幕的空间,影响可读性。团队约定最大连续空行数为 2

    不推荐

    var a = 1
    
    
    
    var b = 2
    

    推荐

    var a = 1
    
    
    var b = 2
    

    链式赋值

    链式赋值容易造成代码的可读性差,所以团队约定禁止使用链式赋值

    不推荐

    var a = b = c = 1
    

    推荐

    var a = 1
    var b = 1
    var c = 1
    

    变量声明

    JavaScript 允许在一个声明中,声明多个变量。团队约定在声明变量时,一个声明只能有一个变量

    不推荐

    var a, b, c
    

    推荐

    var a
    var b
    var c
    

    分号

    JavaScript 在所有类 C 语言中是比较独特的,它不需要在每个语句的末尾有分号。在很多情况下,JavaScript 引擎可以确定一个分号应该在什么位置然后自动添加它。此特征被称为 自动分号插入 (ASI),被认为是 JavaScript 中较为有争议的特征。

    团队中对于是否应该使用分号,也有许多争论,本规范推荐不使用分号,因为我们认为好的工程师应该知道什么时候该加,什么时候不该加。

    相关参考 :semi

    代码块空格

    一致性是任何风格指南的重要组成部分。虽然在哪里放置块的开括号纯属个人偏好,但在整个项目中应该保持一致。不一致的风格将会分散读者阅读代码的注意力。

    团队约定代码块前要添加空格

    不推荐

    if (a){
      b()
    }
    
    function a (){}
    

    推荐

    if (a) {
      b()
    }
    
    function a () {}
    

    函数声明的空格

    当格式化一个函数,函数名或 function 关键字与左括号之间允许有空白。命名函数要求函数名和 function 关键字之间有空格,但是匿名函数要求不加空格。

    团队约定函数括号前要加空格

    不推荐

    function func(x) {
      // ...
    }
    

    推荐

    function func (x) {
      // ...
    }
    

    操作符的空格

    团队约定操作符前后都需要添加空格

    不推荐

    var sum = 1+2
    

    推荐

    var sum = 1 + 2
    

    BOM

    Unicode 字节顺序标记 (BOM) 用来指定代码单元是高字节序还是低字节序。也就是说,是高位在前还是低位在前。UTF-8 不需要 BOM 来表明字节顺序,因为单个字节并不影响字节顺序。

  • 相关阅读:
    Kubernetes+Docker+Istio 容器云实践
    SDN网络IPv6组播机制支持实时视频业务海量用户扩展
    如何运用结构化思维进行故障处理
    UAVStack JVM监控分析工具:图形化展示采集及分析监控数据
    个性化推荐产品功能的设计和B端产品的功能策划方式
    Kubernetes监控实践(2):可行监控方案之Prometheus和Sensu
    demo演示如何写一个无配置格式统一的日志
    指尖前端重构(React)技术调研分析
    学习设计模式前传
    我是码农要翻身
  • 原文地址:https://www.cnblogs.com/xikui/p/16191328.html
Copyright © 2020-2023  润新知