1、单体模式下的对象
之前我们定义一个对象,使用的语法格式如下所示:
<script>
var name = 'qianqian';
var age = 24;
var person = {
name:name,
age:age,
showName:function(){
console.log(this.name);
}
};
person.showName();
</script>
在ES6当中声明定义一个对象的语法简洁化了。在ES6的对象语法当中,如果对象的属性名和属性值变量名相同,则只使用一个变量名即可,即使用name
来代替name:name
的写法。对象的方法定义可以从方法名:function(){}
改为方法名(){}
的写法。ES6当中单体模式下对象声明的语法格式如下所示:
<script>
let name = 'qianqian';
let age = 24;
let person = {
name,
age,
showName(){
console.log(this.name);
}
};
person.showName();
</script>
这两种写法的运行结果相同,均为输出qianqian
。
2、面向对象(class 和 constructor)
之前在面向对象当中类和构造函数的概念区分并不明显。示例代码如下所示:
<script>
//定义一个构造函数(类),在里面定义类的属性
function Person(name,age){
this.name = name;
this.age = age;
};
//使用prototype定义类的方法
Person.prototype.showName = function(){
console.log(this.name);
};
//使用new来调用声明好的类,传入不同的实参来形成不同的实例对象。
var p1 = new Person('qianqian',24);
p1.showName();
</script>
在ES6当中,类(class
)和构造函数(constructor
)的概念被区分开了。ES6当中使用面向对象的语法来定义一个类的示例代码如下所示:
<script>
//使用关键字class来定义一个Person类,在内部定义其属性与方法
class Person{
//在构造函数当中定义类的属性
constructor(name,age){
this.name = name;
this.age = age;
};
//接下去分别定义类的方法,不需要再使用prototype
showName(){
console.log(this.name);
};
};
//使用new来调用声明好的类,传入不同的实参,来生成不同的实例对象
let p1 = new Person('qianqian',24);
p1.showName();
</script>
由Person
这个类生成的实例对象,都有一个默认的constructor
属性,其属性值均为类名Person
。示例代码如下所示:
<script>
class Person{
constructor(name,age){
this.name = name;
this.age = age;
};
showName(){
console.log(this.name);
};
};
let p1 = new Person('qianqian',24);
let p2 = new Person('meimei',23);
console.log(p1.constructor == Person);
console.log(p2.constructor == Person);
console.log(p1.showName == p2.showName);
</script>
其输出结果均为true
。
3、原型继承
假设有一个子类Worker
类要继承父类Person
类,在之前的面向对象的语法当中,我们在Worker
类的构造函数当中,使用Person.apply(this,arguments);
来完成对父类属性的继承。使用Worker.prototype = new Person();
来实现对父类方法的继承。示例代码如下所示:
<script>
function Person(name,age){
this.name = name;
this.age = age;
};
Person.prototype.showName = function(){
console.log(this.name);
};
function Worker(name,age){
Person.apply(this,arguments);
};
//实现方法继承的语法格式为:子类.prototype = new 父类();
Worker.prototype = new Person();
//完成继承后,使用Worker类来生成实例
var w1 = new Worker('qianqian',24);
w1.showName();
</script>
输出结果为qianqian
。
apply
方法只接收两个参数,其中第二个参数必须是一个数组或者类数组,故可以将当前函数的arguments
对象作为apply
函数的第二个参数传入。apply
方法改变的是函数的调用对象,此方法的第一个参数为改变后调用这个函数的对象。
而在ES6当中,实现原型继承的语法就相对简化了许多,我们使用class 子类 extends 父类{};
即可完成子类继承父类全部属性和方法的功能。我们可以给继承的子类对象随意添加新的方法,但如果想要给子类添加新的属性,在其构造函数的内部,使用super(父类的形参列表);
先调用一次父类的构造函数,避免覆盖父类的构造函数,然后再定义新的子类属性。示例代码如下所示:
<script>
class Person{
constructor(name,age){
this.name = name;
this.age = age;
};
showName(){
console.log(this.name);
};
};
class Worker extends Person{
constructor(name,age,job){
//相当于先调用一次父类的构造函数,防止覆盖父类的构造函数
super(name,age);
//再定义新的子类属性
this.job = job;
};
//可以随意给子类对象添加新的方法
showName(){
console.log(this.name);
};
showJob(){
console.log(this.job);
};
};
//调用子类生成实例对象
let w1 = new Worker('qianqian',24,'student');
w1.showName();
w1.showJob();
</script>
输出结果为qianqian
和student
。
4、模块化
ES6自带模块化,不过我们在使用ES6的这个新语法特性时,必须引入编译文件,因为浏览器端还没有完全支持。比如我们定义一个模块a.js
(一般一个js
文件即代表一个模块),在其内部定义了变量和函数之后,可以使用export default {变量名,函数名};
的方式来导出。a.js
的示例代码如下所示:
let a = 5;
function sum(){
return 'haha';
};
export default {a,sum};
我们在主文件index.html
当中使用import 自定义模块名 from '模块文件的相对路径';
来实现模块的导入。其中index.html
的示例代码如下所示:
<script src="https://google.github.io/traceur-compiler/bin/traceur.js"></script>
<script src="https://google.github.io/traceur-compiler/bin/BrowserSystem.js"></script>
<script src="https://google.github.io/traceur-compiler/src/bootstrap.js"></script>
<script type="module">
import A from './a.js';
console.log(A.a);
console.log(A.sum());
</script>
若第一次运行报如下错误:
是因为我们没有把项目文件放在服务器环境下运行。
输出结果为5
和haha
。
5、Promise 对象
promise
是ES6当中一个新的语法点,这个对象主要用来传递和处理异步操作的数据。promise
对象只有三种状态:pending
(等待)、resolve
(成功)、reject
(失败),并且其状态变化只能是从pending
到resolve
,或者是从pending
到reject
。其基本使用语法的示例代码如下所示:
<script>
//一般在异步操作回调函数当中,声明一个Promise对象
let p1 = new Promise(function(resolve,reject){
if(异步操作成功){
resolve(成功的数据);
//把成功的数据传递下去
}else{
reject(失败的原因);
//把失败的原因传递下去
};
});
//promise对象p1具有then方法,接收两个函数参数,该方法仍然返回promise对象
p1.then(function(value){
/*当p1的回调函数当中执行resolve(成功的数据)时,执行该函数,形参value接收由resolve传递下来的成功的数据。*/
},function(err){
/*当p1的回调函数当中执行reject(失败的原因)时,执行该函数,形参err接收由reject传递下来的失败的原因。*/
});
</script>
我们在前端使用ajax
异步操作数据时,可以使用promise
对象,示例代码如下所示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<script src="jquery-1.10.2.js"></script>
<script>
$(function(){
$('#btn').on('click',function(){
let p1 = new Promise(function(resolve,reject){
$.ajax({
url:'http://localhost/demo/1.txt',
type:'GET',
dataType:'text',
success:function(data){
resolve(data);
},
error:function(){
reject('failed');
}
});
});
p1.then(function(value){
console.log(value);
},function(err){
console.log(err);
});
});
});
</script>
</head>
<body>
<button id="btn">button</button>
</body>
</html>
我们也可以在node.js
的异步操作的回调函数当中使用promise
对象。示例代码如下所示:
'use strict';
const fs = require('fs');
const path = require('path');
let target = path.join(__dirname,'./1.txt');
fs.readFile(target,function(err,data){
let p1 = new Promise(function(resolve,reject){
if(err){
reject(err);
}else{
resolve(data);
};
});
p1.then(function(data){
console.log(data.toString());
},function(err){
console.log(err);
});
});
5.1、promise
对象的方法
1、 .then()
该方法在前面有详细介绍,其示例代码如下所示:
<script>
let p1 = new Promise(function(resolve,reject){
resolve(1);
});
p1.then(function(value){
alert(value);
return value + 1;
},function(value){
alert(value);
return value + 2;
}).then(function(value){
alert(value);
});
</script>
先弹出1
,再弹出2
。
2、.catch()
该方法用于捕获异常信息。其示例代码如下所示:
<script>
let p1 = new Promise(function(resolve,reject){
resolve(1);
});
p1.then(function(value){
throw value;
}).catch(function(e){
alert(e);
});
</script>
输出结果为弹出数字1
。
5.2、Promise
类身上的方法
1、 Promise.resolve()
这个方法可以生成一个成功的promise
对象。该方法的参数可以是一个单纯的值或数组,也可以是另一个promise
的执行结果。示例代码如下所示:
<script>
let p1 = Promise.resolve([1,2,3]);
p1.then(function(value){
console.log(value[2]);
},function(err){
alert('failed');
});
</script>
输出结果为3
。
2、 Promise.reject()
这个方法可以生成一个失败的promise
对象。示例代码如下所示:
<script>
let p1 = Promise.reject('failed');
p1.then(function(value){
alert('success')
},function(err){
alert(err);
});
</script>
弹出结果为'failed'
。
3、 Promise.all()
该方法默认接收一个数组,其中数组元素均为promise
对象。这个方法可以将多个promise
对象组合,包装成一个全新的promise
对象。
这个全新的promise
对象也有then
方法,当其参数当中所有的promise
对象都成功时,才会执行then
方法当中的第一个参数函数,此时该函数的形参代表一个数组,里面的值按顺序出现。示例代码如下所示:
<script>
let p1 = Promise.resolve(1);
let p2 = Promise.resolve(2);
let p3 = Promise.resolve(3);
Promise.all([p1,p2,p3]).then(function(value){
console.log(value);
},function(err){
console.log('failed');
});
</script>
其输出结果为[1,2,3]
。
在其参数数组当中只要出现失败的promise
对象,就会执行then
方法当中的第二个参数函数,形参仅包含最先出现的那个失败的promise
对象当中的值。示例代码如下所示:
<script>
let p1 = Promise.resolve(1);
let p2 = Promise.reject(2);
let p3 = Promise.reject(3);
Promise.all([p1,p2,p3]).then(function(value){
console.log('success' + value);
},function(err){
console.log('failed' + err);
});
</script>
其输出结果为'failed2'
。
4、 Promise.race()
该方法默认接收一个数组,其中数组元素均为promise
对象。这个方法选取最先到达的那个promise
结果,该方法的返回结果也为一个promise
对象。示例代码如下所示:
<script>
let p1 = new Promise(function(resolve,reject){
setTimeout(resolve('one'),50);
});
let p2 = new Promise(function(resolve,reject){
setTimeout(resolve('two'),100);
});
Promise.race([p1,p2]).then(function(value){
console.log(value);
},function(err){
console.log(err);
});
</script>
其输出结果为'one'
。
6、Generator(生成器)
生成函数与普通函数在语法格式上的区别为,在函数名前面有*
号,一般紧跟在function
的后面。在生成器函数的内部,有一种类似与return
的语法,关键字yield
(yield
语句可以用于遍历函数内部的状态)。二者的区别是,普通函数只能return
一次,而生成器函数可以yield
多次。在生成器函数的执行的过程中,遇到yield
表达式立即暂停,后续可以恢复执行状态。示例代码如下所示:
<script>
//声明一个生成器函数show
function* show(){
yield 'hello';
yield 'world';
yield 'ES6';
return 'all';
};
//生成器函数先调用一次,用变量res来接收该函数执行的返回值
let res = show();
/*这个返回值身上自带方法.next(),类似于开始进行状态遍历,该方法每调用一次,都会返回一个对象,有value和done这两个属性,value的属性值为每次yield后面对应的值,done的属性值是一个布尔值,代表状态遍历是否结束。*/
console.log(res.next());
console.log(res.next());
console.log(res.next());
console.log(res.next());
console.log(res.next());
</script>
其输出结果为:
生成器函数可以放在对象内部,作为对象的一个方法。其示例代码如下所示:
<script>
var json1 = {
*show(){
yield 'hello';
yield 'world';
return 'all';
}
};
var json2 = {
show:function*(){
yield 'xixi';
yield 'haha';
return 'so';
}
};
var res1 = json1.show();
console.log(res1.next());
console.log(res1.next());
console.log(res1.next());
var res2 = json2.show();
console.log(res2.next());
console.log(res2.next());
console.log(res2.next());
</script>
其输出结果为:
我们可以使用for...of
来循环生成器函数,示例代码如下所示:
<script>
function* show(){
yield 'hello';
yield 'world';
yield 'ES6';
return 'all';
};
for(let v of show()){
console.log(v);
};
</script>
其输出结果为:
生成器函数的yield
表达式语句本身没有返回值,或者说总是返回undefined
。next()
方法可以带一个参数,该参数会被当做上一条yield
语句的返回值。示例代码如下所示:
<script>
function* show1(){
let a = yield 'hello';
return a;
};
let res1 = show1();
console.log(res1.next());
console.log(res1.next());
function* show2(){
let a = yield 'hello';
return a;
};
let res2 = show2();
console.log(res2.next());
console.log(res2.next('world'));
function* show3(){
for(let i = 0; i < 10; i++){
let a = yield i;
if(a){
i = -1;
};
};
};
let res3 = show3();
console.log(res3.next());
console.log(res3.next());
console.log(res3.next(true));
console.log(res3.next());
</script>
其输出结果为:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。