JavaScript 编码指导

发布于 2024-10-06 16:59:11 字数 20170 浏览 0 评论 0

类型

基本类型 : 获取一个基本类型的的时候,你得到的是值本身。

  • string
  • number
  • boolean
  • null
  • undefined
var foo = 1,
    bar = foo;

bar = 9;

console.log(foo, bar); // => 1, 9

复合类型 : 获取一个复合类型的时候,你得到是值的引用。

  • object
  • array
  • function
var foo = [1, 2],
    bar = foo;

bar[0] = 9;

console.log(foo[0], bar[0]); // => 9, 9

对象

  • 使用 literal 语法创建对象。
// bad
var item = new Object();

// good
var item = {};
// bad
var superman = {
  class: 'superhero',
  default: { clark: 'kent' },
  private: true
};

// good
var superman = {
  klass: 'superhero',
  defaults: { clark: 'kent' },
  hidden: true
};

数组

  • 使用 literal 语法创建数组。
// bad
var items = new Array();

// good
var items = [];
  • 不知道数组的长度的时候使用 Array#push。
var someStack = [];


// bad
someStack[someStack.length] = 'abracadabra';

// good
someStack.push('abracadabra');
  • 需要复制一个数组的时候使用 Array#slice jsPerf
var len = items.length,
    itemsCopy = [],
    i;

// bad
for (i = 0; i < len; i++) {
  itemsCopy[i] = items[i];
}

// good
itemsCopy = items.slice();
  • 将 array-like 的对象转换成数组时,使用 Array#slice。
function trigger() {
  var args = Array.prototype.slice.call(arguments);
  ...
}

字符串

  • 字符串使用单引号 ''
// bad
var name = "Bob Parr";

// good
var name = 'Bob Parr';

// bad
var fullName = "Bob " + this.lastName;

// good
var fullName = 'Bob ' + this.lastName;
  • 长于 80 字符的字符串应该使用字符串连接符 + 跨多行书写。
  • 注意:带字符串连接符的长字符串在过长的时候会影响性能。 jsPerf & Discussion
// bad
var 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
var 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
var 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.';
  • 在构建一个字符串时,使用 Array#join 代替字符串连接符。尤其在 IE 下: jsPerf
var items,
    messages,
    length,
    i;

messages = [{
  state: 'success',
  message: 'This one worked.'
},{
  state: 'success',
  message: 'This one worked as well.'
},{
  state: 'error',
  message: 'This one did not work.'
}];

length = messages.length;

// bad
function inbox(messages) {
  items = '<ul>';

  for (i = 0; i < length; i++) {
    items += '<li>' + messages[i].message + '</li>';
  }

  return items + '</ul>';
}

// good
function inbox(messages) {
  items = [];

  for (i = 0; i < length; i++) {
    items[i] = messages[i].message;
  }

  return '<ul><li>' + items.join('</li><li>') + '</li></ul>';
}

函数

  • 函数表达式:
// anonymous function expression
var anonymous = function() {
  return true;
};

// named function expression
var named = function named() {
  return true;
};

// immediately-invoked function expression (IIFE)
(function() {
  console.log('Welcome to the Internet. Please follow me.');
})();
  • Never declare a function in a non-function block (if, while, etc). Assign the function to a variable instead. Browsers will allow you to do it, but they all interpret it differently, which is bad news bears.
  • 注意: ECMA-262 定义了 block 为一系列语句,一个函数声明不是一个语句。 Read ECMA-262's note on this issue
// bad
if (currentUser) {
  function test() {
    console.log('Nope.');
  }
}

// good
if (currentUser) {
  var test = function test() {
    console.log('Yup.');
  };
}
  • 永远不要命名一个形参为 arguments,这会导致形参 arguments 的优先级比存在于所有函数作用域的 arguments 对象高。
// bad
function nope(name, options, arguments) {
  // ...stuff...
}

// good
function yup(name, options, args) {
  // ...stuff...
}

属性

  • 获取一个属性的值使用点语法。
var luke = {
  jedi: true,
  age: 28
};

// bad
var isJedi = luke['jedi'];

// good
var isJedi = luke.jedi;
  • 在键为变量时使用 [] 获取属性的值。
var luke = {
  jedi: true,
  age: 28
};

function getProp(prop) {
  return luke[prop];
}

var isJedi = getProp('jedi');

变量

  • 一直使用 var 去声明变量,不这样做的话会导致生成全局变量,我们应该避免污染全局命名空间。
// bad
superPower = new SuperPower();

// good
var superPower = new SuperPower();
  • 使用一个 var 声明多个变量,每个变量独占一行。
// bad
var items = getItems();
var goSportsTeam = true;
var dragonball = 'z';

// good
var items = getItems(),
    goSportsTeam = true,
    dragonball = 'z';
  • 最后才声明没有赋值的变量,这在你稍后想通过前面已赋值的变量来赋值给另一个变量是很有用。
// 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;
  • 在作用域顶部进行变量赋值,这个避免了变量声明提升(hoist) 带来的问题。
// bad
function() {
  test();
  console.log('doing stuff..');

  //..other stuff..

  var name = getName();

  if (name === 'test') {
    return false;
  }

  return name;
}

// good
function() {
  var name = getName();

  test();
  console.log('doing stuff..');

  //..other stuff..

  if (name === 'test') {
    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;
}

提升(hoisting)

  • 变量声明会被提升(hoist) 到它们作用域的顶部,而声明的赋值部分不会被提升。
// we know this wouldn't work (assuming there
// is no notDefined global variable)
function example() {
  console.log(notDefined); // => throws a ReferenceError
}

// creating a variable declaration after you
// reference the variable will work due to
// variable hoisting. Note: the assignment
// value of `true` is not hoisted.
function example() {
  console.log(declaredButNotAssigned); // => undefined
  var declaredButNotAssigned = true;
}

// The interpreter is hoisting the variable
// declaration to the top of the scope.
// Which means our example could be rewritten as:
function example() {
  var declaredButNotAssigned;
  console.log(declaredButNotAssigned); // => undefined
  declaredButNotAssigned = true;
}
  • 匿名函数表达式提升它们的变量名,而不会提升函数赋值。
function example() {
  console.log(anonymous); // => undefined

  anonymous(); // => TypeError anonymous is not a function

  var anonymous = function() {
    console.log('anonymous function expression');
  };
}
  • 命名函数表达式提升变量名,而不会提升函数名和函数体。
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');
  };


  // the same is true when the function name
  // is the same as the variable name.
  function example() {
    console.log(named); // => undefined

    named(); // => TypeError named is not a function

    var named = function named() {
      console.log('named');
    };
  }
}
  • 函数声明提升它们的名称和函数体。
function example() {
  superPower(); // => Flying

  function superPower() {
    console.log('Flying');
  }
}

条件语句和相等

  • 使用 ===!== ,替代 ==!=
  • 条件语句执行时会使用 ToBoolean 方法进行强制转换,遵循以下简单的规则:
    • Objects 转换为 true
    • Undefined 转换为 false
    • Null 转换为 false
    • Booleans 转换为 布尔值
    • Numbers 为**+0, -0, or NaN 转换为 false**,否则转换为 true
    • Strings 为空字符串 '' 时转换为 false ,否则转换为 true
if ([0]) {
  // true
  // An array is an object, objects evaluate to true
}
  • 使用简写。
// bad
if (name !== '') {
  // ...stuff...
}

// good
if (name) {
  // ...stuff...
}

// bad
if (collection.length > 0) {
  // ...stuff...
}

// good
if (collection.length) {
  // ...stuff...
}

代码块

  • 多行代码块使用大括号。
// 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('fetching type...');
  // set the default type to 'no type'
  var type = this._type || 'no type';

  return type;
}

// good
function getType() {
  console.log('fetching type...');

  // set the default type to 'no type'
  var type = this._type || 'no type';

  return type;
}
  • 在你的注释前加上 FIXME 或者 TODO 帮助其它开发者快速了解你是否指出了一个问题,或者你是否针对问题提出了需要实现的解决方法。这些注释不同与常规的注释,它们代表“可执行”,分别是 FIXME --需要解决 或者 TODO --需要实现
  • 使用 // FIXME: 注明问题。
function Calculator() {

  // FIXME: shouldn't use a global here
  total = 0;

  return this;
}
  • 使用 // TODO: 注明问题的解决方法。
function Calculator() {

  // TODO: total should be configurable by an options param
  this.total = 0;

  return this;
}

空格

  • 使用两个空格长度的软缩进(使用空格缩进)。
// bad
function() {
∙∙∙∙var name;
}

// bad
function() {
∙var name;
}

// good
function() {
∙∙var name;
}
  • 在左大括号前保留一个空格。
// bad
function test(){
  console.log('test');
}

// good
function test() {
  console.log('test');
}

// bad
dog.set('attr',{
  age: '1 year',
  breed: 'Bernese Mountain Dog'
});

// good
dog.set('attr', {
  age: '1 year',
  breed: 'Bernese Mountain Dog'
});
  • 文件末尾保留一个空行。
// bad
(function(global) {
  // ...stuff...
})(this);
// good
(function(global) {
  // ...stuff...
})(this);
// new line here
  • 长的方法链时使用缩进。
// bad
$('#items').find('.selected').highlight().end().find('.open').updateCount();

// good
$('#items')
  .find('.selected')
    .highlight()
    .end()
  .find('.open')
    .updateCount();

// bad
var leds = stage.selectAll('.led').data(data).enter().append('svg:svg').class('led', true)
    .attr('width',  (radius + margin) * 2).append('svg:g')
    .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
    .call(tron.led);

// good
var leds = stage.selectAll('.led')
    .data(data)
  .enter().append('svg:svg')
    .class('led', true)
    .attr('width',  (radius + margin) * 2)
  .append('svg:g')
    .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
    .call(tron.led);

逗号置于行末

  • 逗号置于行未。
// bad
var once
  , upon
  , aTime;

// good
var once,
    upon,
    aTime;

// bad
var hero = {
    firstName: 'Bob'
  , lastName: 'Parr'
  , heroName: 'Mr. Incredible'
  , superPower: 'strength'
};

// good
var hero = {
  firstName: 'Bob',
  lastName: 'Parr',
  heroName: 'Mr. Incredible',
  superPower: 'strength'
};

分号

  • 分号。
// bad
(function() {
  var name = 'Skywalker'
  return name
})()

// good
(function() {
  var name = 'Skywalker';
  return name;
})();

// good
;(function() {
  var name = 'Skywalker';
  return name;
})();

类型转换和强制转换

  • 在语句开头执行强制转换。
  • 字符串:
// => this.reviewScore = 9;

// bad
var totalScore = this.reviewScore + '';

// good
var totalScore = '' + this.reviewScore;

// bad
var totalScore = '' + this.reviewScore + ' total score';

// good
var totalScore = this.reviewScore + ' total score';
  • 使用 parseInt 对数字进行强制转换,并保证提供基数。
  • 出于不得已的原因, parseInt 成为了瓶颈,你因为 性能原因 需要使用位移,在注释里解释你这样做的原因。
var inputValue = '4';

// 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: 'Bob Parr'
});

// good
var thisIsMyObject = {};
function thisIsMyFunction() {};
var user = new User({
  name: 'Bob Parr'
});
  • 使用 Pascal(PascalCase) 命名法命名构造函数或者类。
// bad
function user(options) {
  this.name = options.name;
}

var bad = new user({
  name: 'nope'
});

// good
function User(options) {
  this.name = options.name;
}

var good = new User({
  name: 'yup'
});
  • 命名私有属性时在属性名前加下划线 _
// bad
this.__firstName__ = 'Panda';
this.firstName_ = 'Panda';

// good
this._firstName = 'Panda';
  • 保存一个 this 的引用时使用 _this
// bad
function() {
  var self = this;
  return function() {
    console.log(self);
  };
}

// bad
function() {
  var that = this;
  return function() {
    console.log(that);
  };
}

// good
function() {
  var _this = this;
  return function() {
    console.log(_this);
  };
}
  • 给函数命名,有利于堆栈跟踪。
// bad
var log = function(msg) {
  console.log(msg);
};

// good
var log = function log(msg) {
  console.log(msg);
};

取值函数和赋值函数

  • 取、赋值函数是非必须的。
  • 如果确实需要取、赋值函数,使用 getVal() 和 setVal()。
// bad
dragon.age();

// good
dragon.getAge();

// bad
dragon.age(25);

// good
dragon.setAge(25);
  • 如果属性值是布尔值,使用 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 || 'blue';
  this.set('lightsaber', lightsaber);
}

Jedi.prototype.set = function(key, val) {
  this[key] = val;
};

Jedi.prototype.get = function(key) {
  return this[key];
};

构造函数

  • 将方法赋值给 prototype 对象,而不要用新的对象覆盖 prototype 的值。Overwriting the prototype makes inheritance impossible: by resetting the prototype you'll overwrite the base!
function Jedi() {
  console.log('new jedi');
}

// bad
Jedi.prototype = {
  fight: function fight() {
    console.log('fighting');
  },

  block: function block() {
    console.log('blocking');
  }
};

// good
Jedi.prototype.fight = function fight() {
  console.log('fighting');
};

Jedi.prototype.block = function block() {
  console.log('blocking');
};
  • 方法可以返回 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 || 'no name';
}

Jedi.prototype.getName = function getName() {
  return this.name;
};

Jedi.prototype.toString = function toString() {
  return 'Jedi - ' + this.getName();
};

模块

  • 模块应该以一个 ! 开始,这样确保了脚本部署的时候不会因为模块缺少了最后一个分号而报错。
  • 文件名用驼峰命名法命名,保存在同名的文件夹,与单一入口的名字匹配。
  • 添加一个 noConflict() 方法,设置 exported 模块的值为前一个版本并返回当前模块。
  • 在模块顶部保持声明 'use strict';
// fancyInput/fancyInput.js

!function(global) {
  'use strict';

  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 对象时在对象名前加 $
// bad
var sidebar = $('.sidebar');

// good
var $sidebar = $('.sidebar');
  • 缓存 jQuery 的查找结果。
// bad
function setSidebar() {
  $('.sidebar').hide();

  // ...stuff...

  $('.sidebar').css({
    'background-color': 'pink'
  });
}

// good
function setSidebar() {
  var $sidebar = $('.sidebar');
  $sidebar.hide();

  // ...stuff...

  $sidebar.css({
    'background-color': 'pink'
  });
}
  • 对于 DOM 查询,使用 Cascading $('.sidebar ul') 或者 parent > child $('.sidebar > ul') jsPerf
  • 对于表示特定范围的 jQuery 对象使用 find 查询。
// bad
$('.sidebar', 'ul').hide();

// bad
$('.sidebar').find('ul').hide();

// good
$('.sidebar ul').hide();

// good
$('.sidebar > ul').hide();

// good (slower)
$sidebar.find('ul');

// good (faster)
$($sidebar[0]).find('ul');

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

上一篇:

下一篇: 没有了

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

薄荷港

暂无简介

0 文章
0 评论
22 人气
更多

推荐作者

忆伤

文章 0 评论 0

眼泪也成诗

文章 0 评论 0

zangqw

文章 0 评论 0

旧伤慢歌

文章 0 评论 0

qq_GlP2oV

文章 0 评论 0

旧时模样

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文