【知识总结】交了这么多年JavaScript学费,你掌握了多少(第一期)

吐槽君 分类:javascript

应该使用“ === ”和“!==”代替“ ==”和“!=”

==!=比较值之前,执行类型强制。这很糟糕,因为它可能掩盖类型错误。

例如,它的计算结果' \t\r\n' == 0返回为true

“ [type = ...]”应用于按类型选择元素

虽然:<element_type>[type="<element_type>"]都可以在jQuery中用于按元素类型选择元素,但[type="<element_type>"]速度要快得多,因为它可以利用querySelectorAll()现代浏览器中的本机DOM 方法。

使用以下选择器时,此规则会引起问题:

  • :checkbox
  • :file
  • :image
  • :password
  • :radio
  • :reset
  • :text

不兼容的代码示例:

var input = $(“ form input:radio”); //不符合规定
 

兼容解决方案:

var input = $(“ form input [type = radio]”); //符合
 

不推荐使用,该规则已弃用,最终将被删除。

不应使用“ alert(...)”

alert(...)以及confirm(...)prompt(...)可以在开发过程中调试非常有用,但在生产模式这种弹出的可能暴露敏感信息给攻击者,不应该被显示。

不兼容的代码示例:

if(unexpectedCondition){
  alert(“意外情况”);
}
 

"arguments" 不应直接访问

JavaScript的神奇之处在于,你可以将参数传递给未声明参数的函数,另一方面,也可以在no-args内使用这些传入的参数function。

如果你不想显式命名参数,请使用...语法指定期望可变数量的参数。然后在函数内部,你将要处理一类数组,而不是类似数组的结构。

不兼容的代码示例:

function concatenate() {
  let args = Array.prototype.slice.call(arguments);  // Noncompliant
  return args.join(', ');
}

function doSomething(isTrue) {
  var args = Array.prototype.slice.call(arguments, 1); // Noncompliant
  if (!isTrue) {
    for (var arg of args) {
      ...
    }
  }
 

兼容解决方案:

function concatenate(...args) {
  return args.join(', ');
}

function doSomething(isTrue, ...values) {
  if (!isTrue) {
    for (var value of values) {
      ...
    }
  }
}
 

不应使用“ arguments.caller”和“ arguments.callee”

arguments.callerarguments.callee做了不少优化,不可能让他们在JavaScript中的最新版本中不建议使用。实际上,strict根据文档,EcmaScript 5禁止在模式下同时使用两者:

严格模式功能的参数对象定义了名为“ caller”“ callee”的不可配置的访问器属性,这些属性在访问时引发TypeError异常

不兼容的代码示例:

function whoCalled() {
   if (arguments.caller == null)   //Noncompliant
      console.log('I was called from the global scope.');
   else
      console.log(arguments.caller + ' called me!');  // Noncompliant

  console.log(whoCalled.caller);  // Noncompliant
  console.log(whoCalled.arguments);  // Noncompliant
 

“ await”不应冗余使用

一个async函数总是包裹在一个返回值Promise,return await的使用是多余的。

不兼容的代码示例:

async function foo() {
  // ...
}

async function bar() {
  // ...
  return await foo(); // Noncompliant
}
 

兼容解决方案:

async function foo() {
  // ...
}

async function bar() {
  // ...
  return foo();
}
 

“ catch”子句的作用不仅仅在于重新抛出

一个catch子句只会重新抛出捕获到的异常,其效果与完全省略catch并让它自动弹出的效果相同,但会产生更多的代码,而且还会增加维护人员的工作量。

此类子句应被消除或使用适当的逻辑填充。

不兼容的代码示例:

try {
  doSomething();
} catch (ex) {  // Noncompliant
  throw ex;
}
 

兼容解决方案:

try {
  doSomething();
} catch (ex) {
  console.err(ex);
  throw ex;
}
 

不应使用“continue”

continue是非结构化的控制流语句。它使代码的可测试性,可读性和可维护性降低。if应该使用结构化的控制流语句,例如:

不兼容的代码示例:

  for (i = 0; i < 10; i++) {
    if (i == 5) {
      continue;  /* Noncompliant */
    }
    alert("i = " + i);
  }
 

兼容解决方案:

 for (i = 0; i < 10; i++) {
    if (i != 5) {  /* Compliant */
      alert("i = " + i);
    }
  }
 

“default”子句应写在最后

switch可以default出于各种原因而包含一个子句:处理意外值,以表明所有情况都经过适当考虑。

出于可读性考虑,为了帮助开发人员快速找到switch语句的默认行为,建议将default子句放在 语句的末尾switch。如果default子句不是的第一个或最后一个switch案例,则此规则会引起问题。

不兼容的代码示例:

switch (param) {
  case 0:
    doSomething();
    break;
  default: // default clause should be the first or last one
    error();
    break;
  case 1:
    doSomethingElse();
    break;
}
 

兼容解决方案:

switch (param) {
  case 0:
    doSomething();
    break;
  case 1:
    doSomethingElse();
    break;
  default:
    error();
    break;
}
 

“delete”应仅与对象属性一起使用

delete运算符的语义有些棘手,并且只能可靠地用于从对象中删除属性。将其他任何内容传递给它,你可能会或可能不会获得预期的结果。

不兼容的代码示例:

var x  = 1;
delete x;       // Noncompliant

function foo(){
..
}

delete foo;  // Noncompliant
 

兼容解决方案:

var obj = {
  x:1,
  foo: function(){
  ...
  }
};
delete obj.x;
delete obj.foo;
 

“delete”不应在数组上使用

delete可用于从任何对象中删除一个属性。数组是对象,因此delete也可以在此处使用运算符,但如果是,数组中将留下一个洞,因为索引/键不会移动以反映删除。

删除某个索引处的元素的正确方法是:

  • Array.prototype.splice -从数组中添加/删除元素
  • Array.prototype.pop -从数组末尾添加/删除元素
  • Array.prototype.shift -从数组的开头添加/删除元素

不兼容的代码示例:

var myArray = ['a', 'b', 'c', 'd'];

delete myArray[2];  // Noncompliant. myArray => ['a', 'b', undefined, 'd']
console.log(myArray[2]); // expected value was 'd' but output is undefined
 

兼容解决方案:

var myArray = ['a', 'b', 'c', 'd'];

// removes 1 element from index 2
removed = myArray.splice(2, 1);  // myArray => ['a', 'b', 'd']
console.log(myArray[2]); // outputs 'd'
 

“ for ... in”循环应先对属性进行过滤,然后再对其进行操作

for...in语句使你可以遍历对象的所有属性的名称。属性列表包括通过原型链继承的所有那些属性。当对数据属性感兴趣时,这具有提供功能的副作用。不考虑这一点的程序可能会失败。

因此,每个for...in语句的主体都应该包含在一个if过滤器中,该过滤器将作用于哪些属性。它可以选择特定类型或值范围,也可以排除函数,也可以排除原型中的属性。

不兼容的代码示例:

for (name in object) {
    doSomething(name);  // Noncompliant
}
 

兼容解决方案:

for (name in object) {
  if (object.hasOwnProperty(name)) {
    doSomething(name);
  }
}
 

“ indexOf”检查不应为正数

大多数针对indexOf字符串或数组的调用检查都会将其与-1比较,因为0是有效索引。任何寻找值> 0的检查都会忽略第一个元素,这很可能是一个错误。如果仅检查字符串的存在,请考虑includes改为使用 。在使用includes方法之前 ,请确保你的浏览器版本支持该方法。

不兼容的代码示例:

var color = "blue";
var name = "ishmael";
var number = 123;

var arr = [color, name];

if (arr.indexOf("blue") > 0) { // Noncompliant
  // ...
}
if (name.indexOf("ish") > 0) { // Noncompliant
  // ...
}
 

兼容解决方案:

var color = "blue";
var name = "ishmael";
var number = 123;

var arr = [color, name];

if (arr.indexOf("blue") >= 0) {
  // ...
}
if (name.includes("ish")) {
  // ...
}
 

比较中不应使用“ NaN”

NaN不等于任何东西,甚至不等于任何东西。针对进行相等性或不相等性测试NaN将产生可预测的结果,但可能不是您想要的结果。

相反,查看变量是否等于的最佳方法NaN是使用Number.isNaN()ES2015以来的,或者使用(也许是违反直觉的)将其与自身进行比较。从那时起
NaN ! == NaNa ! == a 你知道它必须相等NaN。

不兼容的代码示例:

var a = NaN;

if (a === NaN) {  // Noncompliant; always false
  console.log("a is not a number");  // this is dead code
}
if (a !== NaN) { // Noncompliant; always true
  console.log("a is not NaN"); // this statement is not necessarily true
}
 

兼容解决方案:

if (Number.isNaN(a)) {
  console.log("a is not a number");
}
if (!Number.isNaN(a)) {
  console.log("a is not NaN");
}
 

“strict”模式应谨慎使用

即使强制执行JavaScript严格模式可能是一个好习惯,但这样做可能会导致尚不支持JavaScript严格模式的浏览器出现意外行为。因此,应谨慎使用此功能,并充分了解不支持此功能的浏览器的潜在后果。

不兼容的代码示例:

function strict() {
  'use strict';
 

应该适当调用“ super()”

在某些情况下super()必须调用,而在某些情况下super()则不能调用。

基本规则是:非派生类中的构造函数无法调用super();派生类中的构造函数必须调用 super()。

此外:

  • super()必须先调用,然后才能使用this and super关键字。

  • super()必须使用与基类的构造函数相同数量的参数来调用。

  • super()只能在构造函数中调用-不能在任何其他方法中调用。

  • super()不能在同一构造函数中多次调用。

不兼容的代码示例:

class Dog extends Animal {
  constructor(name) {
    super();
    this.name = name;
    super();         // Noncompliant
    super.doSomething();
  }
}
 

兼容解决方案:

class Dog extends Animal {
  constructor(name) {
    super();
    this.name = name;
    super.doSomething();
  }
}
 

“ switch”语句不应嵌套

嵌套switch结构很难理解,因为你很容易将内部的情况混淆switch为属于外部的语句。因此,switch应避免使用嵌套语句。

具体来说,你应该对代码进行结构化,以避免需要嵌套switch语句,但是如果不能,则请考虑将内部结构switch移至另一个函数。

不兼容的代码示例:

function foo(n, m) {
  switch (n) {
    case 0:
      switch (m) {  // Noncompliant; nested switch
        // ...
      }
    case 1:
      // ...
    default:
      // ...
  }
}
 

兼容解决方案:

function foo(n, m) {
  switch (n) {
    case 0:
      bar(m);
    case 1:
      // ...
    default:
      // ...
  }
}

function bar(m) {
  switch(m) {
    // ...
  }
}
 

回复

我来回复
  • 暂无回复内容