• 前端小技巧:JavaScript 编码规范


    前端小技巧:JavaScript 编码规范

    1. 类型

    1.1【可选】 基本类型: 当你访问一个基本类型时,直接操作它的值。

    string
    number
    boolean
    null
    undefined
    symbol

    符号(Symbols)不能完全的被 polyfill,因此在不能原生支持symbol类型的浏览器或环境中,不应该使用symbol类型。

    1.2 【可选】 复杂类型: 当你访问一个复杂类型时,直接操作其值的引用。

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

    2. 引用

    2.1 【必须】 使用 

    const

    定义你的所有引用;避免使用

    var

    原因? 这样能够确保你不能重新赋值你的引用,否则可能导致错误或者产生难以理解的代码。

    // bad
    var a = 1;
    var b = 2;
    
    // good
    const a = 1;
    const b = 2;

    2.2 【必须】 如果你必须重新赋值你的引用, 使用 

    let

    代替

    var

    原因? let 是块级作用域,而不像 var 是函数作用域

    // bad
    var count = 1;
    if (true) {
      count += 1;
    }
    
    // good, use the let.
    let count = 1;
    if (true) {
      count += 1;
    }

    2.3 【可选】 注意,let 和 const 都是块级作用域。

    // const 和 let 只存在于他们定义的块级作用域中。
    {
      let a = 1;
      const b = 1;
    }
    console.log(a); // ReferenceError
    console.log(b); // ReferenceError

    3. 对象

    3.1 【必须】 使用字面量语法创建对象。

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

    3.2 【推荐】 在创建具有动态属性名称的对象时使用计算属性名。原因? 它允许你在一个地方定义对象的所有属性。

    function getKey(k) {
      return `a key named ${k}`;
    }
    
    // bad
    const obj = {
      id: 5,
      name: 'San Francisco',
    };
    obj[getKey('enabled')] = true;
    
    // good
    const obj = {
      id: 5,
      name: 'San Francisco',
      [getKey('enabled')]: true,
    };

    3.3 【推荐】 用对象方法简写。

    // bad
    const value = 1;
    const atom = {
      value: value,
      addValue: function (newValue) {
        return atom.value + newValue;
      },
    };
    
    // good
    const value = 1;
    const atom = {
      value,
      addValue(newValue) {
        return atom.value + newValue;
      },
    };

    3.4 【推荐】 用属性值简写。

    const ScreenBody = 'Screen Body';
    
    // bad
    const obj = {
      ScreenBody: ScreenBody,
    };
    
    // good
    const obj = {
      ScreenBody,
    };

    3.5 【推荐】 声明对象时,将简写的属性放在前面。原因? 这样更容易的判断哪些属性使用的简写。

    const ScreenBody = 'Screen Body';
    const ModalText = 'Modal Text';
    
    // bad
    const obj = {
      One: 1,
      two: 2,
      ScreenBody,
      Three: 3,
      Fourth: 4,
      ModalText,
    };
    
    // good
    const obj = {
      ScreenBody,
      ModalText,
      One: 1,
      two: 2,
      Three: 3,
      Fourth: 4,
    };

    3.6 【必须】 只使用引号标注无效标识符的属性。

    // bad
    const bad = {
      'foo': 3,
      'bar': 4,
      'data-blah': 5,
    };
    
    // good
    const good = {
      foo: 3,
      bar: 4,
      'data-blah': 5,
    };

    3.7 【推荐】 不能直接调用 

    Object.prototype的方法,如: hasOwnProperty,propertyIsEnumerable,isPrototypeOf 

    原因? 这些方法可能被有问题的对象上的属性覆盖 - 如 { hasOwnProperty: false } - 或者,对象是一个空对象 Object.create(null)

    // bad
    console.log(object.hasOwnProperty(key));
    
    // good
    console.log(Object.prototype.hasOwnProperty.call(object, key));
    
    // best
    const has = Object.prototype.hasOwnProperty; // 在模块范围内的缓存中查找一次
    console.log(has.call(object, key));
    
    /* or */
    import has from 'has'; // https://www.npmjs.com/package/has
    console.log(has(object, key));

    3.8 【推荐】 使用对象扩展操作符(spread operator)浅拷贝对象,而不是用 Object.assign方法。 使用对象的剩余操作符(rest operator)来获得一个新对象,该对象省略了某些属性。

    // very bad
    const original = { a: 1, b: 2 };
    const copy = Object.assign(original, { c: 3 }); // 变异的 `original` ಠ_ಠ
    delete copy.a; // 这....
    
    // bad
    const original = { a: 1, b: 2 };
    const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 }
    
    // good
    const original = { a: 1, b: 2 };
    const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }
    
    const { a, ...noA } = copy; // noA => { b: 2, c: 3 }

    4. 数组

    4.1 【必须】 使用字面量语法创建数组。

    // bad
    const items = new Array();
    
    // good
    const items = [];

     4.2 【必须】 使用 Array#push 代替直接赋值来给数组添加项。

    const someStack = [];
    
    // bad
    someStack[someStack.length] = 'abracadabra';
    
    // good
    someStack.push('abracadabra');

    4.3 【必须】 使用数组展开符 ... 来拷贝数组。

    // bad
    const len = items.length;
    const itemsCopy = [];
    let i;
    
    for (i = 0; i < len; i += 1) {
      itemsCopy[i] = items[i];
    }
    
    // good
    const itemsCopy = [...items];

    4.4 【推荐】 使用展开符 ... 代替Array.from,将一个可迭代对象转换成一个数组。

    const foo = document.querySelectorAll('.foo');
    
    // good
    const nodes = Array.from(foo);
    
    // best
    const nodes = [...foo];

    4.5 【必须】 使用 Array.from 将一个类数组(array-like)对象转换成一个数组。

    const arrLike = { 0: 'foo', 1: 'bar', 2: 'baz', length: 3 };
    
    // bad
    const arr = Array.prototype.slice.call(arrLike);
    
    // good
    const arr = Array.from(arrLike);

    4.6 【必须】 使用 Array.from 代替展开符 ... 映射迭代器,因为它避免了创建一个中间数组。

    // bad
    const baz = [...foo].map(bar);
    
    // good
    const baz = Array.from(foo, bar);

    4.7 【推荐】 在数组回调函数中使用 return 语句。 如果函数体由单个语句的返回表达式组成,并且无副作用,那么可以省略返回值, 具体查看 8.2。

    // good
    [1, 2, 3].map((x) => {
      const y = x + 1;
      return x * y;
    });
    
    // good
    [1, 2, 3].map(x => x + 1);
    
    // bad - 没有返回值,意味着在第一次迭代后 `acc` 没有被定义
    [[0, 1], [2, 3], [4, 5]].reduce((acc, item, index) => {
      const flatten = acc.concat(item);
      acc[index] = flatten;
    });
    
    // good
    [[0, 1], [2, 3], [4, 5]].reduce((acc, item, index) => {
      const flatten = acc.concat(item);
      acc[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;
    });

    4.8 【推荐】 如果数组有多行,则在数组开始括号 [ 的时候换行,然后在数组结束括号 ] 的时候换行。

    // bad
    const arr = [
      [0, 1], [2, 3], [4, 5],
    ];
    
    const objectInArray = [{
      id: 1,
    }, {
      id: 2,
    }];
    
    const numberInArray = [
      1, 2,
    ];
    
    // good
    const arr = [[0, 1], [2, 3], [4, 5]];
    
    const objectInArray = [
      {
        id: 1,
      },
      {
        id: 2,
      },
    ];
    
    const numberInArray = [
      1,
      2,
    ];

    5. 解构

    5.1 【推荐】 在访问和使用对象的多个属性时使用对象解构。

    原因? 解构可以避免为这些属性创建临时引用。

    // 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}`;
    }
    
    // best
    function getFullName({ firstName, lastName }) {
      return `${firstName} ${lastName}`;
    }

    5.2 【推荐】 使用数组解构。

    const arr = [1, 2, 3, 4];
    
    // bad
    const first = arr[0];
    const second = arr[1];
    
    // good
    const [first, second] = arr;

    5.3 【必须】 在有多个返回值时, 使用对象解构,而不是数组解构。原因? 你可以随时添加新的属性或者改变属性的顺序,而不用修改调用方法。

    // bad
    function processInput(input) {
      // 处理代码...
      return [left, right, top, bottom];
    }
    
    // 调用者需要考虑返回数据的顺序。
    const [left, __, top] = processInput(input);
    
    // good
    function processInput(input) {
      // 处理代码...
      return { left, right, top, bottom };
    }
    
    // 调用者只选择他们需要的数据。
    const { left, top } = processInput(input);

    6. 字符

    6.1 【推荐】 使用单引号 

    // bad
    const name = "Capt. Janeway";
    
    // bad - 模板文字应该包含插值或换行。
    const name = `Capt. Janeway`;
    
    // good
    const name = 'Capt. Janeway';

    6.2 【必须】 不应该用字符串跨行连接符的格式来跨行编写,这样会使当前行长度超过100个字符。原因? 断开的字符串维护起来很痛苦,并且会提高索引难度。

    // bad
    const errorMessage = '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.';
    
    // bad
    const errorMessage = '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.';
    
    // good
    const errorMessage = '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.';

    6.3 【必须】 构建字符串时,使用字符串模板代替字符串拼接。

    原因? 字符串模板为您提供了一种可读的、简洁的语法,具有正确的换行和字符串插值特性。

    // bad
    function sayHi(name) {
      return 'How are you, ' + name + '?';
    }
    
    // bad
    function sayHi(name) {
      return ['How are you, ', name, '?'].join();
    }
    
    // bad
    function sayHi(name) {
      return `How are you, ${ name }?`;
    }
    
    // good
    function sayHi(name) {
      return `How are you, ${name}?`;
    }

    6.4 【必须】 永远不要使用 eval()执行放在字符串中的代码,它导致了太多的漏洞。

    6.5 【必须】 不要在字符串中转义不必要的字符。

    原因? 反斜杠损害了可读性,因此只有在必要的时候才可以出现。

    // bad
    const foo = '\'this\' \i\s \"quoted\"';
    
    // good
    const foo = '\'this\' is "quoted"';
    const foo = `my name is '${name}'`;

    7. 函数

    7.1 【可选】 使用命名的函数表达式代替函数声明。

    原因? 函数声明时作用域被提前了,这意味着在一个文件里函数很容易(太容易了)在其定义之前被引用。这样伤害了代码可读性和可维护性。如果你发现一个函数又大又复杂,并且它干扰了对这个文件其他部分的理解,那么是时候把这个函数单独抽成一个模块了!别忘了给表达式显式的命名,不用管这个名字是不是由一个确定的变量推断出来的(这在现代浏览器和类似babel编译器中很常见)。这消除了由匿名函数在错误调用栈产生的所有假设。 * (Discussion)

    // bad
    function foo() {
      // ...
    }
    
    // also good *
    const foo = function () {
      // ...
    };
    
    // good
    const short = function longUniqueMoreDescriptiveLexicalFoo() {
      // ...
    };

    7.2 【必须】 把立即执行函数包裹在圆括号里。

    原因? 立即调用的函数表达式是个独立的单元 - 将它和它的调用括号还有入参包装在一起可以非常清晰的表明这一点。请注意,在一个到处都是模块的世界中,您几乎用不到 IIFE。

    // immediately-invoked function expression (IIFE) 立即调用的函数表达式
    (function () {
      console.log('Welcome to the Internet. Please follow me.');
    }());

    7.3 【必须】 切记不要在非功能块中声明函数 (if, while)等,请将函数赋值给变量。 浏览器允许你这样做, 但是不同浏览器会有不同的行为, 这并不是什么好事。

    7.4 【必须】 ECMA-262 将 block 定义为语句列表。 而函数声明并不是语句。

    // bad
    if (currentUser) {
      function test() {
        console.log('Nope.');
      }
    }
    
    // good
    let test;
    if (currentUser) {
      test = () => {
        console.log('Yup.');
      };
    }

    7.5 【必须】 永远不要给一个参数命名为 arguments,这将会覆盖函数默认的arguments

    // bad
    function foo(name, options, arguments) {
      // ...
    }
    
    // good
    function foo(name, options, args) {
      // ...
    }

    7.6 【推荐】 使用 rest 语法 ...代替 arguments,

    原因? ... 明确了你想要拉取什么参数。 而且, rest 参数是一个真正的数组,而不仅仅是类数组的arguments

    // bad
    function concatenateAll() {
      const args = Array.prototype.slice.call(arguments);
      return args.join('');
    }
    
    // good
    function concatenateAll(...args) {
      return args.join('');
    }

    7.7 【推荐】 使用默认的参数语法,而不是改变函数参数。

    // really bad
    function handleThings(opts) {
      // 不!我们不应该修改参数。
      // 更加错误的是: 如果 opts 是一个 "非正值"(falsy)它将被设置成一个对象
      // 这或许正是你想要的,但它可能会导致一些难以察觉的错误。
      opts = opts || {};
      // ...
    }
    
    // still bad
    function handleThings(opts) {
      if (opts === void 0) {
        opts = {};
      }
      // ...
    }
    
    // good
    function handleThings(opts = {}) {
      // ...
    }

    7.8 【必须】 使用默认参数时避免副作用。原因? 他们很容易混淆。

    var b = 1;
    // bad
    function count(a = b++) {
      console.log(a);
    }
    count();  // 1
    count();  // 2
    count(3); // 3
    count();  // 3

    7.9 【推荐】 总是把默认参数放在最后。

    // bad
    function handleThings(opts = {}, name) {
      // ...
    }
    
    // good
    function handleThings(name, opts = {}) {
      // ...
    }

    7.10 【推荐】 永远不要使用函数构造器来创建一个新函数。

    原因? 以这种方式创建一个函数跟 eval() 差不多,将会导致漏洞。

    // bad
    var add = new Function('a', 'b', 'return a + b');
    
    // still bad
    var subtract = Function('a', 'b', 'return a - b');

    7.11 【必须】 函数声明语句中需要空格。

    原因? 一致性很好,在删除或添加名称时不需要添加或删除空格。

    // bad
    const f = function(){};
    const g = function (){};
    const h = function() {};
    
    // good
    const x = function () {};
    const y = function a() {};

    7.12 【推荐】 不要改变入参。
    原因? 操作入参对象会导致原始调用位置出现意想不到的副作用。

    // bad
    function f1(obj) {
      obj.key = 1;
    }
    
    // good
    function f2(obj) {
      const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1;
    }

    7.13 【推荐】 不要对入参重新赋值,也不要给入参的属性赋值。部分要求修改入参的常用库(如 Koa、Vuex)可以豁免。

    原因? 重新赋值参数会导致意外的行为,尤其是在访问 arguments 对象的时候。 它还可能导致性能优化问题,尤其是在 V8 中。

    // bad
    function f1(a) {
      a = 1;
      // ...
    }
    
    function f2(a) {
      if (!a) { a = 1; }
      // ...
    }
    
    // good
    function f3(a) {
      const b = a || 1;
      // ...
    }
    
    function f4(a = 1) {
      // ...
    }

    7.14 【推荐】 优先使用扩展运算符 ... 来调用可变参数函数。

    原因? 它更加清晰,你不需要提供上下文,并且能比用 apply 来执行可变参数的 new 操作更容易些。

    // bad
    const x = [1, 2, 3, 4, 5];
    console.log.apply(console, x);
    
    // good
    const x = [1, 2, 3, 4, 5];
    console.log(...x);
    
    // bad
    new (Function.prototype.bind.apply(Date, [null, 2016, 8, 5]));
    
    // good
    new Date(...[2016, 8, 5]);

    7.15 【推荐】 调用或者书写一个包含多个参数的函数应该像这个指南里的其他多行代码写法一样: 每行值包含一个参数,并且最后一行也要以逗号结尾。

    // bad
    function foo(bar,
                 baz,
                 quux) {
      // ...
    }
    
    // good
    function foo(
      bar,
      baz,
      quux,
    ) {
      // ...
    }
    
    // bad
    console.log(foo,
      bar,
      baz);
    
    // good
    console.log(
      foo,
      bar,
      baz,
    );

    8. 箭头函数

     

  • 相关阅读:
    Android 源码阅读之MMS细读TransactionService.java
    [Java2 入门经典]第16章 线程
    Android 源码阅读之建立3G网络流程
    从架构上看Android多媒体播放器
    Android 开发日志之仿三星Launcher
    非常适合OA系统的菜单
    模拟动网当前位置下拉菜单
    模拟windows菜单选项卡效果
    TreeView的各种操作
    ASCII表
  • 原文地址:https://www.cnblogs.com/bore/p/15878465.html
Copyright © 2020-2023  润新知