1.let、const、var区别
let: 声明变量,不存在变量提升(必须先声明,再使用)。具有暂时性死区(在代码块内,使用let命令声明变量之前,该变量都是不可用的),声明的变量仅在块级作用域内有效(在let命令所在的代码块内有效)。不允许重复声明(不允许在相同作用域内,重复声明同一个变量。)
const: 声明一个只读的常量,声明时必须赋值(不赋值会报错)。和let一样具有不存在变量提升、暂时性死区、不允许重复声明、只在声明所在的块级作用域内有效的特性。
var: 声明变量,存在变量提升的现象。没有暂时性死区,允许重复声明,ES6之前只有全局作用域和函数作用域,没有块级作用域。
2.箭头函数与普通函数的区别
箭头函数:this对象是定义时所在的对象。不可以当作构造函数。没有arguments对象。不可以使用yield命令,因此箭头函数不能用作 Generator函数。没有prototype原型对象。
普通函数:this对象是使用时所在的对象。可以当做构造函数。可以使用arguments对象。可以使用yield命令,用作 Generator 函数。含有prototype原型对象。
3.ES5与ES6继承的不同
ES5 的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))。ES6的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this。
4.js模块化(commonjs/AMD/CMD/ES6)
Commonjs,NodeJS是该规范的主要实践者,有四个重要的环境变量:==module==、==exports==、==require==、global。module.exports定义当前模块对外输出,用require加载模块。CommonJS模块输出的是一个值的拷贝,一旦输出一个值,模块内部的变化就影响不到这个值。
// 定义模块math.js
var basicNum = 0;
function add(a, b) {
return a + b;
}
module.exports = { //在这里写上需要向外暴露的函数、变量
add: add,
basicNum: basicNum
}
// 引用自定义的模块时,参数包含路径,可省略.js
var math = require('./math');
math.add(2, 5);
// 引用核心模块时,不需要带路径
var http = require('http');
http.createService(...).listen(3000);
CommonJS是==同步加载模块==。在服务端,模块文件存于本地磁盘中,读取速度快,同步加载不会有问题。但是在浏览器中,由于网络原因,应该使用异步加载模块的方式,就是接下要提到的==AMD==规范。
AMD规范采用异步加载模块的方式,需要依赖加载的模块语句都放在回调函数中,等待依赖的模块加载完成再执行。require.js实现了AMD规范:用require.config()指定项目中用到的基础模块的引用路径,用define()定义模块,用require()加载模块
/** 网页中引入require.js及main.js **/
<script src="js/require.js" data-main="js/main"></script>
/** main.js 入口文件/主模块 **/
// 首先用config()指定各模块路径和引用名
require.config({
baseUrl: "js/lib",
paths: {
"jquery": "jquery.min", //实际路径为js/lib/jquery.min.js
"underscore": "underscore.min",
}
});
// 执行基本操作
require(["jquery","underscore"],function($,_){
// some code here
});
// 定义math.js模块
define(function () {
var basicNum = 0;
var add = function (x, y) {
return x + y;
};
return {
add: add,
basicNum :basicNum
};
});
// 定义一个依赖underscore.js的模块
define(['underscore'],function(_){
var classify = function(list){
_.countBy(list,function(num){
return num > 30 ? 'old' : 'young';
})
};
return {
classify :classify
};
})
// 引用模块,将模块放在[]内
require(['jquery', 'math'],function($, math){
var sum = math.add(10,20);
$("#sum").html(sum);
});
CMD是另一种js模块化的规范,它与AMD很相似。不同点在于AMD先加载所有依赖模块,再执行回调函数,不论回调函数中是否应用到该依赖模块。CMD则推崇依赖就近,延迟执行。sea.js在推广过程中实现了CMD。
/** AMD写法 **/
define(["a", "b", "c", "d", "e", "f"], function(a, b, c, d, e, f) {
// 等于在最前面声明并初始化了要用到的所有模块
a.doSomething();
if (false) {
// 即便没用到某个模块 b,但 b 还是提前执行了
b.doSomething()
}
});
/** CMD写法 **/
define(function(require, exports, module) {
var a = require('./a'); //在需要时声明
a.doSomething();
if (false) {
var b = require('./b');
b.doSomething();
}
});
/** sea.js **/
// 定义模块 math.js
define(function(require, exports, module) {
var $ = require('jquery.js');
var add = function(a,b){
return a+b;
}
exports.add = add;
});
// 加载模块
seajs.use(['math.js'], function(math){
var sum = math.add(1+2);
});
ES6 Module:ES6在语言标准的层面上,实现了模块功能,而且实现得相当简单,旨在成为浏览器和服务器通用的模块解决方案。其模块功能主要由两个命令构成:export和import。export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。
/** 定义模块 math.js **/
var basicNum = 0;
var add = function (a, b) {
return a + b;
};
export { basicNum, add };
/** 引用模块 **/
import { basicNum, add } from './math';
function test(ele) {
ele.textContent = add(99 + basicNum);
}
/** export default **/
//定义输出
export default { basicNum, add };
//引入
import math from './math';
function test(ele) {
ele.textContent = math.add(99 + math.basicNum);
}
- CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
- CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
5.promise、async await、Generator的区别
/*
假定某个 DOM 元素上面,部署了一系列的动画,前一个动画结束,才能开始后一个。如果当中有一个动画出错,就不再往下执行,返回上一个成功执行的动画的返回值。
*/
//promise方案:Promise会含有大量的then,catch的API,操作本身的语义反不清晰。
function chainAnimationsPromise(elem, animations) {
// 变量ret用来保存上一个动画的返回值
let ret = null;
// 新建一个空的Promise
let p = Promise.resolve();
// 使用then方法,添加所有动画
for(let anim of animations) {
p = p.then(function(val) {
ret = val;
return anim(elem);
});
}
// 返回一个部署了错误捕捉机制的Promise
return p.catch(function(e) {
/* 忽略错误,继续执行 */
}).then(function() {
return ret;
});
}
//generator方案:Generator虽然语义上比Promise方案清晰,但是需要用户声明自动执行函数,而且必须保证yield语句后面的表达式,必须返回一个Promise。
function chainAnimationsGenerator(elem, animations) {
return spawn(function*() {
let ret = null;
try {
for(let anim of animations) {
ret = yield anim(elem);
}
} catch(e) {
/* 忽略错误,继续执行 */
}
return ret;
});
}
//async方案:async函数实现最简洁,最符合语义,几乎没有语义不相关的代码。它将 Generator 写法中的自动执行器,改在语言层面提供,不暴露给用户,因此代码量最少。
async function chainAnimationsAsync(elem, animations) {
let ret = null;
try {
for(let anim of animations) {
ret = await anim(elem);
}
} catch(e) {
/* 忽略错误,继续执行 */
}
return ret;
}
6.js隐式转换
7.babel编译原理(未完成)