ES6入门基础
推荐书籍 《ECMAScript 6 入门》:http://es6.ruanyifeng.com/
码云仓库代码(欢迎Start)
码云仓库代码-https://gitee.com/hongjunyong/es6-imooc-lottery
1、为什么要学习ES6
detail.png1.1、对象拷贝
copy.png1.2、参数传递
data.png1.3、更多特性:解构赋值、箭头函数、set和map、异步操作、类与对象、模块化
2、项目构建(略)
// -e要使用ejs模版引擎 .当前目录执行
express -e .
express.png
// 安装依赖:npm install
npm install gulp gulp-if gulp-concat webpack webpack-stream vinyl-named gulp-livereload gulp-plumber gulp-rename gulp-uglify gulp-util y
args --save-dev
项目运行 gulp --watch
3、ES6语法
3.1、let const命令(案例:lesson1-let-const.js)
3.1.1、let的生命周期
// i在for循环外面依旧有效
for(var i=1;i<3;i++){
console.log(i);
}
console.log(i);
// i只有在for循环里面有效,出了括号生命周期结束
for(let i=1;i<3;i++){
console.log(i);
}
console.log(i);
let.png
3.1.2、let变量不能重复定义
错误:
let a = 1;
let a = 2;
3.1.3、const常量不能修改,对象可以修改(指针),且声明的时候必须赋值
const常量不能修改
错误:
const a = 1;
a = 2;
对象可以修改
正确:
const k = {
a:1
}
k.b = 3;
声明的时候必须赋值
错误:
const a;
a = 1;
正确:
const a = 1;
3.1.4、es6开启严格模式('use strict')
3.1.4.1 不允许使用未声明的变量
"use strict";
x = 3.14; // 报错 (x 未定义)
3.1.4.2 不允许使用未声明的变量(对象也是一个变量)
"use strict";
x = { p1: 10, p2: 20 }; // 报错 (x 未定义)
3.1.4.3 不允许删除变量或对象
"use strict";
var x = 3.14;
delete x; // 报错
3.1.4.4 不允许删除函数
"use strict";
function x(p1, p2) {};
delete x; // 报错
3.1.4.5 不允许变量重名
"use strict";
function x(p1, p1) {}; // 报错
3.1.4.6 不允许使用八进制
"use strict";
var x = 010; // 报错
3.1.4.7 不允许使用转义字符
"use strict";
var x = \010; // 报错
3.1.4.8 不允许对只读属性赋值
"use strict";
var obj = {};
Object.defineProperty(obj, "x", {value:1, writable:false});
console.log(obj); // 输出{x: 1}
obj.x = 3.14; // 报错
3.1.4.9 不允许对一个使用getter方法读取的属性进行赋值
"use strict";
var obj = {get x() {return 0} };
obj.x = 3.14; // 报错
3.1.4.10 不允许删除一个不允许删除的属性
"use strict";
delete Object.prototype; // 报错
3.1.4.11 变量名不能使用 "eval" 字符串
"use strict";
var eval = 3.14; // 报错
3.1.4.12 变量名不能使用 "arguments" 字符串:
"use strict";
var arguments = 3.14; // 报错
3.1.4.13 全局的'use strict',函数内的变量也声明
"use strict";
myFunction();
function myFunction() {
y = 3.14; // 报错 (y 未定义)
}
3.1.4.14 函数内部声明是局部作用域 (只在函数内使用严格模式):
x = 3.14; // 不报错
myFunction();
function myFunction() {
"use strict";
y = 3.14; // 报错 (y 未定义)
}
3.1.4.4 为什么使用严格模式:
消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为;
消除代码运行的一些不安全之处,保证代码运行的安全;
提高编译器效率,增加运行速度;
为未来新版本的Javascript做好铺垫。
"严格模式"体现了Javascript更合理、更安全、更严谨的发展方向,包括IE 10在内的主流浏览器,都已经支持它,许多大项目已经开始全面拥抱它。
3.2、解构赋值(案例:lesson2-jiegou.js)
解构赋值的分类:数组解构赋值、对象解构赋值、字符串解构赋值、布尔值解构赋值、函数参数解构赋值、数值解构赋值
3.2.1、数组解构赋值
// 块作用域:变量的重复声明,用块包起来就不会出现问题
{}
{
let a, b, rest;
[a, b] = [1, 2];
// 输出1 2
console.log(a, b);
}
{
let a, b, rest;
[a,b,...rest]=[1,2,3,4,5,6]
// 输出1 2 [3,4,5,6]
console.log(a,b,rest);
}
3.2.1.1、默认值undefined
// 没有配对成功,默认值为3;如果=3去掉,c是undefined
{
let a, b, c, rest;
[a, b, c=3] = [1, 2];
// 输出1 2 3
console.log(a, b, c);
}
3.2.1.2、使用场景
// 变量交换
{
let a = 1;
let b = 2;
[a, b] = [b, a];
// 输出2 1
console.log(a, b)
}
// 取值方便
{
function f() {
return [1,2]
}
let a, b;
[a,b]=f();
// 输出1 2
console.log(a, b)
}
// 选择性接收变量
{
function f() {
return [1,2,3,4,5]
}
let a,b,c;
// 两个逗号,对应一个值
[a,,,b]=f();
// 输出1 4
console.log(a, b)
}
{
function f() {
return [1,2,3,4,5]
}
let a,b,c;
[a,...b]=f();
// 输出1 [2,3,4,5]
console.log(a, b)
}
3.2.2、对象解构赋值
// 左侧与右侧都是一个对象
{
let a,b;
({a, b} = {a:1,b:2});
// 输出1 2
console.log(a,b)
}
{
let o={p:42,q:true};
let {p,q}=o;
// 输出:42 true
console.log(p,q);
}
3.2.2.1、默认值
{
let {a = 10, b = 5} = {a: 3};
// 输出:3 5
console.log(a, b);
}
3.2.2.2、使用场景
// 获取json
{
let metaData = {
title: 'abc',
test:[{
title:'test',
desc:'description'
}]
}
let {title:esTitle,test:[{title:cnTitle}]} = metaData;
// 输出:abc test
console.log(esTitle, cnTitle)
}
3.3、正则(案例:lesson3-regexp.js)略
新特性:构造函数的变化、正则方法的扩展、u修饰符、y修饰符、s修饰符
{
// es5
let regex = new RegExp('xyz','i');
let regex2 = new RegExp(/xyz/i);
// 输出:true true
console.log(regex.test('xyz123'), regex2.test('xyz123'));
// es6
// 允许第二个参数i覆盖修饰符ig
let regex3 = new RegExp(/xyz/ig,'i');
console.log(regex3.flags)
}
// y修饰符
{
let s = 'bbb_bb_b';
// g跟y都是全局匹配;但是全局匹配不同点是,g是从上一次匹配继续开始查找(只要能找到,就算匹配成功)
// y是从下一个匹配,如果第一个匹配不对,就算匹配失败
// 第一步g跟y都可以匹配到bbb
// 第二步只有g可以匹配到bb
let a1 = /b+/g;
let a2 = /b+/y;
console.log('one',a1.exec(s),a2.exec(s));
console.log('two',a1.exec(s),a2.exec(s));
// 判断一个正则是否使用了y修饰符
console.log(a1.sticky);
console.log(a2.sticky);
}
// u修饰符(1、当处理字符串中的正则的长度大于2的时候 2、.是修饰小于2个字节)
{
// true: \uD83D\uDC2A当成了2个字母(字符)
console.log('u-1',/^\uD83D/.test('\uD83D\uDC2A'));
// false: \uD83D\uDC2A当成了1个字母(字符)
console.log('u-2',/^\uD83D/u.test('\uD83D\uDC2A'));
// 如果{}放的是unicode编码,要加个u,才能被识别
// false
console.log(/\u{61}/.test('a'));
// true
console.log(/\u{61}/u.test('a'));
// 𠮷
console.log(`\u{20BB7}`);
let s = '𠮷';
// false
console.log('u',/^.$/.test(s))
// true
console.log('u',/^.$/u.test(s))
// false
console.log('test',/𠮷{2}/.test('𠮷𠮷'));
// true
console.log('test-2',/𠮷{2}/u.test('𠮷𠮷'));
}
3.4、字符串(案例:lesson4-string.js)
新增特性:Unicode表示法、遍历接口、模板字符串、新增方法(10种)
npm install babel-polyfill --save-dev
label-polyfill.png
{
let str = 'string';
// 查找是否包含了r
console.log('查找是否包含了r:', str.includes('r')); // true
// 判断是否以str为起始
console.log('判断是否以str为起始:',str.startsWith('str')); // true
// 判断是否以ng为结尾
console.log('判断是否以ng为结尾:',str.endsWith('ng')); // true
}
{
let str = 'abc';
// 字符串复制
console.log('字符串复制:' + str.repeat(2)); // abcabc
}
{
let name = 'list';
let info = 'hello world';
let m = `i am ${name},${info}`;
console.log('字符串拼接:' + m) // i am list,hello world
}
{
// 通常运用在日期
// 向前补:长度是4位,不够补0
console.log('1'.padStart(4,'0')); // 0001
// 向后补
console.log('1'.padEnd(2,'0')); // 10
}
3.5 数值扩展(案例:lesson5-number-math.js)
新增特性:新增方法、方法调用
{
// Number.isFinite()用来检查一个数值是否为有限的
// 有进 true
console.log('15',Number.isFinite(15));
// 无进 false
console.log('NaN',Number.isFinite(NaN));
// 分母为0 false
console.log('1/0',Number.isFinite('true'/0));
// true
console.log('NaN',Number.isNaN(NaN));
// false
console.log('0',Number.isNaN(0));
}
{
// 判断一个数是不是整数
// true
console.log('判断25是不是整数:' + Number.isInteger(25));
// true
console.log('判断25.0数是不是整数:' + Number.isInteger(25.0));
// false
console.log('判断25.1数是不是整数:' + Number.isInteger(25.1));
// false
console.log('判断"25.1"数是不是整数:' + Number.isInteger('25.1'));
// false
console.log('判断"25"数是不是整数:' + Number.isInteger('25'));
}
{
// 常量
// 表示数的最大上线 9007199254740991
console.log(Number.MAX_SAFE_INTEGER);
// 表示数的最小下线 -9007199254740991
console.log(Number.MIN_SAFE_INTEGER);
// 10是一个安全的数 true
console.log('10', Number.isSafeInteger(10));
// false
console.log('a', Number.isSafeInteger('a'));
}
{
// Math.trunc取整数
// 4
console.log(4.1,Math.trunc(4.1));
// 4
console.log(4.9,Math.trunc(4.9));
}
{
// 判断数字是正数还是负数
// 负数为-1
console.log('-5',Math.sign(-5));
// 0为0
console.log('0',Math.sign(0));
// 正数为1
console.log('5',Math.sign(5));
// NaN
console.log('foo',Math.sign('foo'));
}
{
// -1的立方根
console.log('-1的立方根:',Math.cbrt(-1))
console.log('8的立方根:',Math.cbrt(8))
}
3.6 数组扩展(案例:lesson6-array.js)
新增特性:Array.from、Array.of、copyWithin、find\findIndex、fill、entries\keys\values、inludes
{
// 是一个数组
let arr = Array.of(3,4,7,9,11);
console.log('arr是一个数组' + arr); // 3,4,7,9,11
// 空数组
let empty = Array.of();
console.log('空数组:',empty); // 空数组: []
}
{
let p = document.querySelectorAll('p');
let pArr = Array.from(p);
pArr.forEach(function (item) {
// textContent原生js获取DOM节点内容
// es6
// hjy
// oli
console.log(item.textContent);
});
// 把数组的里参数都乘以2
console.log(Array.from([1,3,5],function (item) {
return item*2; // 2,6,10
}));
}
{
// 数组里的参数都被替换成7
console.log('fill-7',[1,'a',undefined].fill(7)); // [7, 7, 7]
// 从起始位置1,不到3的位置,替换成7
console.log('fill,post',['a','b','c'].fill(7,1,3)); // ["a", 7, 7]
}
{
for(let index of ['1','c','ks'].keys()){
// 0 1 2
console.log('keys', index);
}
for(let value of ['1','c','ks'].values()){
// 1 c ks
console.log('values', value);
}
for(let [index,value] of ['1','c','ks'].entries()){
// index=0, value=1
// index=1, value=c
// index=2, value=ks
console.log('index=' + index + ', value=' + value);
}
}
{
// Array.prototype.copyWithin(target, start = 0, end = this.length)
// target(必需):从该位置开始替换数据。如果为负值,表示倒数。
// start(可选):从该位置开始读取数据,默认为 0。如果为负值,表示倒数。
// end(可选):到该位置前停止读取数据,默认等于数组长度。如果为负值,表示倒数。
// 从0的位置开始替换,从3开始读取,从4截止
// 把4放到1的位置上:[4, 2, 3, 4, 5]
console.log([1,2,3,4,5].copyWithin(0,3,4));
}
{
console.log([1,2,3,4,5,6].find(function (item) {
// 查找第一个符合大于3的值(找到了就停止)
// 返回4
return item > 3;
}));
console.log([1,2,3,4,5,6].findIndex(function (item) {
// 查找第一个符合大于3的下标(找到了就停止)
// 返回3
return item > 3;
}));
}
{
// 数组中是不是包含了1
// true
console.log('number',[1,2,NaN].includes(1));
// true
console.log('number',[1,2,NaN].includes(NaN));
}
3.7 函数扩展(案例:lesson7-function.js)
新增特性:参数默认值、rest参数、扩展运算符、箭头函数、this绑定、尾调用
{
function test(x,y = 'world') {
// 如果y没有值,就采用默认值为world;如果有值,用采用传递过来的参数
console.log('默认值',x,y)
}
test('hello');
test('hello','hjy');
// 错误写法:
// function test(x,y = 'world',c)
// 正确写法:
// function test(x,y = 'world',c='bb')
}
{
let x = 'test';
// 都是取kill
function test2(x,y=x) {
console.log("作用域:",x,y);
}
// 作用域: kill kill
test2('kill');
function test3(c,y=x) {
// 作用域: kill test
console.log("作用域:",c,y);
}
test3('kill');
}
{
// ...arg不确定传入几个参数,转成一个数组
function test4(...arg) {
for(let v of arg){
// rest 1
// rest 2
// rest 3
// rest 4
// rest a
console.log('rest',v);
}
}
test4(1,2,3,4,'a');
}
{
// 把数组转成一个离散的值
console.log(...[1,2,4]); // 1 2 4
console.log('a',...[1,2,4]);// a 1 2 4
}
{
// 函数
// arrow函数名 v参数 v*2返回值
let arrow = v => v*2;
let arrow2 = () => 5;
console.log('a',arrow(3)); // a 6
console.log('a',arrow2()); // a 5
}
{
// 尾调用(提升性能:函数地址嵌套)
function tail(x) {
console.log('tail',x);
}
function fx(x) {
return tail(x)
}
fx(123)
}
3.8 对象扩展(案例:lesson8-Obj.js)
新增特性:简洁表示法、属性表达式、扩展运算符、Object新增方法
{
// 简洁表达
let o = 1;
let k = 2;
let es5 = {
o:o,
k:k
};
let es6 = {
o,
k
};
console.log(es5,es6); // {o: 1, k: 2} {o: 1, k: 2}
// 对象里有方法
let es5_method = {
hello:function () {
console.log('hello');
}
};
let es6_method = {
hello(){
console.log('hello');
}
};
console.log(es5_method.hello(),es6_method.hello());// hello hello
}
{
// 属性表达式
let a = 'b';
let es5_obj = {
a:'c'
};
// [a]是一个变量
let es6_obj = {
[a]:'c'
};
// {a: "c"} {b: "c"}
console.log(es5_obj,es6_obj)
}
{
// 新增API
// Object.is与三个等号相同 输出:true true
console.log('判断2个字符串是否相等', Object.is('abc','abc'), 'abc' === 'abc');
// 数组是引用类型,但是数组引用的是不同地址 输出:false false
console.log('数组',Object.is([],[]), [] === []);
// 当个对象合并成一个对象{a: "a", b: "b"}
console.log('拷贝', Object.assign({a:'a'}, {b:'b'}));
// 对数组进行遍历
let test = {k:123,o:456};
for(let [key,value] of Object.entries(test)){
console.log(key,value);
}
}
3.9 symbol(案例:lesson9-symbol.js)
ES6新增加的类型
就是这种数据类型,提供一个独一无二(保证唯一)的值
{
// 声明
let a1 = Symbol();
let a2 = Symbol();
// false
console.log(a1 === a2);
// 'a3'是一个key值
let a3 = Symbol.for('a3');
let a4 = Symbol.for('a3');
// true
console.log(a3 === a4);
}
{
// 使用场景:两个相同的名字,不想去改变
let a1 = Symbol.for('abc');
let obj = {
[a1]:'123',
'abc':'345',
'c':456
};
console.log(obj); // {abc: "345", c: 456, Symbol(abc): "123"}
// symbol的值取不到
for(let [key,value] of Object.entries(obj)){
// let of abc 345
// let of c 456
console.log('let of', key, value);
}
// 取到symbol的值
Object.getOwnPropertySymbols(obj).forEach(function (item) {
// 123
console.log(obj[item])
});
// 两种参数的值都可以获取到
Reflect.ownKeys(obj).forEach(function (item) {
// ownKeys abc 345
// ownKeys c 456
// ownKeys Symbol(abc) 123
console.log('ownKeys', item, obj[item]);
})
}
3.10 set-map数据结构(案例:lesson10-set-map.js)
{
let list = new Set();
list.add(5);
list.add(7);
// 判断长度 输出:2
console.log('size',list.size);
}
{
let arr = [1,2,3,4,5];
let list = new Set(arr);
// 5
console.log('size', list.size);
}
{
// 运用场景:去重
let list = new Set();
list.add(1);
list.add(2);
// 重复元素,没有添加成功
list.add(1);
// {1, 2}
console.log('list',list);
let arr = [1,2,3,1,2];
let list2 = new Set(arr);
// 输出{1,2,3}
console.log('unique',list2);
}
{
let arr = ['add','delete','clear','has'];
let list = new Set(arr);
// 判断list里面有没有add这个值 输出:true
console.log('has', list.has('add'));
// 删除list
console.log('delete', list.delete('add'), list);
// 清空list
list.clear();
console.log('list',list);
}
{
let arr = ['add','delete','clear','has'];
let list = new Set(arr);
for(let key of list.keys()){
// keys add
// keys delete
// keys clear
// keys has
console.log('keys',key);
}
for(let value of list.values()){
// values add
// values delete
// values clear
// values has
console.log('values',value);
}
for(let value of list){
// values add
// values delete
// values clear
// values has
console.log('values',value);
}
for(let [key,value] of list.entries()){
// entries add add
// entries delete delete
// entries clear clear
// entries has has
console.log('entries',key,value)
}
list.forEach(function (item) {
// add
// delete
// clear
// has
console.log(item);
})
}
{
// 和set的数据类型不一样,WeakSet只是能对象,不能是数值,例如boolean
// WeakSet对象这块,弱引用(不会检测对象在其他地方引用到,意味着不会跟垃圾回收机制挂钩到,简单说:WeakSet是一个地址的引用)
// WeakSet没有clean、没有set、不能遍历
let weakList = new WeakSet();
let arg = {};
weakList.add(arg);
// 报错
// weakList.add(2);
console.log('weakList',weakList);
}
{
let map = new Map();
let arr = ['123'];
map.set(arr,456);
console.log('map', map, map.get(arr)); // key是123 value是456
}
{
let map = new Map([['a',123],['b',456]]);
console.log('map args', map); // {"a" => 123, "b" => 456}
console.log('size', map.size); // 2
console.log('delete', map.delete('a'), map); // {"b" => 456}
console.log('clear', map.clear(), map); // {}
}
{
// 与set和weakSet是一样的
let weakmap = new WeakMap();
}
3.11 map-set与数组和对象的比较(案例:lesson11-map-set-array-obj.js)
涉及的数据结构能使用map,不使用数组
数据的唯一性使用set
{
// map 和 array 数据结构横向对比:增删改查
let map = new Map();
let array = [];
// 增
map.set('t',1);
array.push({t:1});
console.info('map-array-add',map,array);
// 查
let map_exist = map.has('t');// true
let array_exist = array.find(item=>item.t);// 遍历数组,查看是否存在;如果存在,就返回值
console.info('map-array-find', map_exist, array_exist);
// 改(map比较简单,array复杂)
map.set('t',2);
array.forEach(item => item.t ? item.t = 2 : '');
console.info('map-array-modify',map, array);
// 删(map比较简单,array复杂)
map.delete('t');
let index = array.findIndex(item => item.t);
array.splice(index,1);
console.info('map-array-remove',map, array);
}
{
// set 和 array 的对比
let set = new Set();
let array = [];
// 增
set.add({t:1});
array.push({t:1});
console.info('set-array-add', set, array);
// 查
let set_exist = set.has({t:1});// false
let array_exist = array.find(item=>item.t);// 遍历数组,查看是否存在;如果存在,就返回值
console.info('set-array-find', set_exist, array_exist);
// 改
set.forEach(item => item.t ? item.t=2 :'');
array.forEach(item => item.t ? item.t=2 :'');
console.info('set-array-modify', set, array);
// 删(set和array删除都相对麻烦)
set.forEach(item => item.t ? set.delete(item) : '');
let index = array.findIndex(item => item.t);
array.splice(index, 1);
console.info('set-array-remove', set, array);
}
{
// set map 和 object 对比
let item = {t:1};
let map = new Map();
let set = new Set();
let obj = {};
// 增
map.set('t',1);
set.add(item);
obj['t'] = 1;
console.info('map-set-obj', obj, map, set);
// 查(obj不如map和set语义化)
console.info({
map_find:map.has('t'),
set_find:set.has(item),
obj_find:'t' in obj
});
// 改
map.set('t',2);
item.t = 2;
obj['t'] = 2;
console.log('map-set-obj-modify', obj, map, set);
// 删(set和array删除都相对麻烦)
map.delete('t');
set.delete(item);
delete obj['t'];
console.log('map-set-obj-remove', obj, map, set);
}
3.12 Proxy 和 Reflect(案例:lesson12-proxy-reflect.js)
Proxy代理,代理商:用户 和 商家(连接了用户和最真实对象的一个层)
Reflect反射
{
// 供应商 原始对象,存储真实数据
let obj = {
time:'2017-03-11',
name:'net',
_r:123
};
// 代理商
let monitor = new Proxy(obj, {
// 拦截(代理)对象属性的读取
get(target, key){
// target相当于obj
// console.log(target);
// 把2017替换成2018
return target[key].replace('2017','2018');
},
// 拦截对象设置属性
set(target, key, value){
if(key === 'name'){
return target[key] = value
}else {
return target[key];
}
},
// 拦截key in object 操作
has(target, key){
if(key === 'name'){
return target[key]
}else{
return false;
}
},
// 拦截delete
deleteProperty(target,key){
if(key.indexOf('_') > -1){
delete target[key];
return true;
}else{
return target[key];
}
},
// 拦截Object.keys, Object.getOwnPropertySymbols, Object.getOwnPropertyNames
// 保护time的key不被用户看到
ownKeys(target){
return Object.keys(target).filter(item=>item!='time')
}
});
console.log('get', monitor.time); // 2018-03-11
monitor.time = '2019';
monitor.name = 'hjy';
console.log('set',monitor.time); // 2018-03-11
console.log('set',monitor.name); // hjy
// time被拦截了 true false
console.log('has','name' in monitor, 'time' in monitor);
// 对象依旧存在
// delete monitor.time;
// console.log('delete', monitor);
// 成功的删掉_r
// delete monitor._r;
// console.log('delete', monitor);
console.log('ownKeys',Object.keys(monitor));
}
{
let obj = {
time:'2017-03-11',
name:'net',
_r:123
};
// 读取time的值
console.log('Reflect get', Reflect.get(obj,'time')); // 2017-03-11
// 把name改成hjy
Reflect.set(obj, 'name', 'hjy');
console.log(obj); // {time: "2017-03-11", name: "hjy", _r: 123}
// 判断obj里是否有name
console.log('has',Reflect.has(obj,'name')); // true
}
{
function validator(target, validator) {
// 对target进行代理
return new Proxy(target,{
// 保存配置选项
_validator:validator,
// 对set进行修改
set(traget,key,value,proxy){
if(target.hasOwnProperty(key)){
let va = this._validator[key];
if(!!va(value)){
return Reflect.set(target,key,value,proxy);
}else{
throw Error(`不能设置${key}到${value}`)
}
}else{
throw Error(`${key} 不存在`)
}
}
})
}
const personValidators={
name(val){
return typeof val === 'string'
},
age(val){
return typeof val === 'number' && val > 18
}
};
class Person{
constructor(name,age){
this.name = name;
this.age = age;
return validator(this,personValidators)
}
}
const person = new Person('hjy',30);
console.log(person);
// 不能设置数字
// person.name = 48;
person.name = 'oli';
console.log(person);
}
3.13 类 和 对象(案例:lesson13-class.js)
类的概念:基本语法、类的继承、静态方法、静态属性、getter、setter
{
// 基本定义和生成实例
class Parent{
// 构造函数
constructor(name='hjy'){
this.name = name;
}
}
let v_parent = new Parent('v');
let v_parent2 = new Parent();
// {name: "v"}
console.log('构造函数和实例',v_parent);
// {name: "hjy"}
console.log('构造函数和实例',v_parent2);
}
{
// 继承
class Parent{
// 构造函数
constructor(name='hjy'){
this.name = name;
}
}
class Child extends Parent{
}
// {name: "hjy"}
console.log('继承', new Child());
}
{
// 继承传递参数
class Parent{
// 构造函数
constructor(name='hjy'){
this.name = name;
}
}
class Child extends Parent{
constructor(name='child'){
// 修改父类的参数(要把super放在第一行)
super(name);
// 子类增加自己的属性
this.type='childType';
}
}
// {name: "lio", type: "childType"}
console.log('子类向父类传递参数', new Child('lio'));
}
{
// getter setter
class Parent{
// 构造函数
constructor(name='hjy'){
this.name = name;
}
get longName(){
return '姓名:' + this.name
}
set longName(value){
this.name = value;
}
}
let v = new Parent();
// hjy
console.log('getter',v.longName);
v.longName='lio';
// lio
console.log('setter',v.longName);
}
{
// 静态方法(通过类调用,而不是通过类的实例去调用)
class Parent{
// 构造函数
constructor(name='hjy'){
this.name = name;
}
// 静态方法
static tell(){
console.log('tell');
}
}
// tell
Parent.tell();
}
{
// 静态属性
class Parent{
// 构造函数
constructor(name='hjy'){
this.name = name;
}
// 静态方法(不能定义静态属性)
static tell(){
console.log('tell');
}
}
// 静态属性
Parent.type = 'test';
// tell
console.log('静态属性',Parent.type);
}
3.14 Promise(案例:lesson14-promise.js)
异步编程的解决方法
A执行完再执行B,两种实现方式:回调、事件触发
{
// es5回调解决异步操作
let ajax = function (callback) {
console.log('执行');
setTimeout(function () {
// 判断回调是不是存在,如果存在,执行下一步
callback && callback.call()
},1000)
};
ajax(function () {
console.log('timeout1');
});
}
{
// es6
let ajax = function () {
console.log('执行2');
// 返回一个Promise实例(执行下一步功能)
// resolve执行下一步操作
// reject中断下一步操作
return new Promise(function (resolve,reject) {
setTimeout(function () {
resolve();
},1000);
})
};
ajax().then(function () {
console.log('promise','timeout2');
})
}
{
// A执行完再执行B,B执行完了执行C ...
let ajax = function () {
console.log('执行3');
// 返回一个Promise实例(执行下一步功能)
// resolve执行下一步操作
// reject中断下一步操作
return new Promise(function (resolve,reject) {
setTimeout(function () {
resolve();
},1000);
})
};
ajax().then(function () {
return new Promise(function (resolve,reject) {
// 又可以下一步
resolve();
},2000)
}).then(function () {
console.log('timeout3');
})
}
{
// catch捕获错误
let ajax = function (num) {
console.log('执行4');
return new Promise(function (resolve,reject) {
// 如果大于5,执行下一步
if(num > 5){
resolve();
}else{
// 抛出错误
throw new Error('出错了');
}
})
};
ajax(6).then(function () {
console.log('log',6);
}).catch(function (err) {
console.log('catch',err);
});
ajax(3).then(function () {
console.log('log',3);
}).catch(function (err) {
console.log('catch',err);
})
}
{
// 所有图片加载完再添加到页面
function loadImg(src) {
return new Promise((resolve,reject) => {
let img = document.createElement('img');
img.src = src;
// 图片加载完
img.onload=function () {
resolve(img);
};
// 图片加载失败
img.onerror = function (err) {
reject(err);
};
})
}
function showImgs(imgs) {
imgs.forEach(function (img) {
document.body.appendChild(img);
})
}
// all:把多个Promise实例当成一个Promise实例
Promise.all([
// 三张图片都加载完,才会触发all,才执行then
loadImg('http://myoli.xin/public/images/banner.jpg'),
loadImg('http://myoli.xin/public/images/banner.jpg'),
loadImg('http://myoli.xin/public/images/banner.jpg')
]).then(showImgs)
}
{
// 有一个图片加载完成添加到页面
function loadImg(src) {
return new Promise((resolve,reject) => {
let img = document.createElement('img');
img.src = src;
// 图片加载完
img.onload=function () {
resolve(img);
};
// 图片加载失败
img.onerror = function (err) {
reject(err);
};
})
}
function showImgs(img) {
let p = document.createElement('p');
p.appendChild(img);
document.body.appendChild(p)
}
// 三张图片,只要有一个图片加载出来,那个就先显示在页面上
Promise.race([
loadImg('http://myoli.xin/public/images/banner.jpg'),
loadImg('http://myoli.xin/public/images/banner.jpg'),
loadImg('http://myoli.xin/public/images/banner.jpg')
]).then(showImgs)
}
3.15 Iterator(案例:lesson15-iterator.js)
操作数组、object、map、set
{
let arr = ['hello','world'];
let map = arr[Symbol.iterator]();
// {value: "hello", done: false}
console.log(map.next());
// {value: "world", done: false}
console.log(map.next());
// {value: undefined, done: true} true代表没有下一步
console.log(map.next());
}
{
// 自定义iterator接口
// obj数据是我们自己填充
let obj = {
start:[1,3,2],
end:[7,9,8],
// Symbol.iterator变量名
[Symbol.iterator](){
let self = this;
// 记录当前遍历索引
let index = 0;
// start和end合并成一个数组
let arr = self.start.concat(self.end);
// 记录数组的长度
let len = arr.length;
return {
next(){
if(index < len){
return {
value:arr[index++],
done:false
}
} else {
return {
value:arr[index++],
done:true
}
}
}
}
}
}
for(let key of obj){
console.log(key);
}
}
{
// 对数组进行遍历
let arr = ['hello','world'];
for(let value of arr){
// hello
// world
console.log('value',value);
}
}
3.16 Generator(案例:lesson16-decorators.js)
异步编程的一种解决方案
{
// genertaor基本定义
// 与普通的函数不同:* 、 yield
let tell = function* () {
yield 'a';
yield 'b';
return 'c';
};
// 调用tell,执行到第一个yield停止下来
let k = tell();
// 执行第一个yield
// {value: "a", done: false}
console.log(k.next());
// 执行第二个yield
// {value: "b", done: false}
console.log(k.next());
// 执行retrun
// {value: "c", done: true}
console.log(k.next());
// {value: undefined, done: true}
console.log(k.next());
}
{
// of遍历
let obj = {
};
obj[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
};
for(let value of obj){
// 1
// 2
// 3
console.log('value',value);
}
}
{
let state = function* () {
while(1){
yield 'A';
yield 'b';
yield 'c';
}
}
let status = state();
// {value: "A", done: false}
// {value: "b", done: false}
// {value: "c", done: false}
// {value: "A", done: false}
// {value: "b", done: false}
console.log(status.next());
console.log(status.next());
console.log(status.next());
console.log(status.next());
console.log(status.next());
}
{
// 抽奖
let draw = function (count) {
// 具体抽奖逻辑
console.info(`剩余${count}次`);
};
let residue = function* (count) {
while (count > 0){
count--;
yield draw(count);
}
};
// 可以抽奖5次,如果是最后一次,点击无效
let star = residue(5);
let btn = document.createElement('button');
btn.id = 'start';
btn.textContent = '抽奖';
document.body.appendChild(btn);
document.getElementById('start').addEventListener('click',function () {
star.next();
},false)
}
{
// 长轮询(接口请求失败,一直请求)
let ajax = function* () {
yield new Promise(function (resolve,reject) {
// 接口
setTimeout(function () {
resolve({code:0})
},200);
})
};
let pull = function () {
let genertaor = ajax();
let step = genertaor.next();
step.value.then(function (d) {
if(d.code != 0){
setTimeout(function () {
console.log('wait');
pull();
},1000);
}else{
console.log(d);
}
})
};
pull();
}
3.17 Decorator(案例:lesson17-decorators.js)
修饰器:是一个函数,修改类的行为(扩展类的动能,只在类里修改有用)
{
// 是一个函数
let readonly = function (target, name, descriptor) {
descriptor.writable = false;
return descriptor
};
// 修改类的行为
class Test{
// 加了修饰器,就是不能重新修改参数;只有只读的状态
// @readonly与上面的readonly要一致
@readonly
time(){
return '2017-03-11'
}
}
let test = new Test();
// 加了修饰器,就是不能重新修改参数;只有只读的状态
// 报错
// test.time = function () {
// console.log('reset name')
// }
// 2017-03-11
console.log(test.time())
}
{
let typename = function (target,name,descriptor) {
// 静态属性
target.myname = 'hello';
};
// 修饰器(对类进行修饰)
@typename
class Test{
}
console.log('类修饰符',Test.myname); // hello
// 第三方库修饰器的js库:core-decorators; npm install core-decorators
}
{
// 看广告是show还是click
let log = (type) => {
return function (target,name,descriptor) {
let src_method = descriptor.value;
// 方法重新赋值
descriptor.value=(...arg)=>{
src_method.apply(target,arg);
console.info(`log ${type}`);
}
}
}
class AD{
@log('show')
show(){
console.info('ad is show');
}
@log('click')
click(){
console.info('ad is click');
}
}
// 实例化
let ad = new AD();
ad.show();
ad.click();
}
3.18 模块化(案例:lesson18-module.js)
let A = 123;
let test = function () {
console.log('test');
}
class Hello{
test(){
console.log('class');
}
}
export default {
A,
test,
Hello
}
// 模块化:导入所有 lesson只是一个别名
import * as lesson from './class/lesson18-module';
console.log(lesson.A);
console.log(lesson.test);
import Lesson18 from './class/lesson18-module';
console.log(Lesson18.A);
网友评论