一名【合格】前端工程师的自检清单 - 答案版(语法和API)

1,193 阅读9分钟

1. 理解ECMAScriptJavaScript的关系

ECMAScriptJavaScript的标准,JavaScriptECMAScript具体实现.

JavaScript包含3部分:

  • ECMAScript,由ECMA-262定义,提供核心语言功能;
  • 文档对象模型DOM,提供访问和操作网页内容的方法和接口;
  • 浏览器对象模型BOM,提供与浏览器交互的方法和接口;

有兴趣的可以看看阮一峰老师的《JavaScript语言的历史》.

2. 熟练运用es5es6提供的语法规范

ES5:

说起es6大家都很熟悉了,但是es5呢?

其实现在我们用的一些语法特性,有些都是es5的,到底有哪些呢?下面我会列举一些:

  1. 严格模式(use strict)

    关于严格模式的使用以及特点,就不多赘述了

  2. JSON对象

    JSON.stringify()JSON.parse()

  3. Object扩展

    Object.create(prototype, [descriptors])Object.defineProperties(object, descriptors)

  4. Array扩展

    • Array.prototype.indexOf(value): 得到值在数组中的第一个下标
    • Array.prototype.lastIndexOf(value) : 得到值在数组中的最后一个下标
    • Array.prototype.forEach(function(item, index){}) : 遍历数组
    • Array.prototype.map(function(item, index){}) : 遍历数组返回一个新的数组,返回加工之后的值
    • Array.prototype.filter(function(item, index){}): 遍历过滤出一个新的子数组, 返回条件为true的值
  5. Function扩展

    Function.prototype.bind(obj)

ES6:

推荐阮一峰老师的《ECMAScript6入门》

3. 熟练掌握JavaScript提供的全局对象(例如DateMath)、全局函数(例如decodeURIisNaN)、全局属性(例如Infinityundefined

全局的对象global objects )或称标准内置对象,不要和"全局对象(global object)"混淆。这里说的全局的对象是说在全局作用域里的对象。“全局对象 (global object)”可以在全局作用域里,通过this访问(但只有在 ECMAScript 5 的非严格模式下才可以,在严格模式下得到的是undefined)。实际上,全局作用域包含了全局对象的属性,还有它可能继承来的属性。

Date:

创建一个 JavaScript Date实例,该实例呈现时间中的某个时刻。Date对象则基于Unix Time Stamp,即自1970年1月1日(UTC)起经过的毫秒数。

  • 如果没有输入任何参数,则Date的构造器会依据系统设置的当前时间来创建一个Date对象。
  • 如果提供了至少两个参数,其余的参数均会默认设置为 1(如果没有指定 day 参数)或者 0(如果没有指定 day 以外的参数)。
  • JavaScript的时间由世界标准时间(UTC)1970年1月1日开始,用毫秒计时,一天由 86,400,000 毫秒组成。Date对象的范围是 -100,000,000 天至 100,000,000 天(等效的毫秒值)。
  • Date对象为跨平台提供了统一的行为。时间属性可以在不同的系统中表示相同的时刻,而如果使用了本地时间对象,则反映当地的时间。
  • Date对象支持多个处理 UTC 时间的方法,也相应地提供了应对当地时间的方法。UTC,也就是我们所说的格林威治时间,指的是time中的世界时间标准。而当地时间则是指执行JavaScript的客户端电脑所设置的时间。
  • 以一个函数的形式来调用Date对象(即不使用new操作符)会返回一个代表当前日期和时间的字符串。

Math:

Math是一个内置对象, 它具有数学常数和函数的属性和方法。不是一个函数对象。 Math 适用于Number类型。它不支持BigInt

与其他全局对象不同的是,Math不是一个构造器。Math的所有属性与方法都是静态的。引用圆周率的写法是Math.PI,调用正余弦函数的写法是Math.sin(x)x是要传入的参数。Math的常量是使用 JavaScript 中的全精度浮点数来浮点数来定义的。定义的。

decodeURI:

decodeURI()函数解码一个由encodeURI先前创建的统一资源标识符(URI)或类似的例程。

将已编码 URI 中所有能识别的转义序列转换成原字符,但不能解码那些不会被encodeURI编码的内容(例如 "#")。

isNaN:

isNaN()函数用来确定一个值是否为NaN。注:isNaN函数内包含一些非常有趣的规则;你也可以使用 ECMAScript 2015中定义的Number.isNaN()来判断。

  • isNaN函数的必要性

JavaScript 中其他的值不同,NaN不能通过相等操作符(=====)来判断 ,因为NaN == NaNNaN === NaN都会返回false。 因此,isNaN就很有必要了。

  • NaN值的产生

当算术运算返回一个未定义的或无法表示的值时,NaN就产生了。但是,NaN并不一定用于表示某些值超出表示范围的情况。将某些不能强制转换为数值的非数值转换为数值的时候,也会得到NaN

例如,0 除以0会返回NaN—— 但是其他数除以0则不会返回NaN

  • 令人费解的怪异行为

如果isNaN函数的参数不是Number类型,isNaN函数会首先尝试将这个参数转换为数值,然后才会对转换后的结果是否是NaN进行判断。因此,对于能被强制转换为有效的非NaN数值来说(空字符串和布尔值分别会被强制转换为数值01),返回false值也许会让人感觉莫名其妙。比如说,空字符串就明显“不是数值(not a number)”。

这种怪异行为起源于:"不是数值(not a number)"在基于IEEE-754数值的浮点计算体制中代表了一种特定的含义。isNaN函数其实等同于回答了这样一个问题:被测试的值在被强制转换成数值时会不会返回IEEE-754中所谓的“不是数值(not a number)”。

下一个版本的ECMAScript (ES2015)包含Number.isNaN()函数。通过Number.isNaN(x)来检测变量x是否是一个NaN将会是一种可靠的做法。然而,在缺少Number.isNaN函数的情况下, 通过表达式(x != x)来检测变量x是否是NaN会更加可靠。

一个isNaNpolyfill 可以理解为(这个polyfill利用了NaN自身永不相等于自身这一特征 ):

var isNaN = function(value) {
    var n = Number(value);
    return n !== n;
};


isNaN(NaN);       // true
isNaN(undefined); // true
isNaN({});        // true
isNaN(true);      // false
isNaN(null);      // false
isNaN(37);        // false
// strings
isNaN("37");      // false: 可以被转换成数值37
isNaN("37.37");   // false: 可以被转换成数值37.37
isNaN("37,5");    // true
isNaN('123ABC');  // true:  parseInt("123ABC")的结果是 123, 但是Number("123ABC")结果是 NaN
isNaN("");        // false: 空字符串被转换成0
isNaN(" ");       // false: 包含空格的字符串被转换成0
// dates
isNaN(new Date());                // false
isNaN(new Date().toString());     // true
isNaN("blabla")   // true: "blabla"不能转换成数值
                  // 转换成数值失败, 返回NaN

Infinity:

全局属性Infinity是一个数值,表示无穷大。

Infinity的属性特性
writable false
enumerable false
configurable false

Infinity是全局对象(global object)的一个属性,即它是一个全局变量。

Infinity的初始值是Number.POSITIVE_INFINITY

Infinity(正无穷大)大于任何值。该值和数学意义上的无穷大很像,例如任何正值乘以InfinityInfinity, 任何数值(除了Infinity-Infinity)除以Infinity0

ECMAScript 5 的规范中,Infinity是只读的(实现于 JavaScript 1.8.5 / Firefox 4)。

console.log(Infinity          ); /* Infinity */  
console.log(Infinity + 1      ); /* Infinity */  
console.log(Math.pow(10, 1000)); /* Infinity */  
console.log(Math.log(0)       ); /* -Infinity */  
console.log(1 / Infinity      ); /* 0 */

undefined:

全局属性undefined表示原始值undefined。它是一个JavaScript的原始数据类型。

undefine的属性特性
writable false
enumerable false
configurable false

undefined是全局对象的一个属性。也就是说,它是全局作用域的一个变量。

undefined的最初值就是原始数据类型undefined。

在现代浏览器(JavaScript 1.8.5/Firefox 4+),自ECMAscript5标准以来undefined是一个不能被配置(non-configurable),不能被重写(non-writable)的属性。

即便事实并非如此,也要避免去重写它。

一个没有被赋值的变量的类型是undefined。如果方法或者是语句中操作的变量没有被赋值,则会返回undefined(对于这句话持疑惑态度,请查看英文原文来理解)。

function test(a){
    console.log(typeof a);    // undefined
    return a;
}
test();                       // 返回"undefined"

有兴趣的同学可以看看MDN上的JavaScript 标准内置对象

4. 熟练应用mapreducefilter 等高阶函数解决问题

5. setInterval需要注意的点,使用setTimeout实现setInterval

  • 不能传递带参数的函数
setInterval(function(args){}, 600);
  • 如果需要传递参数,可以使用闭包返回一个函数,或者
var intervalID = window.setInterval(myCallback, 500, 'Parameter 1', 'Parameter 2');
function myCallback(a, b)
{
 // Your code here
 // Parameters are purely optional.
 console.log(a);
 console.log(b);
}
  • 需要使用clearInterval清除定时器,防止定时器一直执行下去,同时也需要手动释放内存
Var timer = null

If (timer) {
clealInterval(timer)
Timer = null
}
timer  = setInterval(callback, 500);
  • this指向问题

setInterval()调用的代码运行在与所在函数完全分离的执行环境上。这会导致,这些代码中包含的this关键字在非严格模式会指向window(或全局)对象,严格模式下为 undefined,这和所期望的this的值是不一样的。

使用setTimeout实现setInterval,大体思路就是使用递归不断地执行setTimeout

function mySetInterval(fn, millisec){
  function interval(){
    setTimeout(interval, millisec);
    fn();
  }
  setTimeout(interval, millisec)
}

6. JavaScript提供的正则表达式API、可以使用正则表达式(邮箱校验、URL解析、去重等)解决常见问题

5个常用方法:

  1. test
reg.test(str); // 返回是否包含正则 true/false

var str = "abcdefghijkl3mnop2qts";
/\d/.test(str); // true
  1. match
str.match(reg); // 一般正则表达式加g,会返回包含所有匹配项的数组

var str = "abcdefghijkl3mnop2qts";
str.match(/\d/g); // ["3", "2"]
  1. search
str.search(reg); // 返回第一条匹配的索引位置

var str = "abcdefghijkl3mnop2qts";
str.search(/\d/); // 12
  1. replace
str.replace(str/reg, replacement); // 不改变原字符串,返回新字符串
  1. exec

在循环中反复地调用 exec() 方法是唯一一种获得全局模式的完整模式匹配信息的方法。

7. JavaScript异常处理的方式,统一的异常处理方案

  • try...catch...finally 语句: try语句包含了由一个或者多个语句组成的try块,和至少一个catch子句或者一个finally子句的其中一个,或者两个兼有,下面是三种形式的try声明:
  1. try...catch
  2. try...finally
  3. try...catch...finally
  • throw语句:

用来抛出一个用户自定义的异常。当前函数的执行将被停止(throw之后的语句将不会执行),并且控制将被传递到调用堆栈中的第一个catch块。如果调用者函数中没有catch块,程序将会终止。

function getRectArea(width, height) {
  if (isNaN(width) || isNaN(height)) {
    throw "Parameter is not a number!";
  }
}

try {
  getRectArea(3, 'A');
}
catch(e) {
  console.error(e);
  // expected output: "Parameter is not a number!"
}
  • window.onerror

感兴趣的同学可以点这里.