A mostly reasonable approach to JavaScript
Note: 。
-
1.1
function()
vsnew function()
function f1() { this.name = 'Tom'; const that = this; f2(that); } function f2(that) { this.name = 'Jerry'; console.log(that.name); //Tom console.log(this.name); //Jerry }
两种执行情况:
f1(); //普通函数 //Jerry //Jerry new f1(); //构造函数 //Tom //Jerry
f1()
作为普通函数执行时,函数内部this
此时指向global
, 而f2()
未指定调用者,函数内this
也指向global
,两者context相同。f1()
作为构造函数时,会建立一个独立的context,而f2()
的context 保持不变。
const
不可变
let
可变
// bad
const item = new Object();
// good
const item = {};
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,
};
// bad
const len = items.length;
const itemsCopy = [];
let i;
for (i = 0; i < len; i++) {
itemsCopy[i] = items[i];
}
// good
const itemsCopy = [...items];
// bad
function getFullName(user) {
const firstName = user.firstName;
const lastName = user.lastName;
return `${firstName} ${lastName}`;
}
// good
function getFullName(obj) {
const { firstName, lastName } = obj;
return `${firstName} ${lastName}`;
}
// best
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 sayHi(name) {
return 'How are you, ' + name + '?';
}
// bad
function sayHi(name) {
return ['How are you, ', name, '?'].join();
}
// good
function sayHi(name) {
return `How are you, ${name}?`;
}
class Queue {
constructor(contents = []) {
this._queue = [...contents];
}
pop() {
const value = this._queue[0];
this._queue.splice(0, 1);
return value;
}
}
// good
class PeekableQueue extends Queue {
peek() {
return this._queue[0];
}
}
class Jedi {
jump() {
this.jumping = true;
return this;
}
setHeight(height) {
this.height = height;
return this;
}
}
const luke = new Jedi();
luke.jump()
.setHeight(20);
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() {
superPower(); // => Flying
function superPower() {
console.log('Flying');
}
}
- 对象 被计算为 true
- Undefined 被计算为 false
- Null 被计算为 false
- 布尔值 被计算为 布尔的值
- 数字 如果是 +0、-0、或 NaN 被计算为 false, 否则为 true
- 字符串 如果是空字符串 '' 被计算为 false,否则为 true
if ([0]) {
// true
// An array is an object, objects evaluate to true
}
if (name) {
// ...stuff...
}
// good
if (collection.length) {
// ...stuff...
}
// 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;
}
// good
// is current tab
const active = true;
// good
function getType() {
console.log('fetching type...');
// set the default type to 'no type'
const type = this._type || 'no type';
return type;
}
class Calculator {
constructor() {
// FIXME: shouldn't use a global here
total = 0;
}
}
class Calculator {
constructor() {
// TODO: total should be configurable by an options param
this.total = 0;
}
}
为什么? 这会让 git diffs 更干净。另外,像 babel 这样的转译器会移除结尾多余的逗号,也就是说你不必担心老旧浏览器的尾逗号问题
// good - git diff with trailing comma
const hero = {
firstName: 'Florence',
lastName: 'Nightingale',
+ inventorOf: ['coxcomb chart', 'modern nursing'],
}
// good
const hero = {
firstName: 'Dana',
lastName: 'Scully',
};
const heroes = [
'Batman',
'Superman',
];
// good (防止函数在两个 IIFE 合并时被当成一个参数)
;(() => {
const name = 'Skywalker';
return name;
})();
// bad
const totalScore = this.reviewScore + '';
// good
const totalScore = String(this.reviewScore);
// good
/**
* 使用 parseInt 导致我的程序变慢,
* 改成使用位操作转换数字快多了。
*/
const val = inputValue >> 0;
Array.from(Array(100).keys());
[...Array(100).keys()];
Object.keys(Array(100).join().split(','));
Object.keys(Array(100).fill(undefined));
Object.keys(Array.apply(null,{length:100}));
Array.prototype.recursion = function(length) {
if (this.length === length) {
return this;
}
this.push(this.length);
this.recursion(length);
}
arr = [];
arr.recursion(100);
Array(100).fill(0).map(function (val, index) {
return index;
})
// good
const hasAge = Boolean(age);
// good
const hasAge = !!age;
// good
class User {
constructor(options) {
this.name = options.name;
}
}
const good = new User({
name: 'yup',
});
// bad
this.__firstName__ = 'Panda';
this.firstName_ = 'Panda';
// good
this._firstName = 'Panda';
// good
function foo() {
return () => {
console.log(this);
};
}
class Jedi {
constructor(options = {}) {
const lightsaber = options.lightsaber || 'blue';
this.set('lightsaber', lightsaber);
}
set(key, val) {
this[key] = val;
}
get(key) {
return this[key];
}
}
// bad
const sidebar = $('.sidebar');
// good
const $sidebar = $('.sidebar');
// good
const $sidebar = $('.sidebar');
// good
$('.sidebar ul').hide();
// good
$('.sidebar > ul').hide();
// good
$sidebar.find('ul').hide();