文章目录
- 一、Iterator迭代器
- 1.1 基础知识概述
- 1.2 工作原理
- 1.3 Symbol.iterator
- 1.4 Generator函数来实现Symbol.iterator接口
- 二、ES6 Class 类
- 2.1 概述
- 2.2 ES6中的继承
- 2.3 面向对象应用 - React
一、Iterator迭代器
1.1 基础知识概述
迭代器(Iterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署Iterator接口,就可以完成遍历操作。
ES6创造了一种新的遍历命令:for…of 循环,Iterator 主要供 for…of 使用。
原生JavaScipt案例合集
JavaScript +DOM基础
JavaScript 基础到高级
Canvas游戏开发
原生具备了 Iterator 接口的数据结构:
- Array 数组
- TypedArray 定型数组(一类指定元素类型的数组,不是实际的数组类型。创建的实例将在内存中创建一个数组缓冲区)
- String 字符串
- Arguments 参数(实参)对象
- NodeList 节点列表
- Set 数据结构
- Map 数据结构
var arr = [1,2,3,4];
let iterator = arr[Symbol.iterator]();
console.log(iterator.next()); //{ value: 1, done: false }
console.log(iterator.next()); //{ value: 2, done: false }
console.log(iterator.next()); //{ value: 3, done: false }
console.log(iterator.next()); //{ value: 4, done: false }
console.log(iterator.next()); //{ value: undefined, done: true }
1.2 工作原理
- 创建一个指针对象,指向当前数据结构的起始位置
- 第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员
- 接下来不断调用 next 方法,指针一直往后移,直到指向最后一个成员
- 每次调用 next 方法,返回一个包含 value 和 done 属性的对象
let obj = {
name:"张三",
age:18,
arr:[1,2,3,4,"壹","贰","叁","肆"]
}
现在想要拿到 obj 对象中 arr 数组的数据。由于 Object 并没有内置 Iterator ,所以使用 for…of 遍历时,控制台报错。
let obj = {
name:"张三",
age:18,
arr:[1,2,3,4,"壹","贰","叁","肆"]
}
for(value of obj){
console.log(value)
}
//Uncaught TypeError: obj is not iterable
至于对象没有布置 iterator 接口的原因,不知道大家有没有看根据《你一生的故事》拍成的电影“降临",片中出现的外星语言是一门非线性的语言。而我们说的数组,Map 等结构中的成员都是有顺序的,即都是线性的结构,而对象,各成员并没有一个确定的顺序,所以遍历时先遍历谁后遍历谁并不确定。所以,给一个对象部署 iterator 接口,其实就是对该对象做一种线性转换。如果你有这种需要,就需要手动给你的对象部署 iterator 接口。如下:
let obj = {
name:"张三",
age:18,
arr:[1,2,3,4,"壹","贰","叁","肆"],
[Symbol.iterator](){
let index =0
let _this = this
return {
next:function(){
if(index < _this.arr.length){
return { value:_this.arr[index++], done:false}
}else{
return {value:undefined,done:true}
}
}
}
}
}
for(value of obj){
console.log(value)
}
//1 2 3 4 "壹" "贰" "叁" "肆"
可以看到,Symbol.iterator会返回一个对象,这就是一个遍历器对象,而作为遍历器对象,其必须具备的特征就是必须具备next()方法。
1.3 Symbol.iterator
这个符号可以是任意对象上的一个专门属性,语言机制会自动的在这个属性上寻找一个方法,这个方法会构造一个迭代器来迭代这个对象的值,这个方法就是 next 方法,… 展开和 for/of 循环会自动使用它,**我们可以自定义 Symbol.iterator 属性为任意对象值定义自己的迭代器逻辑,它将覆盖默认的迭代器。**相当于定义了一种元编程行为,提供给 Javascript 其他部分(运算符和循环结构)在处理定义的对象时使用。
- 在 JS 中迭代器对象实现了可迭代协议,迭代器对象由 Symbol.iterator 属性的值返回。
- Symbol.iterator 属性的值是一个函数,它返回一个迭代器对象。
- 迭代器指的是拥有 next 方法的对象。
- 该next方法必须返回一个带有 value 和 done 的对象。
1.4 Generator函数来实现Symbol.iterator接口
var yieldIterator = {};
yieldIterator[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
};
[...yieldIterator] // [1, 2, 3]
注意,yield* 后面跟的是一个可遍历的结构,它会调用该结构的遍历器接口。
其它调用到遍历器的操作还有解构赋值、扩展操作符、其它任何接受数组作为参数的场合
- for…of
- Array.from()
- Map(), Set(), WeakMap(), WeakSet()(比如)
- Promise.all()
- Promise.race()
一旦当你给你的结构部署了iterator接口,那么恭喜你,你可以使用for…of来遍历你的结构了!
二、ES6 Class 类
2.1 概述
ES6之前,类和构造函数是同一个东西,并且调用的函数需要外挂(通过构造函数调用原型进行定义)。这对于面向对象语言很不友好,所以ES6中提供了类的概念。
- class类、constructor构造器区别开来
- class类中直接定义方法(原型方法、静态方法、实例方法)
class People {
// 静态方法
static sayHello(){
return "Hello ES6继承!!";
}
// 通过 constructor 定义类的构造函数
constructor(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
// 实例方法
this.sayHi = function(){
return "你好"
}
}
// 原型方法,不需要 function 声明
eat() {
return "是人就得喝水...";
}
}
// 通过 new 关键子定义一个类的对象
var p = new People("汉武帝", 1000, '男');
2.2 ES6中的继承
- extends 用于继承的关键字
- super 用于执行父类(超类、基类)中的构造函数
// 通过关键字 class 定义基类
class People {
// 静态方法
static sayHello(){
return "Hello ES6继承!!";
}
// 通过 constructor 定义类的构造函数
constructor(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
// 实例方法
this.sayHi = function(){
return "你好"
}
}
// 原型方法,不需要 function 声明
eat() {
return "是人就得喝水...";
}
}
class Doctor extends People {
constructor(name, age, sex, clothes) {
super(name, age, sex);
this.clothes = clothes;
}
behavior() {
return "救死扶伤";
}
}
// 通过 new 关键子定义一个类的对象
var p = new People("汉武帝", 1000, '男');
var d = new Doctor("李时珍", 700, '男', '白大褂');
2.3 面向对象应用 - React
-
组件化 - class
-
JSX(JS拓展版) == babel == browser.js
-
下载 react.js , react-dom.js,browser.js ,并引入到项目中
-
script 标签类型 type = “text/babel”,且不可以省略
HTML代码:
<div id="div1"></div>
JS代码:
<script src="./libs/react.js"></script>
<script src="./libs/react-dom.js"></script>
<script src="./libs/browser.js"></script>
<script type="text/babel">
// 自定义组件
class Item extends React.Component{
constructor(...args){
super(...args)
}
render(){
// 返回固定的值
// return <li>123</li>
// 返回通过属性动态传递的值
return <li>{this.props.str}</li>
}
}
class List extends React.Component{
constructor(...args){
super(...args)
}
render(){
/*
let aItems = [];
for(let i = 0; i < this.props.arr.length; i++){
aItems.push(<Item str={this.props.arr[i]}></Item>)
}
return <ul>
// 数组映射
{aItems}
</ul>
*/
// map 优化
let aItems = this.props.arr.map(a => <Item str={a}></Item>);
/*
return <ul>
{this.props.arr.map(a => <Item str={a}></Item>)}
</ul>
*/
return <ul>
{aItems}
</ul>
}
}
window.onload = function(){
let oDiv = document.getElementById('div1');
ReactDOM.render(
// 常规标签渲染
// <span>123</span>,
// 自定义组件渲染
<List arr="{['abc','def',ghi]}"></List>,
oDiv
)
}
</script>