模块化(module):
export default / export 暴露,import 引入
注意:
使用export default 时,用import直接引入不用花括号;
如果export 时,则要使用花括号。
扩展:
在 ES6 之前,社区制定了一些模块加载方案,最主要的有 CommonJS 和 AMD 两种。CommonJS用于服务器,AMD用于浏览器。
①CommonJS:Node.js采用了这个规范。 根据CommonJS规范,一个单独的文件就是一个模块。加载模块使用require方法,该方法读取一个文件并执行,最后返回文件内部的exports对象。
②AMD(异步模块加载):但是Commonjs是同步加载模块,当要用到该模块了,现加载现用,这种同步机制到了浏览器里边就有问题了,性能问题。所以异步加载出现了,实现这种规范的js库是require.js。
语法:define 定义模块,require引入模块。
define({
method1: function() {},
method2: function() {},
});
require([module], callback);
Promise :
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。
Promise是一个构造函数,用来生成promise实例,构造函数接收一个函数作为参数(执行函数),执行函数有两个参数(resolve和reject),当执行函数成功时执行resolve并将需要的参数传递出去,当执行函数失败时执行reject并将需要的参数传递出去。当实例生成后,可以用这个实例的then方法来指定成功和失败时的回调函数。
下面是一个用Promise对象实现的 Ajax 操作的例子:
const getJSON = function(url) {
const promise = new Promise(function(resolve, reject){
const handler = function() {
if (this.readyState !== 4) {
return;
}
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error(this.statusText));
}
};
const client = new XMLHttpRequest();
client.open("GET", url);
client.onreadystatechange = handler;
client.responseType = "json";
client.setRequestHeader("Accept", "application/json");
client.send();
});
return promise;
};
getJSON("/posts.json").then(function(json) {
console.log('Contents: ' + json);
}, function(error) {
console.error('出错了', error);
});
Promise.all()和Promise.race()
all方法接收一个promise数组([p1,p2,p3]),将其包装成一个新的promise对象p,当p1,p2,p3都是成功状态时,将p的状态变为成功状态,而race方法则是只要有一个promise对象返回成功,p就会变为成功状态。
想到最近使用的promise的实例代码如下:
//使用promise依次获取完三种筛选项后,一起渲染一次
let this_=this;
let role=new Promise(function (resolve,reject) {
let url=urlConfig.queryFilterManageItemDetails+this_.state.websiteId+"/1";
let headers={
'accessToken': this_.state.accessToken
};
let params={};
ajax.post(url,params,function (data,total) {
resolve(data.list);
},headers)
});
let business=new Promise(function (resolve,reject) {
let url=urlConfig.queryFilterManageItemDetails+this_.state.websiteId+"/2";
let headers={
'accessToken': this_.state.accessToken
};
let params={};
ajax.post(url,params,function (data,total) {
resolve(data.list);
},headers)
});
Promise.all([role, business]).then(function (results) {
console.log(results);//results是个数组,数组项为两个promise成功返回的值
this_.setState({
filterRoleList:results[0],
filterBusinessList:results[1]
})
});
async/await(拓展内容ES7,async/await同步代码的方式实现异步)
async用来定义个异步函数,返回一个promise对象;
当async函数中return一个值时,这个值就是Promise对象中resolve的值,
当async函数中throw一个值时,这个值就是Promise对象中reject的值。
实例如下:
async function imAsync(num) {
if (num > 0) {
return num // 这里相当于resolve(num)
} else {
throw num // 这里相当于reject(num)
}
}
imAsync(1).then(function (v) {
console.log(v); // 1
});
// 注意这里是catch
imAsync(0).catch(function (v) {
console.log(v); // 0
})
await 在async定义的函数里出现,暂停async函数的执行,等他后面的那个promise执行完成后,继续执行async函数内的下一行代码。
注意:await不是谁都等,只等后面的promise,不是promise不等。
实例如下:
function timeout(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
async function asyncPrint(value, ms) {
await timeout(ms);
console.log(value);
}
asyncPrint('hello world', 50);
Class:
ES6 的类,完全可以看作是构造函数的语法糖(只是这样写,本质是一样的)。
下面看一下类的构造函数写法的不同:
//构造函数写法
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.toString = function () {
return '(' + this.x + ', ' + this.y + ')';
};
var p = new Point(1, 2);
而使用ES6的类是这样写:
class Point {
constructor(x,y){
this.x=x;
this.y=y;
}
toString(){
return '(' + this.x + ', ' + this.y + ')';
}
}
typeof Point // "function"
Point === Point.prototype.constructor // true
上面代码表明,类的数据类型就是函数,类本身就指向构造函数.
如果非要说区别,那就是ES6定义的类的原型上的方法是不可枚举的,也就是用Object.keys()遍历不到那个toString,而ES5的表现与之不同。
Class的继承
聊到ES6的继承,先回顾一下ES5的继承,介绍一下典型的构造函数继承,原型继承和组合继承。
首先,定义一个父类构造函数:
function Animal (name) {
this.name = name || 'Animal';
this.sleep = function(){
console.log(this.name + '正在睡觉!');
}
}
// 原型方法
Animal.prototype.eat = function(food) {
console.log(this.name + '正在吃:' + food);
};
继承方案一:构造函数继承
function Cat(){
Animal.call(this);
}
let cat = new Cat();
特点:cat实例继承了Animal的构造函数里的属性和方法,但是没有继承原型上的方法。
继承方案二:原型继承
function Cat(){
}
Cat.prototype=new Animal();
特点:纯粹的原型继承,实例通过原型来查找属性和方法,如果父类中有引用类型的属性,子类实例修改这个属性时会影响到其他实例,因为他们共享这个引用类型的地址。
原型和原型链相关的介绍见:https://www.jianshu.com/p/a4e79a85dbf0
继承方案三:组合继承
function Cat(name){
Animal.call(this);
}
Cat.prototype = new Animal();
特点:调用两次父类的构造函数,子类实例构造函数上的属性和方法将其原型的覆盖了。
继承方案四:寄生组合式继承
function inherit(Target,Origin) {//实现寄生组合式继承的核心函数
function F() {};
F.prototype = Origin.prototype; //F()的原型指向的是Origin
Target.prototype = new F(); //Target的原型指向的是F()
Target.prototype.constructor = Target;
Target.prototype.__proto__ == Origin.prototype
}
function Cat(name){
Animal.call(this);
}
inherit(Cat,Animal);//实现寄生组合式继承
Class的继承
那么现在说Class的继承,是像这样写:
class Cat extends Animal{
constructor(){
super();
}
}
而这个Class继承就可看作是寄生组合式继承的语法糖。
箭头函数
箭头函数写起来更加简洁,与普通函数的区别在于this的指向上。
this的指向:
①普通函数中的this指向undefined;
②对象方法中的this指向这个对象;
③构造函数中的this指向实例化的对象;
④箭头函数的this指向定义时的外层作用域的指向。
修改this指向:
call和apply都可以修改this指向并直接执行函数,但传参形式不同,apply第二个参数是数组;
bind和call传参形式相同,但bind可以延缓函数的执行;
ES6其他
①let/const 声明变量和常量;
②模板字符串,使用反引号内部用${}表示变量;
③解构赋值;
④函数默认参数,function(a=1){};