[Javascript] 编程实践之1: Google的Javascript代码风格5:语言特性

gulp-es6-module-to-closure:编译 importexport => goog.requiregoog.provide gulp-es6-module-to-closure 编译 ES6 import/export => Google Closure goog.require/goog.provide 注意:为了支持 ES6 特性,引入了一些特殊规则。 请参见下面的示例,尤其是当您使用现有代码中的翻译库时。 安装 npm install gulp-es6-module-to-closure --save-dev 用法 var es6ModuleToClosure = require ( "gulp-es6-module-to-closure" ) ; gulp . src ( "./src/**/*.js" ) . pipe ( es6ModuleToClosure ( { root : 'src' , namespace : "prefix.name.space" } ) ) 立即下载

Google的Javascript风格指南

5 语言特性

JavaScript包含许多可疑(甚至危险)的特性。本节描述哪些功能可以使用,哪些不可以使用,以及对它们的使用的任何附加限制。

5.1 局部变量声明

5.1.1 const和let的使用

使用const或者let声明所有的局部变量。默认情况下使用const,除非需要重新给变量赋值。不能使用var关键字。

5.1.2 每次只声明一个变量

每次只声明一个局部变量;不使用a = 1, b = 2;这种方式。

5.1.3 仅在需要时声明,并且尽快初始化

局部变量通常不会在其包含的块或类似块的构造的开始处声明。相反,局部变量被声明在它们第一次使用的地方附近(在合理范围内),从而以最小化它们的作用域。

5.1.4 根据需要声明类型

如果没有其它JSDoc,可以在声明上方的行中添加JSDoc类型注释,或者在变量名之前内联添加注释。

例子:

const /** !Array<number> */ data = [];

/**
 * Some description.
 * @type {!Array<number>}
 */
const data = [];

不允许混合内联和JSDoc样式:编译器将只处理第一个JSDoc,内联注释将丢失。

/** Some description. */
const /** !Array<number> */ data = [];

提示:在很多情况下,编译器可以推断出模板化的类型,但不能推断出它的参数。当初始化文字或构造函数调用不包含模板参数类型的任何值(例如,空数组、对象、映射或集合),或者变量在闭包中被修改时,尤其如此。局部变量类型注释在这些情况下特别有用,因为不这样的话编译器将推断模板参数为未知。

5.2 数组文法

5.2.1 使用拖拽逗号
const values = [
  'first value',
  'second value',
];
5.2.2 不要使用可变数组的构造函数

如果添加或者删除参数,则构造函数很容易出错。使用文法来代替。

不允许:

const a1 = new Array(x1, x2, x3);
const a2 = new Array(x1, x2);
const a3 = new Array(x1);
const a4 = new Array();

除了第三种情况外,其它与预期一致:如果x1是整数,那么a3就是一个大小为x1的数组,其中所有元素都是未定义的。如果x1是其他任何数字,则抛出异常,如果是其他任何数字,则抛出单元素数组。

相反,应该这样写:

const a1 = [x1, x2, x3];
const a2 = [x1, x2];
const a3 = [x1];
const a4 = [];

在适当时候,允许使用新数组(长度)来显式地分配给定长度的数组:new Array(length)。

5.2.3 非数值性质

不要在数组上定义或使用非数值属性(长度除外),使用map或者object来代替。

5.2.4 析构

可以在赋值的左侧使用数组文字来执行析构(例如从单个数组或iterable中解包多个值时)。可以包含最后一个rest元素(在…之间没有空格)和变量名)。如果元素是不使用的,就应该忽略它们。

const [a, b, c, ...rest] = generateResults();
let [, b,, d] = someArray;

也可以对函数参数使用析构(注意,需要一个参数名,但是忽略了它)。如果析构数组参数是可选的,则始终指定[]为默认值,并在左侧提供默认值:

/** @param {!Array<number>=} param1 */
function optionalDestructuring([a = 4, b = 2] = []) { … };

不允许:

function badDestructuring([a, b] = [4, 2]) { … };

提示:对于将多个值打包或者解包到函数的参数或返回中,尽可能选择对象析构而不是数组析构,因为它允许命名单个元素并为每个元素指定不同的类型。

5.2.5 传播算子(Spread operator)

数组文法中可以包含传播算子操作符(…),以将一个或者多个其它迭代的元素压平。应该使用扩展操作符,而不是更为笨拙的Array.prototype。在(…)后面没有空格。

示例:

[...foo]   // preferred over Array.prototype.slice.call(foo)
[...foo, ...bar]   // preferred over foo.concat(bar)

5.3 对象文法

5.3.1 使用拖拽逗号

当在final属性和右大括弧之间有换行符时,在后面加上逗号。

5.3.2 不要使用Object的构造函数

虽然Object不具有和Array一样的问题,但是为了保持一致性,仍然不允许使用Object的构造函数。使用文法({} or {a: 0, b: 1, c: 2}) 进行代替。

5.3.3 不要混合使用含引号和不含引号的关键字

Object文法既可以表示结构(里面的关键字不含引号),也可以表示字典(里面的关键字含引号)。但是不要在一个Object里面混合使用这两种关键字。

不允许:

{
  width: 42, // struct-style unquoted key
  'maxWidth': 43, // dict-style quoted key
}

这种规定也扩展到将属性名传递给函数,比如hasOwnProperty。特别是,这样做会破坏编译后的代码,因为编译器无法重命名/混淆字符串文字。

不允许:

/** @type {{width: number, maxWidth: (number|undefined)}} */
const o = {width: 42};
if (o.hasOwnProperty('maxWidth')) {
  ...
}

上述方式最好被实现如下:

/** @type {{width: number, maxWidth: (number|undefined)}} */
const o = {width: 42};
if (o.maxWidth != null) {
  ...
}
5.3.4 计算属性名

允许计算属性名(例如,{[‘key’ + foo(): 42}): 42}),它们被认为是字典样式(引用)的键(例如除非计算的属性是一个符号(例如,[symbol .iterator])。枚举值也可以用于计算的键,但不应与非枚举键在同一文本中混合使用。

5.3.5 方法速记

可以使用方法简写({method(){…}})在对象文字上定义方法,以代替紧跟在函数或箭头函数文字后面的冒号。

例子:

return {
  stuff: 'candy',
  method() {
    return this.stuff;  // Returns 'candy'
  },
};

请注意,在方法简写或函数中,this指的是对象文字本身,而在箭头函数中,this指的是对象文字之外的范围。

例子:

class {
  getObjectLiteral() {
    this.stuff = 'fruit';
    return {
      stuff: 'candy',
      method: () => this.stuff,  // Returns 'fruit'
    };
  }
}
5.3.6 简写属性

在Object文法中,允许简写属性。

示例:

const foo = 1;
const bar = 2;
const obj = {
  foo,
  bar,
  method() { return this.foo + this.bar; },
};
assertEquals(3, obj.method());
5.3.7 析构

对象析构模式可用于赋值的左侧,以执行析构并从单个对象解包多个值。

被析构的对象也可以用作函数参数,但是应该尽可能地保持简单:一个单级的未引用的简写属性。更深层次的嵌套和计算属性不能用于参数析构。在析构参数的左边指定任何默认值({str = ‘some default’} ={},而不是{str} = {str: ‘some default’}),如果析构对象本身是可选的,那么它必须默认为{}。析构参数的JSDoc可以被赋予任何名称(名称是未使用的,但是编译器需要它)。

例子:

/**
 * @param {string} ordinary
 * @param {{num: (number|undefined), str: (string|undefined)}=} param1
 *     num: The number of times to do something.
 *     str: A string to do stuff to.
 */
function destructured(ordinary, {num, str = 'some default'} = {})

禁止:

/** @param {{x: {num: (number|undefined), str: (string|undefined)}}} param1 */
function nestedTooDeeply({x: {num, str}}) {};
/** @param {{num: (number|undefined), str: (string|undefined)}=} param1 */
function nonShorthandProperty({num: a, str: b} = {}) {};
/** @param {{a: number, b: number}} param1 */
function computedKey({a, b, [a + b]: c}) {};
/** @param {{a: number, b: string}=} param1 */
function nontrivialDefault({a, b} = {a: 2, b: 4}) {};

析构也可以用于goog.require语句,在这种情况下不能被包装:整个语句占用一行,不管它有多长(见3.6 goog.require和goog.requireType语句)。

5.3.8 枚举

枚举是通过向对象文字添加@enum注释来定义的。在enum定义之后,不能将其他属性添加到它。枚举必须是常量,并且所有枚举值必须是深度不可变的。

/**
 * Supported temperature scales.
 * @enum {string}
 */
const TemperatureScale = {
  CELSIUS: 'celsius',
  FAHRENHEIT: 'fahrenheit',
};

/**
 * An enum with two options.
 * @enum {number}
 */
const Option = {
  /** The option used shall have been the first. */
  FIRST_OPTION: 1,
  /** The second among two options. */
  SECOND_OPTION: 2,
};

5.4 类

5.4.1 构造函数

构造函数是可选的。在设置任何字段或以其它方式访问它之前,子类构造函数必须调用super()。接口应该在构造函数中声明非方法属性。

5.4.2 域

在构造函数中设置一个具体对象的所有字段(即除了方法之外的所有属性)。从不使用@const重新分配的字段(这些字段不需要是深度不可变的)。使用适当的可见性注释(@private、@protected、@package)注释非公共字段,并以下划线结束所有@private字段的名称。字段从不设置在具体类的原型上。

例子:

class Foo {
  constructor() {
    /** @private @const {!Bar} */
    this.bar_ = computeBar();

    /** @protected @const {!Baz} */
    this.baz = computeBaz();
  }
}

提示:在构造函数完成后,不应该向实例中添加或从实例中删除属性,因为这极大地阻碍了VMs的优化能力。如果有必要,以后初始化的字段应该在构造函数中显式地设置为undefined,以防止以后的形状更改。向对象添加@struct将检查未声明的属性是否被添加/访问。默认情况下,类会添加这个。

5.4.3 计算属性

计算属性只能在属性为符号的类中使用。不允许使用字典样式的属性(即引用或计算的非符号键,如5.3.3 不要混合使用被应用和不被应用的关键字中所定义的,不要混合引用和非引用键)。一个[Symbol.iterator]方法应该在任何逻辑上可迭代的类中被定义。除此之外,Symbol应该被谨慎使用。

提示:小心使用任何其他内置的符号(例如,Symbol.isConcatSpreadable),因为编译器不会填充它们,因此在旧的浏览器中不能工作。

5.4.4 静态方法

在不影响可读性的情况下,最好使用模块本地函数而不是私有静态方法。

静态方法应该只在基类本身上调用。静态方法不应该在包含动态实例的变量上调用,动态实例可以是构造函数,也可以是子类的构造函数(如果这样做了,必须用@nocollapse来定义),而且不能直接在没有定义方法本身的子类上调用。

不允许:

class Base { /** @nocollapse */ static foo() {} }
class Sub extends Base {}
function callFoo(cls) { cls.foo(); }  // discouraged: don't call static methods dynamically
Sub.foo();  // Disallowed: don't call static methods on subclasses that don't define it themselves
5.4.5 老式的类声明

虽然ES6类是首选的,但是在某些情况下,ES6类可能是不可行的,例如:

  1. 如果存在或将存在子类,包括创建子类的框架,则不能立即更改为使用ES6类的语法。如果这样一个类要使用ES6语法,则需要修改所有不使用ES6类语法的下游子类。
  2. 框架在调用超类构造函数之前需要一个已知的this值,因为具有ES6超类的构造函数在调用超类返回之前不能访问this值的实例。

在所有其它方面,样式指南仍然适用于这段代码:let,const,默认参数,rest,以及箭头函数等都应该在适当的时候使用。

goog.defineClass允许类似于ES6类语法的类定义:

let C = goog.defineClass(S, {
  /**
   * @param {string} value
   */
  constructor(value) {
    S.call(this, 2);
    /** @const */
    this.prop = value;
  },

  /**
   * @param {string} param
   * @return {number}
   */
  method(param) {
    return 0;
  },
});

另外,虽然所有新代码都应该首选goog.defineClass,但也允许使用更传统的语法。

/**
  * @constructor @extends {S}
  * @param {string} value
  */
function C(value) {
  S.call(this, 2);
  /** @const */
  this.prop = value;
}
goog.inherits(C, S);

/**
 * @param {string} param
 * @return {number}
 */
C.prototype.method = function(param) {
  return 0;
};

如果有超类的话,每个实例的属性应该在调用超类构造函数后在构造函数中定义。方法应该在构造函数的原型上定义。

正确定义构造函数原型层次结构比它第一次出现时更困难!因此,最好从the Closure Library 中使用goog.inherits。

5.4.6 不要直接操作原型

class关键字允许比定义prototype属性更清晰、更可读的类定义。普通的实现代码没有操作这些对象的业务,尽管它们对于5.4.5 老式的类声明定义的类仍然很有用。混合和修改内建对象的原型是被明确禁止的。

例外:框架代码(如聚合体或Angular)可能需要使用原型,而不应该使用更糟糕的变通方法来避免这样做。

5.4.7 Getters和Setters

不要使用JavaScript getter and setter properties。它们可能会让人感到惊讶,并且很难进行推理,而且在编译器中对它们的支持也很有限。相反,提供普通的方法即可。

例外:在某些情况下,定义getter或setter是不可避免的(例如,Angular和Polymer等数据绑定框架,或者为了与无法调整的外部api兼容)。仅在这些情况下,如果使用get和set简写方法关键字或Object.defineProperties(而不是Object.defineProperty,它会干扰属性的重命名)来定义getter和setter,则可以谨慎地使用它们。getter不能改变可观察状态。

不允许:

class Foo {
  get next() { return this.nextId++; }
}
5.4.8 toString的重载

toString方法可能被覆盖,但是必须始终成功,并且不会有可见的副作用。

提示:特别要注意从toString调用其它方法,因为异常条件可能导致无限循环。

5.4.9 接口

接口可以用@interface或@record声明。使用@record声明的接口可以是显式的(即通过@implements),也可以是由类或对象文字隐式实现的。

接口上的所有非静态方法体必须是空块。字段必须在类构造函数中声明为未初始化的成员。

例子:

/**
 * Something that can frobnicate.
 * @record
 */
class Frobnicator {
  constructor() {
    /** @type {number} The number of attempts before giving up. */
    this.attempts;
  }

  /**
   * Performs the frobnication according to the given strategy.
   * @param {!FrobnicationStrategy} strategy
   */
  frobnicate(strategy) {}
}
5.4.10 抽象类

在需要的时候可以使用抽象类。抽象类和方法必须被标识为@abstract。不要使用goog.abstractMethod。具体请参见abstract classes and methods。

5.5 函数

5.5.1 顶层函数

顶层函数可以直接在导出对象上定义,也可以在本地声明。有关导出的更多信息,请参见3.3.3 goog.module导出。

示例:

/** @param {string} str */
exports.processString = (str) => {
  // Process the string.
};
/** @param {string} str */
const processString = (str) => {
  // Process the string.
};

exports = {processString};
5.5.2 嵌套函数和闭包

函数可以包含嵌套的函数定义。如果给函数起一个名字很有用,那么应该把它分配给一个本地常量。

5.5.3 箭头函数

箭头函数提供了简洁的函数语法,并简化了嵌套函数中this的作用域。 优先选择箭头函数而不是function关键字,特别是对于嵌套函数(请参见5.3.5 方法速记)。

优先使用箭头函数,而不是其他this范围划分方法,例如f.bind(this),goog.bind(f,this)和const self = this。 箭头函数对于调用回调函数特别有用,因为在绑定传递所有参数时,允许显式指定要传递给回调的参数。

箭头的左侧包含零个或多个参数。 如果只有一个未分解的参数,则参数周围的括号是可选的。 使用括号时,可以指定内联参数类型(请参见7.8 方法和函数注释)。

提示:即使对于单参数箭头函数也始终使用括号可以避免添加参数但忘记添加括号可能导致可解析的代码不再按预期工作的情况。

箭头的右侧包含函数的主体。 默认情况下,主体为block语句(零个或多个由花括号包围的语句)。 如果发生以下情况之一,则主体也可能是隐式返回的单个表达式:程序逻辑要求返回值,或者void运算符位于单个函数或方法调用之前(使用void确保返回undefined的值,防止泄漏值并传达意图)。 如果单一表达形式提高了可读性(例如,对于简短表达或简单表达),则它是首选。

例子:

/**
 * Arrow functions can be documented just like normal functions.
 * @param {number} numParam A number to add.
 * @param {string} strParam Another number to add that happens to be a string.
 * @return {number} The sum of the two parameters.
 */
const moduleLocalFunc = (numParam, strParam) => numParam + Number(strParam);

// Uses the single expression syntax with `void` because the program logic does
// not require returning a value.
getValue((result) => void alert(`Got ${result}`));

class CallbackExample {
  constructor() {
    /** @private {number} */
    this.cachedValue_ = 0;

    // For inline callbacks, you can use inline typing for parameters.
    // Uses a block statement because the value of the single expression should
    // not be returned and the expression is not a single function call.
    getNullableValue((/** ?number */ result) => {
      this.cachedValue_ = result == null ? 0 : result;
    });
  }
}

禁止:

/**
 * A function with no params and no returned value.
 * This single expression body usage is illegal because the program logic does
 * not require returning a value and we're missing the `void` operator.
 */
const moduleLocalFunc = () => anotherFunction();
5.5.4 生成器(Generators)

生成器启用了许多有用的抽象,可以根据需要使用。

定义生成器函数时,请将*附加到function关键字(如果存在),并将其与函数名称隔开。 使用委派收益时,请在yield关键字上附加*。

例:

/** @return {!Iterator<number>} */
function* gen1() {
  yield 42;
}

/** @return {!Iterator<number>} */
const gen2 = function*() {
  yield* gen1();
}

class SomeClass {
  /** @return {!Iterator<number>} */
  * gen() {
    yield 42;
  }
}
5.5.5 参数和返回类型

函数参数和返回类型通常应使用JSDoc注释记录。 有关更多信息,请参见7.8 方法和函数注释。

5.5.5.1 默认参数

使用参数列表中的equals运算符可以允许使用可选参数。 可选参数必须在equals运算符的两侧都包含空格,其名称必须与必需参数完全相同(即,不以opt_开头),在其JSDoc类型中使用=后缀,紧随必需参数之后,并且不使用产生可观察侧的初始化程序效果。 具体功能的所有可选参数都必须具有默认值,即使该值未定义。 与具体功能相反,抽象和接口方法必须省略默认参数值。

例:

/**
 * @param {string} required This parameter is always needed.
 * @param {string=} optional This parameter can be omitted.
 * @param {!Node=} node Another optional parameter.
 */
function maybeDoSomething(required, optional = '', node = undefined) {}

/** @interface */
class MyInterface {
  /**
   * Interface and abstract methods must omit default parameter values.
   * @param {string=} optional
   */
  someMethod(optional) {}
}

谨慎使用默认参数。 当存在少数不具有自然顺序的可选参数时,建议使用分解(如5.3.7 析构中所述)来创建可读的API。

注意:与Python的默认参数不同,可以使用返回新的可变对象(例如{}或[])的初始化程序,因为每次使用默认值时都会对初始化程序进行评估,因此不会在单个对象之间共享调用。

提示:尽管可以将包括函数调用在内的任意表达式用作初始化程序,但应使其尽可能简单。 避免使用暴露了共享可变状态的初始化程序,因为这样很容易在函数调用之间引入意外耦合。

5.5.5.2 Rest参数

使用rest参数而不是访问参数。 其余参数在其JSDoc中以…前缀键入。 rest参数必须是列表中的最后一个参数。 …和参数名称之间没有空格。 不要将rest参数命名为var_args。 切勿命名局部变量或参数参数,否则会混淆内置名称。

例:

/**
 * @param {!Array<string>} array This is an ordinary parameter.
 * @param {...number} numbers The remainder of arguments are all numbers.
 */
function variadic(array, ...numbers) {}
5.5.6 泛化

必要时,在函数或方法定义上方的JSDoc中使用@template TYPE声明通用函数和方法。

5.5.7 Spread操作

函数调用可以使用Spread运算符(…)。 当数组或可迭代程序解压缩为可变参数的多个参数时,请优先使用Spread运算符而不是Function.prototype.apply。 …之后没有空格。

例:

function myFunction(...elements) {}
myFunction(...array, ...iterable, ...generator());

5.6 String文法

5.6.1 使用单引号

普通字符串文字用单引号(’)而不是双引号(“)分隔。

提示:如果字符串包含单引号字符,请考虑使用模板字符串,以避免不得不对引号进行转义。

普通字符串文字不能跨越多行。

5.6.2 模板文法(Template literals)

在复杂的字符串连接上使用模板文字(以`分隔),尤其是在涉及多个字符串文字的情况下。 模板文字可能跨越多行。

如果模板文字跨越多行,则不需要遵循封闭块的缩进,尽管添加的空格可能无关紧要。

例:

function arithmetic(a, b) {
  return `Here is a table of arithmetic operations:
${a} + ${b} = ${a + b}
${a} - ${b} = ${a - b}
${a} * ${b} = ${a * b}
${a} / ${b} = ${a / b}`;
}
5.6.3 无连续行

请勿在普通或模板字符串文字中使用换行符(即,在字符串文字中的行以反斜杠结束)。 即使ES5允许这样做,但如果在斜杠后出现任何尾随空格,则可能会导致棘手的错误,并且对读者而言不太明显。

不允许:

const longString = 'This is a very long string that far exceeds the 80 \
    column limit. It unfortunately contains long stretches of spaces due \
    to how the continued lines are indented.';

相反,请使用:

const longString = 'This is a very long string that far exceeds the 80 ' +
    'column limit. It does not contain long stretches of spaces since ' +
    'the concatenated strings are cleaner.';

5.7 数字文法

数字可以用十进制,十六进制,八进制或二进制指定。 对于十六进制,八进制和二进制,分别使用0x,0o和0b的前缀(带有小写字母)。 除非前面紧跟着x,o或b,否则切勿包含前导零。

5.8 控制结构

5.8.1 For循环

使用ES6,该语言现在具有三种不同的for循环。 可以使用所有方法,尽管在可能的情况下应首选for-of循环。

for-in循环仅可用于dict样式的对象(请参见5.3.3 不要混合使用被应用和不被应用的关键字),并且不应将其用于遍历数组。

应该在for-in循环中使用Object.prototype.hasOwnProperty来排除不需要的原型属性。 尽可能使用for-of和Object.keys。

5.8.2 异常

异常是语言的重要组成部分,每当出现例外情况时都应使用异常。 始终抛出错误或Error的子类:永远不要抛出字符串文字或其他对象。 构造错误时,请始终使用new。

这种处理扩展到Promise拒绝值,因为在异步功能中Promise.reject(obj)等效于throw obj。

自定义异常提供了一种从功能传达其他错误信息的好方法。 应该在本机错误类型不足的地方定义和使用它们。

优先于临时错误处理方法(例如,传递错误容器引用类型或返回具有error属性的对象),而不是引发异常。

5.8.2.1 空catch块

响应捕获到的异常,什么也不做是非常正确的。 当确实在catch块中不执行任何操作时,在注释中解释这样做的合理原因。

try {
  return handleNumericResponse(response);
} catch (ok) {
  // it's not numeric; that's fine, just continue
}
return handleTextResponse(response);

不允许:

  try {
    shouldFail();
    fail('expected an error');
  } catch (expected) {
  }

提示:与其他语言不同,上述模式根本无法使用,因为这会捕获失败引发错误。 使用assertThrows()代替。

5.8.3 Switch语句

术语注:在一个开关块的括号内是一个或多个语句组。 每个语句组由一个或多个开关标签(大小写为FOO:或default:)组成,后跟一个或多个语句。

5.8.3.1 掉落特性:已注解

在switch块内,每个语句组要么突然终止(带有break,return或thrown异常),要么用注释标记,以指示执行将继续执行或可能继续执行下一个语句组。 任何传达掉落想法的评论都是足够的(通常// fall through)。 在switch块的最后一个语句组中不需要此特殊注释。

例:

switch (input) {
  case 1:
  case 2:
    prepareOneOrTwo();
  // fall through
  case 3:
    handleOneTwoOrThree();
    break;
  default:
    handleLargeNumber(input);
}
5.8.3.2 应包含default分支

每个switch语句包括一个默认语句组,即使它不包含任何代码。 默认语句组必须是最后一个。

5.9 this

仅在类构造函数中,以及方法中定义的箭头函数内,或在立即封闭的函数的JSDoc中声明了显式@this的函数中使用this。

永远不要使用this来引用全局对象,评估上下文,事件的目标或不必要的call()ed或apply()函数。

5.10 Equality检查

除下面列举的情况外,请使用标识运算符(=== / !==)。

5.10.1 需要强制的异常

捕获null和undefined的值:

if (someObjectOrPrimitive == null) {
  // Checking for null catches both null and undefined for objects and
  // primitives, but does not catch other falsy values like 0 or the empty
  // string.
}

5.11 禁止的特性

5.11.1 with

不要使用with关键字。 自ES5起,它使您的代码更难以理解,并且在strict模式下被禁止。

5.11.2 动态代码评估

不要使用eval或Function(… string)构造函数(代码加载器除外)。 这些功能具有潜在的危险,根本无法在CSP环境中使用。

5.11.3 自动分号插入

始终以分号终止语句(如上所述,函数和类声明除外)。

5.11.4 非标准功能

不要使用非标准功能。 这包括已删除的旧功能(例如,WeakMap.clear),尚未标准化的新功能(例如,当前的TC39工作草案,任何阶段的提案或已提议但尚未完成的Web标准),或仅在某些浏览器中实现的专有功能。 仅使用当前ECMA-262或WHATWG标准中定义的功能。 (请注意,针对特定API(例如Chrome扩展程序或Node.js)编写的项目显然可以使用这些API)。 禁止使用非标准语言的“扩展名”(例如某些外部编译器提供的扩展名)。

5.11.5 原始类型的包装器

切勿在原始对象包装器(Boolean,Number,String和Symbol)上使用new,也不要在类型注释中包含它们。

禁止:

const /** Boolean */ x = new Boolean(false);
if (x) alert(typeof x);  // alerts 'object' - WAT?

包装器可以被称为用于强制(比使用+或连接空字符串更可取)或创建符号的函数。

示例:

const /** boolean */ x = Boolean(0);
if (!x) alert(typeof x);  // alerts 'boolean', as expected
5.11.6 修改builtin对象

切勿通过向其构造函数或其原型添加方法来修改内置类型。 避免依赖执行此操作的库。 请注意,JSCompiler的运行时库将在可能的情况下提供符合标准的polyfill; 没有别的办法可以修改内置对象。

除非绝对必要(例如第三方API要求),否则请勿在全局对象中添加符号。

5.11.7 调用构造函数时忽略括弧()

在不使用括弧()的情况下,切勿在新语句中调用构造函数。

不允许:

new Foo;

相反,请使用:

new Foo();

省略括号会导致细微的错误。 这两行不相等:

new Foo().Bar();
new Foo.Bar();
Vercel部署个人博客 先去注册一个账号,建议注册一个Github账号后,使用Github账号来登录Vercel。vercel 部署静态资源网站极其方便简单,并且有可观的访问速度,最主要的是免费部署。此时项目已经成功搭建完毕了,点击图片即可跳转到 vercel 所提供的二级域名访问。然后可以直接拉取我的仓库,所有已经配置好了,可以直接使用,建议fork成自己的!然后修改dns就行,注意vercel提供的域名可能访问不了,需要自己绑定!如果有自己的域名,还可以在 vercel 中进行设置。进入Vercel官网。 阅读详情

相关推荐

C#.NET斗地主服务端核心架构与高性能实现

斗地主作为典型的实时对战棋牌逻辑,本质是状态驱动的分布式协同问题。其技术内核涵盖有限状态机建模、低延迟网络同步、无GC内存操作与轻量级AI决策等关键能力。在.NET平台下,借助Span<T>、ImmutableArray、命令/事件总线与内存池等特性,可构建出高吞吐(200+ QPS)、低延迟(<150ms)、强一致的可落地服务端。本文聚焦C#.NET生态中斗地主核心模块的设计取舍与压测验证,深入解析状态机驱动、CardSet结构体优化、Kestrel中间件锁、规则+概率混合AI等实战方案,为实时对战类业务

weixin_29726381的博客 345

goog.provide & Google Closure

问:Goog.provide和Goog.require有什么区别? 答:goog.provide创建一个名称空间; goog.require从给定的名称空间中“导入”代码,以便闭包编译器可以找到它。 通常,在创建类时,将为其提供一个名称空间,并需要您的类直接使用的所有名称空间。 goog.provide 规则1 goog.provide 语句放在前面,goog.require 放后面,两者用一行空行分隔。 所有引用按字母排序。 两种引用都不换行,即使超过列宽 80 的限制。 只提供顶级 symbol。

Antrn 2073

RC滤波电路工作原理:【带图+公式计算】

容抗Xc和电容C成反比,和频率f也成反比,C越大,交流电容易通过电容,说明电容量大,电容的阻碍作用小;交流电的频率高,交流电也容易通过电容,说明频率高,电容的阻碍作用也小。我们可以看到,一个2V的纹波,经常RC电路后,幅值下降到mv级别,基本可以忽略不计,这就是RC滤波电路的工作原理。一个频率为1Khz的信号,通过一个容值为0.1uf的电容,计算电容对该信号产生的阻抗。将RC滤波器电路中的电阻,取值为1KΩ,电容取值为0.47uf,纹波幅值为2V。从公式1可以看到,Xc越大,Vout值就越接近Vin的值。

weixin_66299220的博客 2万+

Closure教程一: Closure库简述

Closure教程一: Closure库简述Closure库包含了从UI组件到通信工具的许多丰富多彩的工具。Closure库的各个模块提供了许多相关的约定使得代码更容易组织和使用。 本篇文章将为你简单地介绍Closure代码库的核心规则。读完本篇文章您将对如何使用Closure库有初步的了解。 1.命名空间Closure库的方法和属性所属命名空间采用点分法的命名方式,以便防止和

不能没有你 5852

自然二进制数与格雷码的相互转换

自然二进制数与格雷码两者优势: 自然二进制数的编码方式简单明了,容易理解,在加减运算中能够直接进行,同时十分方便进行一些位运算操作(如移位、取反等)。 格雷码计数时只有一位变化,可有效减少计数器状态的冗余转换,同时在传输数据时能够减小传输错误的概率,此外带权重编码处理更加方便。 在一定程度上自然二进制数与格雷码优缺点基本相反,综上所述,自然二进制数和格雷码各有优劣之处,需要根据具体应用场景选择合适的编码方式。简单来说,在计数器和编码器中,倾向于使用格雷码;而在进行加减运算时,则倾向于使用自然二进制数。

Loudrs的博客 7494

WebVTT中的文本轨道(Text Tracks,TT)到底是什么鬼?

WebVTT,全称是The Web Video Text Tracks Format,意思是网络视频文本轨道格式。那么到底什么是文本轨道(Text Tracks)呢?这篇文章希望一探究竟。

码农1479的博客 1987

Google JavaScript样式指南

Google JavaScript样式指南 目录 1简介1.1术语说明1.2指南说明2源文件基础知识2.1文件名2.2文件编码:UTF-82.3特殊字符3源文件结构3.1许可或版权信息(如果有)3.2 @fileoverview JSDoc,如果存在的话3.3 goog.module语句3.4 goog.require语句3.5文件的实现4格式化4.1大括号4.2块缩进:...

weixin_30528371的博客 356

Kile5报错—> ARM-Compiler ‘Default Compiler Version 5‘ which is not available安装使用Compiler Version 5 的办法

Kile5报错—> ARM-Compiler ‘Default Compiler Version 5‘ which is not available安装使用Compiler Version 5 的办法

weixin_72050316的博客 1188

Google Closure Library 入门指南:从零开始构建你的第一个应用

还在为 JavaScript 代码的模块化、依赖管理和类型安全而烦恼吗?Google Closure Library 提供了一个完整的解决方案,它不仅是一个功能丰富的 JavaScript 库,更是一个完整的开发工具链。通过本文,你将学会: - ✅ 快速搭建 Closure Library 开发环境 - ✅ 理解模块系统和依赖管理机制 - ✅ 使用强大的 DOM 操作和事件处理功能 - ✅ 构建...

gitblog_00830的博客 441

excel 如何自动调整行间距 vba

EXCEL是一个非常使用的软件,虽然我们平时仅使用他做一些报表,仅此而已;我在工作中,由于很懒,不愿意做考试重复的工作,就想着使用vba的宏来完成重复的工作,这样就能省出一部分的时间来了。本人不喜欢在博客里面写以下教程类的东西,我的理念是将工作中的痛点的解决办法分享出来,以解决问题为主。

sixtome 1316

SAP-ABAP:FI财务会计模块常用BAPI及核心用途实例说明

SAP FI模块的BAPI覆盖了从主数据管理、凭证过账到财务关账的全流程操作,是系统集成与自动化的重要工具。实际应用中需结合业务场景选择合适的BAPI,并严格遵循事务控制与校验规则。如需扩展功能,可通过BAdI或用户出口增强标准逻辑。

baidu_35680696的博客 1601

JavaScript 静态方法

静态方法不能在对象上调用,只能在类中调用

qq_68609773的博客 1526

数字电视中的 Closed Caption (CC) 字幕标准协议

本文将详细介绍 DVB中的 CC 字幕标准协议,包括数据结构格式、字段定义、字段占用比特数以及字段用途。此外,本文还将举例说明如何从 TS 传输流中解析 CC 字幕信息,并组织打包到电视节目中进行显示。

以实战经验介绍行业知识 670

[Javascript] 编程实践之1: Google的Javascript代码风格8:一些策略

Google的Javascript风格指南8 一些策略8.1 Google样式指南未明确指出的问题:请保持一致性!8.2 编译器警告8.2.1 使用标准警告集8.2.2 如何处理警告8.2.3 在最窄的合理范围内禁止警告8.3 弃用8.4 代码不是Google风格8.4.1 重新格式化已有代码8.4.2 新加入的代码:请遵照Google风格8.5 本地风格规则8.6 生成的代码:大部分豁免 8 一些策略 8.1 Google样式指南未明确指出的问题:请保持一致性! 对于本规范未明确解决的任何样式问题,请优先

魔豆(Magicbean)的博客 326

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

Google 编程风格:C++、Python、JavaScript、Shell、TypeScript

Google 编程风格:C++、Python、JavaScript、Shell、TypeScript

freeking101的博客 5万+

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

[Javascript] 编程实践之1: Google的Javascript代码风格9:附件

Google的Javascript风格指南9 附件9.1 JSDoc标签参考9.1.1 类型注释和其他Closure Compiler注释9.1.2 文档注释9.1.2.1 @author 或者 @owner - 不推荐9.1.2.2 @bug9.1.2.3 @code -弃用, 不推荐使用9.1.2.4 @desc9.1.2.5 @link9.1.2.6 @see9.1.2.7 @supported9.1.3 适用于特定框架的注释9.1.3.1 @ngInject 特定于Angular 19.1.3.2

魔豆(Magicbean)的博客 605

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

[Javascript] 编程实践之1: Google的Javascript代码风格4:格式化

Google的Javascript风格指南4 格式化4.1 大括弧4.1.1 在所有的控制结构中都使用大括弧4.1.2 非空块的K&R风格4.1.3 空块:可能更精炼4.2 块缩进:+2个空格4.2.1 数组文法:可类似于块4.2.2 对象文法:可类似于块4.2.3 类文法4.2.4 函数表达式4.2.5 Switch语句4.3 语句4.3.1 每行一条语句4.3.2 分号是必须的4.4 列数限制:804.5 换行4.5.1 在哪里做行中断4.5.2 缩进连续线至少+4个空格4.6 空格4.6.1

魔豆(Magicbean)的博客 647

[Javascript] 编程实践之1: Google的Javascript代码风格7:JSDoc

Google的Javascript风格指南7 JSDoc7.1 通用形式7.2 Markdown7.3 JSDoc标签7.4 换行7.5 顶级/文件级注释7.6 类注释7.7 Enum和typedef注释7.8 方法和函数注释7.9 属性注释7.10 Type注释7.10.1 可空性7.10.2 类型转换7.10.3 模板参数类型7.10.4 函数类型表达式7.10.5 空格7.11 可见性注释 7 JSDoc JSDoc在所有类、域以及方法中被使用。 7.1 通用形式 在此示例中可以看到JSDoc块的基本

魔豆(Magicbean)的博客 1041

[Javascript] 编程实践之1: Google的Javascript代码风格3:源文件结构

Google的Javascript风格指南3 源文件结构3.1 许可证或者版权信息(如果有)3.2 @fileoverview JSDoc (如果有)3.3 goog.module语句3.3.1 层次结构3.3.2 goog.module.declareLegacyNamespace3.3.3 goog.module导出3.4 ES模块3.4.1 导入3.4.1.1 导入路径3.4.1.1.1 在路径导入中的文件名扩展3.4.1.2 多次导入同一文件3.4.1.3 名称导入3.4.1.3.1 名称模块导入3

魔豆(Magicbean)的博客 779

[Javascript] 编程实践之1: Google的Javascript代码风格6:命名规范

Google的Javascript风格指南6 命名规范6.1 所有标识符的通用规则6.2 标识符类型规则6.2.1 Package命名6.2.2 Class命名6.2.3 Method命名6.2.4 Enum命名6.2.5 Constant命名6.2.5.1 “constant”的定义6.2.5.2 本地别名6.2.6 非常量域名称6.2.7 参数名称6.2.8 局部变量名称6.2.9 模板参数名称6.2.10 模块局部名称6.3 驼峰案例:定义 6 命名规范 6.1 所有标识符的通用规则 标识符仅使用AS

魔豆(Magicbean)的博客 697

还在纠结JS代码风格? Google给你你答案了!

Google JavaScript 代码风格指南Google 和 Airbnb 是目前最流行的 JavaScript 代码风格,如果你长期使用 JavaScript 来写...

全栈空间 658

[TypeScript] 编程实践之1: Google的TypeScript代码风格1:介绍

TypeScript语言规范1 介绍1.1 环境声明1.2 函数类型1.3 对象类型1.4 结构子类型化1.5 上下文类型推断1.6 类1.7 枚举类型1.8 字符串参数重载1.9 通用类型和功能1.10 命名空间1.11 模块 版本1.8 2016年1月 Microsoft自2012年10月1日起根据Open Web Foundation最终规范协议版本1.0(“ OWF 1.0”)提供此规范。OWF 1.0可以从http://www.openwebfoundation.org/legal/the-owf

魔豆(Magicbean)的博客 1398

[TypeScript] 编程实践之1: Google的TypeScript代码风格5:语句

TypeScript语言规范5 语句5.1 块5.2 变量语句5.2.1 简单变量声明5.2.2 析构变量声明5.2.3 implied类型5.3 let和const声明5.4 If,Do和While语句5.5 for语句5.6 for-in语句5.7 For-of语句5.8 Continue语句5.9 Break语句5.10 Return语句5.11 With语句5.12 Switch语句5.13 Throw语句5.14 Try语句 5 语句 本章介绍TypeScript为JavaScript语句提供的静

魔豆(Magicbean)的博客 1371

x-cmd pkg | go - Google 开发的开源编程语言

Go 语言(或 Golang)是 Google 开发的开源编程语言,诞生于 2006 年。其设计目标是“兼具 Python 等动态语言的开发速度和 C/C++ 等编译型语言的性能与安全性”。语法接近 C 语言,但对于变量的声明有所不同。支持垃圾回收功能。原生支持并发:在多核并发上拥有原生的设计优势,无须第三方库、开发者的编程技巧和开发经验。代码风格统一:代码的格式化不再是开发者的个人喜好,而是一种强制性的规范。其有统一的一套格式化工具go fmt,保证了不同开发者编写的代码风格统一。

edwinjhlee的博客 1912

Kotlin的语言特性及使用场景

Kotlin 是由 JetBrains 开发的现代化编程语言,2017 年被 Google 官方宣布为。它相较于 Java 更简洁、安全、功能强大,同时兼容 Java 生态,因此得到了广泛应用。语言,支持高阶函数(HOF)和 Lambda 表达式,使代码更灵活。Kotlin 代码比 Java 更简洁,能够减少。,用于处理异步任务,避免回调地狱,提高并发性能。能力,可以减少代码冗余,提高开发效率。💡 Kotlin 适合现代化开发,,避免 Java 过度重载。Kotlin 原生支持。Kotlin 拥有强大的。

王景程的博客 2036

javascript代码_现代 JavaScript 教程 代码风格

点击上方“前端教程”,选择“星标”每天前端开发干货第一时间送达!来自:javascript.infohttps://zh.javascript.info/coding-style我们的代码必须尽可能的清晰和易读。这实际是一种编程艺术 —— 以一种正确并且人类易读的方式编码来完成一个复杂的任务。有一个帮助你(实现上面的目标)的事情就是良好的代码风格。语法一个含有规则的备忘录(更多细节如下)...

weixin_39634022的博客 132
上一篇: [Javascript] 编程实践之1: Google的Javascript代码风格4:格式化
下一篇: [Javascript] 编程实践之1: Google的Javascript代码风格6:命名规范
魔豆Magicbean
博客等级 码龄19年 146粉丝 742原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值