欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 创投人物 > es6语法

es6语法

2024/11/29 9:30:57 来源:https://blog.csdn.net/weixin_62831076/article/details/142684444  浏览:    关键词:es6语法

es6语法

let和const命令

let

  1. let声明的变量,只在let命令所在的代码块内有效
{let a = 10;var b = 20;
}
console.log(a); //a is not defined
console.log(b); //20

2.不存在遍历提升现象

var命令会发生变量提升现象,即变量可以在声明之前使用,值为undefined

let声明的变量一定要在声明后使用,否则会报错

//var的情况
console.log(c);//输出undefined
var c = 30;//let的情况
console.log(c);// 报错ReferenceError
let c = 30;

3.不允许重复声明

let在相同作用域内,重复声明同一个变量会报错

let c = 10;
let c = 30;
console.log(c); //报错function func(arg) {let arg; // 报错
}

4.暂时性死区

只要块级作用域内存在let命令,它所声明的变量就“绑定”这个区域,不再受外部的影响

if (true) {// TDZ开始tmp = 'abc'; // ReferenceErrorconsole.log(tmp); // ReferenceErrorlet tmp; // TDZ结束console.log(tmp); // undefinedtmp = 123;console.log(tmp); // 123
}

较隐蔽的暂时性死区

//function bar(x = y, y = 2) {// return [x, y];
//}//bar(); // 报错
function bar(x = 2, y = x) {return [x, y];
}
bar(); // [2, 2]

块级作用域

为什么需要块级作用域?

原因一:内层变量可能会覆盖外层变量

function foo(a){console.log(a);if(1===2){var a = 'hello ';}
}
var a = 10;
foo(a);

原因二:用来计数的循环遍历泄露为全局变量

var arr = []
for(var i = 0; i < 10; i++){arr[i] = function(){return i;}
}
console.log(arr[5]());//10

变量i只用来控制循环,但是循环结束后,它并没有消失,用于变量提升,泄露成了全局变量

解决循环计数问题

//解决方式一:使用闭包
var arr = []
for(var i = 0; i < 10; i++){arr[i] = (function(n){return function(){return n;}})(i)
}
//解决方式二:使用let声明ivar arr = []
for(let i = 0; i < 10; i++){arr[i] = function () {return i;}
}

const

声明一个只读的常量。一旦声明,常量的值就不能改变

const a = 10;
a = 20;//报错const b; //报错

const其本质并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动

const foo = {};// 为 foo 添加一个属性,可以成功
foo.prop = 123;
foo.prop // 123// 将 foo 指向另一个对象,就会报错
foo = {}; // TypeError: "foo" is read-only

默认情况下建议使用const,当知道变量值需要被修改时再改为let即可

模板字符串

传统的 JavaScript 语言,输出模板通常是这样写的

let name = "Kimi";
let greeting = "Hello, " + name + "!";
console.log(greeting); // 输出: Hello, Kimi!

上面的这种写法相当繁琐不方便,ES6引入了模板字符串解决这个问题

let name = "Kimi";
let greeting = `Hello, ${name}!`;
console.log(greeting); // 输出: Hello, Kimi!

解构赋值

数组解构

  • 将数组的单元值快速批量赋值给一系列变量
<script>// 普通的数组let arr = [1, 2, 3]// 批量声明变量 a b c // 同时将数组单元值 1 2 3 依次赋值给变量 a b clet [a, b, c] = arrconsole.log(a); // 1console.log(b); // 2console.log(c); // 3
</script>
  • 数组解构细节
<script>// const pc = ['海尔', '联想', '小米', '方正'];// [hr, lx, mi, fz] = pc// console.log(hr, lx, mi, fz);// function getValue() {//   return [100, 60]// }// [max, min] = getValue()// console.log(max, min);// const pc = ['海尔', '联想', '小米', '方正']// const [hr, lx, mi, fz] = ['海尔', '联想', '小米', '方正']// console.log(hr)// console.log(lx)// console.log(mi)// console.log(fz)// // 请将最大值和最小值函数返回值解构 max 和min 两个变量// function getValue() {//   return [100, 60]// }// const [max, min] = getValue()// console.log(max)// console.log(min)// 1. 变量多, 单元值少 , undefined// const [a, b, c, d] = [1, 2, 3]// console.log(a) // 1// console.log(b) // 2// console.log(c) // 3// console.log(d) // undefined// 2. 变量少, 单元值多// const [a, b] = [1, 2, 3]// console.log(a) // 1// console.log(b) // 2// 3.  剩余参数 变量少, 单元值多// const [a, b, ...c] = [1, 2, 3, 4]// console.log(a) // 1// console.log(b) // 2// console.log(c) // [3, 4]  真数组// 4.  防止 undefined 传递// const [a = 0, b = 0] = [1, 2]// const [a = 0, b = 0] = []// console.log(a) // 1// console.log(b) // 2// 5.  按需导入赋值// const [a, b, , d] = [1, 2, 3, 4]// console.log(a) // 1// console.log(b) // 2// console.log(d) // 4// const arr = [1, 2, [3, 4]]// console.log(arr[0])  // 1// console.log(arr[1])  // 2// console.log(arr[2])  // [3,4]// console.log(arr[2][0])  // 3// 多维数组解构// const arr = [1, 2, [3, 4]]// const [a, b, c] = [1, 2, [3, 4]]// console.log(a) // 1// console.log(b) // 2// console.log(c) // [3,4]const [a, b, [c, d]] = [1, 2, [3, 4]]console.log(a) // 1console.log(b) // 2console.log(c) // 3console.log(d) // 4</script>

注意: js 前面必须加分号情况

在这里插入图片描述

1.立即执行函数

在这里插入图片描述

2.数组解构

在这里插入图片描述

对象解构

  • 将对象属性和方法快速批量赋值给一系列变量
<script>// 普通对象const user = {name: '小明',age: 18};//以前用法//console.log(obj.name)// 批量声明变量 name age// 同时将数组单元值 小明  18 依次赋值给变量 name  ageconst {name, age} = user//解构之后name、age就可以直接用了,不需要对象.属性来使用了console.log(name) // 小明console.log(age) // 18
</script>

多级对象解构:

 <script>// const pig = {//   name: '佩奇',//   family: {//     mother: '猪妈妈',//     father: '猪爸爸',//     sister: '乔治'//   },//   age: 6// }// // 多级对象解构// const { name, family: { mother, father, sister } } = pig// console.log(name)// console.log(mother)// console.log(father)// console.log(sister)const person = [{name: '佩奇',family: {mother: '猪妈妈',father: '猪爸爸',sister: '乔治'},age: 6}]const [{ name, family: { mother, father, sister } }] = personconsole.log(name)console.log(mother)console.log(father)console.log(sister)</script>

函数参数的解构

function add([x, y]){return x + y;
}add([1, 2]); // 3

使用默认值:

function addCart(n,num=0){return n+num;
}
addCart(10);//10
addCart(10,20); //30

用途:

1.从函数返回多个值

函数只能返回一个值,若要返回多个值,只能放在数组或对象中返回

// 返回一个数组function example() {return [1, 2, 3];
}
let [a, b, c] = example();// 返回一个对象function example() {return {foo: 1,bar: 2};
}
let { foo, bar } = example();

2.函数参数的定义

解构赋值可以方便地将一组参数与变量名对应起来

// 参数是一组有次序的值
// function f([x, y, z]) { 
//     console.log(x,y,z);//1 2 3
//  }
// f([1, 2, 3]);// 参数是一组无次序的值
function f({x, y, z}) {console.log(x,y,z);//1 2 3
}
f({z: 3, y: 2, x: 1});

3.提取JSON数据

解构赋值对提取 JSON 对象中的数据,尤其有用

let jsonData = {id: 42,status: "OK",data: [867, 5309]
};let { id, status, data: number } = jsonData;
//对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者
console.log(id, status, number);
// 42, "OK", [867, 5309]

4.输入模块的指定方法

加载模块时,往往需要指定输入哪些方法→解构赋值使得输入语句非常清晰。

const {ajax} = require('xxx')ajax()

函数扩展

函数参数

默认值

ES6之前,不能直接为函数的参数指定默认值,只能采用变通的方法

function log(x,y){y = y || 'world';console.log(x,y);
}
log('hello');//hello world
log('hello','china') //hello china
log('hello','')//hello world

ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面。

function log(x, y = 'World') {console.log(x, y);
}log('Hello') // Hello World
log('Hello', 'China') // Hello China
log('Hello', '') // Hello
默认的表达式可以是一个函数*
function getVal(val) {return val + 5;
}
function add2(a, b = getVal(5)) {return a + b;
}
console.log(add2(10));
练习
// 写法一
function m1({x = 0, y = 0} = {}) {return [x, y];
}// 写法二
function m2({x, y} = { x: 0, y: 0 }) {return [x, y];
}

以上两种写法的区别:都对函数的参数设定了默认值;区别:写法一函数参数默认值为空对象,但设置了对象解构赋值的默认值;写法二函数参数默认值为一个具体属性的对象,但没有设置对象解构赋值的默认值

// 函数没有参数的情况
m1() // [0, 0]
m2() // [0, 0]// x 和 y 都有值的情况
m1({x: 3, y: 8}) // [3, 8]
m2({x: 3, y: 8}) // [3, 8]// x 有值,y 无值的情况
m1({x: 3}) // [3, 0]
m2({x: 3}) // [3, undefined]// x 和 y 都无值的情况
m1({}) // [0, 0];
m2({}) // [undefined, undefined]m1({z: 3}) // [0, 0]
m2({z: 3}) // [undefined, undefined]

剩余参数

ES6引入了rest参数(形式为…变量名),用于获取函数的多余参数,主要是为了解决arguments的问题。

按照ES5的写法,如果不确定用户传几个参数,我们肯定是使用arguments(动态参数)伪数组来接收

let book = {title: '学前端',name: 'zcy',age: 18
}function pick(obj) {let result = {};for (let i = 1; i < arguments.length; i++) {result[arguments[i]] = obj[arguments[i]];}return result;
}
let bookData = pick(book, 'title', 'name', 'age');
console.log(bookData);

但在es6中,我们可以获取一个真正的数组。

let book = {title: '学前端',name: 'zcy',age: 18
}function pick(obj, ...args) {console.log(args);  //['title', 'name', 'age']let result = {}; // 定义一个空对象for (let i = 0; i < args.length; i++) {//把对象中的属性值拿过来,给空对象(如果该对象没有这个属性,那么就添加一个)result[args[i]] = obj[args[i]];}return result;
}
let bookData = pick(book, 'title', 'name', 'age');
console.log(bookData);

展开运算符

将一个数组(或对象)分割,并将数组的各个项作为分离的参数传给函数。其实就是把数组或对象拆开

应用场景:

1、比如我要获取数组的最大值,以前我们会使用apply

const arr = [123, 545, 34, 234, 5];
console.log(Math.max.apply(null, arr));

但是现在我们可以这样写

const arr = [123, 545, 34, 234, 5];
console.log(Math.max(...arr));

2、其实也可以把对象里的东西拆开

let obj1 = {x:100, y:200};
let obj2 = {a:1,...obj1,b:2
}
console.log(obj2);  //{a: 1, x: 100, y: 200, b: 2}

箭头函数

基本用法

在ES5中这样定义函数

let f = function(v){return v;
}

在ES6允许使用箭头=>定义函数

let f = v=>v;
//等同于
let f = function(v){return v;
}// 有一个参数
let add = value => value;// 有两个参数
let add = (value,value2) => value + value2;let add = (value1,value2)=>{return value1 + value2;
} 
// 无参数
let fn = () => "hello world";let doThing = () => {}
//如果箭头函数直接返回一个对象,必须在对象外面加上括号,否则会报错。
let getId = id => ({id: id,name: 'mjj'}) //注意
let obj = getId(1);
对象中的箭头函数

如一个Person对象,里面有eat方法:

let person = {name: "jack",// 以前:eat: function (food) {console.log(this.name + "在吃" + food);},// 箭头函数版:eat2: food => console.log(person.name + "在吃" + food),// 这里拿不到this// 简写版:eat3(food){console.log(this.name + "在吃" + food);}
}
箭头函数this指向

在这里插入图片描述

  • 箭头函数中并不存在this!!!,内部this只能通过查找作用域链来确定
  • 箭头函数默认帮我们绑定外层this的值,所有在箭头函数中this值和外层this是一样的
  • 箭头函数的this引用的就是最近作用域的this
<body><script>// 以前this的指向:  谁调用的这个函数,this 就指向谁// console.log(this)  // window// // 普通函数// function fn() {//   console.log(this)  // window// }// window.fn()// // 对象方法里面的this// const obj = {//   name: 'andy',//   sayHi: function () {//     console.log(this)  // obj//   }// }// obj.sayHi()// 2. 箭头函数的this  是上一层作用域的this 指向// const fn = () => {//   console.log(this)  // window// }// fn()// 对象方法箭头函数 this// const obj = {//   uname: 'pink老师',//   sayHi: () => {//     console.log(this)  // this 指向谁? window//   }// }// obj.sayHi()const obj = {uname: 'pink老师',sayHi: function () {console.log(this)  // objlet i = 10const count = () => {console.log(this)  // obj }count()}}obj.sayHi()</script>
</body>
let PageHandler = {id:123,init:function(){document.addEventListener('click',function(event) {this.doSomeThings(event.type);},false);},doSomeThings:function(type){console.log(`事件类型:${type},当前id:${this.id}`);}
}
PageHandler.init();//解决this指向问题
let PageHandler = {id: 123,init: function () {// 使用bind来改变内部函数this的指向document.addEventListener('click', function (event) {this.doSomeThings(event.type);}.bind(this), false);},doSomeThings: function (type) {console.log(`事件类型:${type},当前id:${this.id}`);}
}
PageHandler.init();let PageHandler = {id: 123,init: function () {// 箭头函数没有this的指向,箭头函数内部的this值只能通过查找作用域链来确定// 如果箭头函数被一个非箭头函数所包括,那么this的值与该函数的所属对象相等,否 则是全局的window对象document.addEventListener('click', (event) => {console.log(this);this.doSomeThings(event.type);}, false);},doSomeThings: function (type) {console.log(`事件类型:${type},当前id:${this.id}`);}
}
PageHandler.init();
箭头函数参数

箭头函数中没有 arguments,只能使用 ... 动态获取实参

<body><script>// 1. 利用箭头函数来求和const getSum = (...arr) => {let sum = 0for (let i = 0; i < arr.length; i++) {sum += arr[i]}return sum}const result = getSum(2, 3, 4)console.log(result) // 9</script>
</body>
箭头函数的作用
  • 使表达更加简洁

     代码解读
    复制代码const isEven = n => n % 2 == 0;
    const square = n => n * n;
    
  • 简化回调函数

     代码解读
    复制代码// 正常函数写法
    [1,2,3].map(function (x) {return x * x;
    });// 箭头函数写法
    [1,2,3].map(x => x * x);
    

注意:

1.箭头函数它不是一个对象,可认为是一个表达式或语法条

2.箭头不能使用使用new关键字来实例化对象

 代码解读
复制代码let Person = ()=>{}
let p1 = new Person();// Person is not a constructor

##对象扩展

基本用法

const name = '张三';
const age = 19;
const person = {name, //等同于name:nameage,// 方法也可以简写sayName() {console.log(this.name);}
}
person.sayName();

这种写法用于函数的返回值,将会非常方便。

function getPoint() {const x = 1;const y = 10;return {x, y};
}getPoint()
// {x:1, y:10}
对象扩展运算符
const [a, ...b] = [1, 2, 3];
a // 1
b // [2, 3]

...)用于取出参数对象的所有可遍历属性,拷贝到当前对象之中。

 代码解读
复制代码let z = { a: 3, b: 4 };
let n = { ...z };
n // { a: 3, b: 4 }

数组扩展

扩展运算符-替代apply()方法

由于扩展运算符可以展开数组,所以不再需要apply()方法将数组转为函数的参数了

// ES5 的写法
function f(x, y, z) {// ...
}
var args = [0, 1, 2];
f.apply(null, args);// ES6 的写法
function f(x, y, z) {// ...
}
let args = [0, 1, 2];
f(...args);

例子1:应用Math.max()方法,简化求出一个数组最大元素

// ES5 的写法
Math.max.apply(null, [14, 3, 77])// ES6 的写法
Math.max(...[14, 3, 77])// 等同于
Math.max(14, 3, 77);

例子2

// ES5 的写法
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
Array.prototype.push.apply(arr1, arr2);// ES6 的写法
let arr1 = [0, 1, 2];
let arr2 = [3, 4, 5];
arr1.push(...arr2);

from()将伪数组转换为真数组

1.将arguments转换为一个真数组

function add() {let arr = Array.from(arguments);console.log(arr);  //[1, 2, 3]
}
add(1, 2, 3);

2.比如ul里面的好多li的数组集合,转换为真正的数组

<body><ul><li>1</li><li>2</li><li>3</li></ul><script>//  Array.from(lis) 把伪数组转换为真数组const lis = document.querySelectorAll('ul li')// console.log(lis)// lis.pop() 报错const liss = Array.from(lis)liss.pop()console.log(liss)</script>
</body>

也可直接用展开运算符

console.log([...lis]);  // [li, li, li, li]

3.from()还可以有第二个参数(可选),是一个映射函数→允许你在将每个元素添加到新数组时对其进行处理。

语法:

Array.from(arrayLike[, mapFn[, thisArg]])
//arrayLike:一个类似数组的对象
//mapFn(可选):一个映射函数,用于在将元素添加到新数组时对其进行处理
//thisArg(可选):执行映射函数时使用的 this 值

示例:

// 使用字符串创建数组
let str='hello'
// 字符串是一个可迭代对象,因为它具有length属性,且可以通过索引访问每个字符
// Array.from()遍历字符串的每个字符→从索引0-索引4→每个字符("H", "e", "l", "l", "o")被依次添加到新数组
let arr=Array.from(str)
console.log(arr);//输出:['h', 'e', 'l', 'l', 'o']// 使用映射函数对每个元素进行处理
//这个映射函数被调用时,当前元素作为第一个参数,当前元素的索引作为第二个参数
let squares = Array.from({length: 5}, (v, i) => i + 1);
console.log(squares); // 输出: [1, 2, 3, 4, 5]// 使用映射函数对数组的每个元素进行平方处理
let arr = [1, 2, 3, 4, 5];
let squared = Array.from(arr, x => x * x);
console.log(squared); // 输出: [1, 4, 9, 16, 25]

of()将任意数据类型转换为数组

console.log(Array.of('2', [2, 3], { 'a': 1 }, undefined));
//['2', Array(2), {…}, undefined]

find()findiIndex()

1.find()是找出数组中符合条件的第一个数组成员

const array = [1, 2, 3, 4, 5];
const found = array.find(element => element > 3);
console.log(found); // 输出: 4

2.findexIndex()是找出数组中符合条件的第一个数组成员的索引

const array = [1, 2, 3, 4, 5];const index = array.findIndex(element => element > 3);
console.log(index); // 输出: 3

数组中的keys()values()entries()遍历

它们都返回一个遍历器对象,可以用for…of循环进行遍历

  • keys() 用于获取数组索引的遍历
  • values() 用于获取数组值的遍历
  • entries() 用于获取数组键/值对的遍历
const array = ['a', 'b', 'c'];// 遍历键
for (let key of array.keys()) {console.log(key); // 输出: 0 然后是 1 然后是 2
}// 遍历值
for (let value of array.values()) {console.log(value); // 输出: 'a' 然后是 'b' 然后是 'c'
}// 遍历键/值对
for (let entry of array.entries()) {console.log(entry); // 输出: [0, 'a'] 然后是 [1, 'b'] 然后是 [2, 'c']
}

includes()判断某个元素是否在数组中

用于判断一个数组是否包含一个特定的值,根据情况,它能够返回 truefalse

const array = [1, 2, 3, 4, 5];// 检查数组是否包含值 3
console.log(array.includes(3)); // 输出: true// 检查数组是否包含值 6
console.log(array.includes(6)); // 输出: false// 使用 fromIndex 选项
console.log(array.includes(2, 3)); // 输出: false,因为在索引 3 之后找不到值 2

Symbol类型

  • 唯一性:每个通过 Symbol() 创建的符号都是唯一的,即便描述(description)相同,创建的符号也不同。
  • 不可变Symbol 值是不可改变的。
  • 不可枚举:使用 Symbol 定义的属性不会出现在对象的 for...inObject.keys()、或 JSON.stringify() 等操作中。
<script>// 原始数据类型Symbol,它表示独一无二的值// 最大用途:用来定义对象的私有变量const name=Symbol('name')const name2=Symbol('name')console.log(name===name2);//falselet s1=Symbol('s1')console.log(s1);//Symbol(s1)let obj={[s1]:'学前端'}// obj[s1]='学前端'// console.log(obj);//{Symbol(s1): '学前端'}// console.log(obj[s1]);//学前端// 获取Symbol声明的属性let m=Object.getOwnPropertySymbols(obj)console.log(m[0]);//Symbol(s1)let s=Reflect.ownKeys(obj)console.log(s[0]);</script>

Set和Map数据结构

set

<script>// 集合:表示无重复值的有序列表let set =new Set()console.log(set);//Set(0) {size: 0}// 添加元素set.add(2)set.add(4)set.add('4')set.add(['hello','hi','fine'])// 删除元素set.delete(2)// 校验某个值是否在set中console.log( set.has(4));console.log( set.size);// 将set转换成数组let set2=new Set([1,2,3,5,6,3])console.log(set2);//Set(5) {1, 2, 3, 5, 6}// 扩展运算符let arr=[...set2]console.log(arr);//[1, 2, 3, 5, 6]// 1.set中对象的引用无法被释放// let set3=new Set(),obj={}// set3.add(obj)// // 释放当前的资源// obj=null// console.log(set3);// 2.通过弱引用可被释放let set4=new WeakSet(),obj={}set4.add(obj)// 释放当前资源obj=nullconsole.log(set4);
</script>

map

<script>// Map类型是键值对的有序列表,键和值是任意类型// let map=new Map()// map.set('name','张三')// map.set('age',20)// console.log(map.get('name'));// console.log(map.delete('name'));// console.log(map.clear());// map.set(['a',[1,2,3],'hello'])// console.log(map);
</script>

proxy和Reflect

proxy

监听对象属性

在之前,若希望监听一个对象的相关操作,可通过Object.defineProperty 的存储属性来进行监听,它必须去深度遍历对象里的每一个属性

<script>const obj={name:'why',age:18,height:1.88}// 需求:监听对象属性的所有操作// 监听属性的操作// 1.只针对一个属性// let _name=obj.name// Object.defineProperty(obj,'name',{//   set: function(newValue){//     console.log("监听:给name设置了新值:",newValue);//     _name=newValue//   },//   get: function(){//     console.log("监听:获取name的值");//     return _name//   }// })// 2.监听所有的属性:遍历所有的属性,对每一个属性使用definePropertyconst keys=Object.keys(obj)for(const key of keys){let value=obj[key]Object.defineProperty(obj,key,{set: function(newValue){console.log(`监听:给${key}设置了新值`,newValue);value=newValue},get: function(){console.log(`监听:获取${key}的值`);return value}})}console.log(obj.name);console.log(obj.age);obj.name='zcy'obj.age=21</script>

缺点:

1.其设计初衷既不是为了去监听一个完整的对象

2.目前我们只能用它监听属性的设置和获取,不能监听增加和删除

在ES6中,新增了一个Proxy类,就是为了我们监听另外一个对象而生的

先创建一个代理对象,之后对该对象的所有操作,都通过代理对象完成,代理对象可监听我们想要原对象进行哪些操作

 <script>const obj={name:'why',age:18,height:1.88}// 1.创建一个代理对象const proxy = new Proxy(obj,{set:function(target,key,newValue){console.log(`监听:监听${key}的设置值:`,newValue);target[key]=newValue},get:function(target,key){console.log(`监听:监听${key}的获取`);return target[key]}})// 对obj的所有操作,应该去操作objProxyconsole.log(proxy.name);//whyproxy.name='zcy'console.log(proxy.name);//zcy// 新增proxy.address='广州'</script>
其它捕获器的监听

在这里插入图片描述

代码实例:

 <script>const obj={name:'why',age:18,height:1.88}// 1.创建一个代理对象const proxy = new Proxy(obj,{set:function(target,key,newValue){console.log(`监听:监听${key}的设置值:`,newValue);target[key]=newValue},get:function(target,key){console.log(`监听:监听${key}的获取`);return target[key]},deleteProperty:function(target,key){const deleted = delete target[key]console.log(`监听:监听删除${key}属性,删除操作结果:${deleted}`);return delete target[key]},has:function(target,key){console.log(`监听:监听in判断${key}属性`);return key in target}})// deletedelete proxy.name;// hasconsole.log("age"in proxy);</script>

Reflect

提供许多操作JavaScript对象的方法,有点像Object中操作对象的方法

已经有Object,那为啥还需要Reflect嘞?

1.由于早期ECMA规范并未考虑到对象本身的操作如何设计更加规范,故将这些API放在Object身上

2.Object作为一个构造函数,这些操作实际上放到它身上并不太合适

3.ES6中新增Reflect,让这些操作集中到Reflext身上

reflect和Object的区别之一

<script>"use strict"const obj={name:'acy',age:18}Object.defineProperty(obj,'name',{configurable:false})// 1.用以前的方式进行操作// delete obj.name// if(obj.name){//   console.log('name删除成功');// }else{//   console.log('name没有删除成功');// }// 2.Reflectif(Reflect.deleteProperty(obj,'name')){console.log('name删除成功');}else{console.log('name没有删除成功');}</script>

Reflect和Proxy共同完成代理

<script>obj={name:'zcy',age:19}const proxy=new Proxy(obj,{set:function(target,key,newValue,receiver){// target[key]=newValue// 代理对象的目的:不再直接操作原对象// 1.好处一:代理对象的目的:不再直接操作原对象// 2.好处二:Reflect.set有返回布尔值,可以判断本次操作是否成功console.log(receiver);const isSuccess=Reflect.set(target,key,newValue)if(!isSuccess){throw new Error(`set ${key} failure`)}},get:function(target,key,receiver){}})console.log(obj);</script>

receiver的作用:

<script>obj={_name:'zcy',set name(newValue){console.log("this",this);this._name=newValue},get name(){return this._name}}const proxy=new Proxy(obj,{set:function(target,key,newValue,receiver){// target[key]=newValue// 代理对象的目的:不再直接操作原对象// 1.好处一:代理对象的目的:不再直接操作原对象// 2.好处二:Reflect.set有返回布尔值,可以判断本次操作是否成功// 3.好处三:receiver就是我们外面的proxy对象;Reflect.set、get的最后一个参数,可以决定对象访问器setter/getter的this指向// console.log(receiver);console.log('proxy设置方法被调用');const isSuccess=Reflect.set(target,key,newValue,receiver)if(!isSuccess){throw new Error(`set ${key} failure`)}},get:function(target,key,receiver){return Reflect.get(target,key,receiver)}})// 操作代理对象proxy.name='sss'
</script>

迭代器Iterator

  • 迭代器(Iterator)是一种允许你逐个访问一个数据集合中元素的接口。迭代器模式是一种设计模式,主要用于遍历一个聚合对象,如数组,或者某些类似数组的对象(例如 NodeList
  • 一个数据结构只要具有Symbol.iterator属性,就说明有interator接口,就可以被for...of遍历
<script>// Iterator// 是一种新的遍历机制,两个核心// 1.迭代器是一个接口,能快捷的访问数据,通过Symbol.iterator来创建迭代器 通过迭代器的next()获取迭代之后的结果// 2.迭代器是用于遍历数据结构的指针(数据库的游标)// 使用迭代const items=['one','two','three']// 1.创建新的迭代器const ite=items[Symbol.iterator]()console.log(ite.next());//{value: 'one', done: false} done→如果为false表示遍历继续,如果为true,表示遍历完成console.log(ite.next());//{value: 'two', done: false}console.log(ite.next());//{value: 'three', done: false}
</script>

生成器Generator

Generator函数的写法:function* fn() {yield},yield相当于return

Generator 函数的调用方法与普通函数一样,也是在函数名后面加上一对圆括号。不同的是,调用 Generator 函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象,也就是遍历器对象

yield

当每次调用next方法,内部指针就从函数头部或上次停下来的地方开始执行,直到遇到下一个yield表达式(或return语句)为止

即Generator 函数是分段执行的,yield表达式是暂停执行的标记,而next方法可以恢复执行

遍历器对象next方法的运行逻辑:

(1)遇到yield表达式,就暂停执行后面的操作,并将紧跟在yield后面的那个表达式的值,作为返回的对象的value属性值
(2)下一次调用next方法时,再继续往下执行,直到遇到下一个yield表达式
(3)如果没有再遇到新的yield表达式,就一直运行到函数结束,直到return语句为止,并将return语句后面的表达式的值,作为返回的对象的value属性值
(4)如果该函数没有return语句,则返回的对象的value属性值为undefined

function* fn() {console.log('start');yield 2;yield 'hello world';return 'end'
}
let gen = fn();
console.log(gen.next());  //{value: 2, done: false}
console.log(gen.next()); //{value: 'hello world', done: false}
console.log(gen.next());  //{value: 'end', done: true}
console.log(gen.next()); //{value: undefined, done: true}

Generator 函数可以不用yield表达式,此时会变成一个单纯的暂缓执行函数:

function* f() {console.log('执行了!')
}var generator = f();setTimeout(function () {generator.next()
}, 2000);

上面代码中,函数f如果是普通函数,在为变量generator赋值时就会执行。

但是,函数f是一个 Generator 函数,就变成只有调用next方法时,函数f才会执行

Generator和Iterator接口的关系

任何一个对象,只要有Symbol.iterator方法(iterator接口),就可以调用该方法生成一个遍历器(迭代器)对象;

若没有,可给当前对象赋值一个interator接口,再进行遍历

 // 使用场景:为不具备Interator接口的对象提供了遍历操作function* ObjectEntries(obj){// 获取对象所有属性名保存到数组[name,age]const propKeys=Object.keys(obj)for (const propKey of propKeys){yield[propKey,obj[propKey]]}}const obj={name:'acy',age:20}// 给当前对象赋值一个interator接口obj[Symbol.iterator]=ObjectEntriesconsole.log(obj);for(let [key,value] of ObjectEntries(obj)){console.log(`${key},${value}`);}

next方法的参数

yield表达式本身没有返回值,或者说总是返回undefined。next方法可以带一个参数,该参数就会被当作上一个yield表达式的返回值
如果不传参, 第二次不带参数,那么y = 2 * undefined = NaN,z = undefined / 3 = NaN,第三次不带参数,那么z = undefined, 返回5 + NaN + undefined = NaN
如果传参,那么第二次参数传给上一个yield也就是y = 2 * 12 = 24, value: 24 /3 = 8,第三次参数传给上一个yield也就是z = 13, value: 5 + 24 + 13 = 42

function* foo(x) {var y = 2 * (yield (x + 1));var z = yield (y / 3);return (x + y + z);
}var a = foo(5);
a.next() // Object{value:6, done:false}
a.next() // Object{value:NaN, done:false}  第二次不带参数,那么y=2*undefined=NaN,z=undefined/3 =NaN
a.next() // Object{value:NaN, done:true}   第三次不带参数,那么z=undefined, 返回5+NaN+undefined=NaNvar b = foo(5);
b.next() // { value:6, done:false }
b.next(12) // { value:8, done:false } //第二次参数传给上一个yield也就是y=2*12=24,value:24/3=8
b.next(13) // { value:42, done:true } //第三次参数传给上一个yield也就是z=13,value:5+24+13=42

示例代码:

<script>// 1.generator函数 可以通过yield关键字,将函数挂起,为改变执行流程提供了可能,也为异步变成提供方案// 2.它与普通函数的区别// 2.1function后面 函数名之前有个*// 2.2只能在函数内部使用yield表达式,让函数挂起function* func(a){console.log('one');yield 2;console.log('two');yield 3;console.log('end');}// console.log(func());// 返回一个遍历器对象 可以调用next方法// let fn=func()// console.log(fn.next());// console.log(fn.next());// console.log(fn.next());/* 总结:generator函数是分段执行的yield语句是暂停执行next()恢复执行*/function* add(){console.log('start');// x 不是yield '2' 的返回值,它是next()调用 恢复当前yield()执行传入的实参let x = yield '2'console.log('one:'+x);let y = yield '3'console.log('two:'+y);return x+y}const fn = add()console.log(fn.next());//{value: '2', done: false}console.log(fn.next(20));//{value: '3', done: false}console.log(fn.next(30));//{value: 50, done: true}
</script>

Promise对象

基础认识

  • 表示(管理)一个异步操作最终完成(或失败)及其结果值
  • 通过学习Promise,可以知道成功和失败状态,可以关联对应处理函数,了解 axios 内部运作的原理

在这里插入图片描述

Promise三种状态

每个 Promise 对象必定处于以下三种状态之一:

  1. 待定(pending):初始状态,既没有被兑现,也没有被拒绝
  2. 已兑现(fulfilled):操作成功完成
  3. 已拒绝(rejected):操作失败
    在这里插入图片描述
<body><script>/*** 目标:认识Promise状态*/// 1. 创建Promise对象(pending-待定状态)const p = new Promise((resolve, reject) => {// Promise对象创建时,这里的代码都会执行了// 2. 执行异步代码setTimeout(() => {// resolve() => 'fulfilled状态-已兑现' => then()resolve('模拟AJAX请求-成功结果')// reject() => 'rejected状态-已拒绝' => catch()reject(new Error('模拟AJAX请求-失败结果'))}, 2000)})console.log(p)// 3. 获取结果p.then(result => {console.log(result)}).catch(error => {console.log(error)})</script>
</body>

resolvereject

1.resolve : 将Promise对象的状态从 Pending(进行中) 变为 Fulfilled(已成功)

2.reject : 将Promise对象的状态从 Pending(进行中) 变为 Rejected(已失败)

3.resolvereject 都可以传入任意类型的值作为实参,表示 Promise 对象成功(Fulfilled)和失败(Rejected)的值

Promise封装XHR对象

<body><p class="my-p"></p><script>/*** 目标:使用Promise管理XHR请求省份列表*  1. 创建Promise对象*  2. 执行XHR异步代码,获取省份列表*  3. 关联成功或失败函数,做后续处理*/// 1. 创建Promise对象const p = new Promise((resolve, reject) => {// 2. 执行XHR异步代码,获取省份列表const xhr = new XMLHttpRequest()xhr.open('GET', 'http://hmajax.itheima.net/api/province')xhr.addEventListener('loadend', () => {// xhr如何判断响应成功还是失败的?// 2xx开头的都是成功响应状态码if (xhr.status >= 200 && xhr.status < 300) {resolve(JSON.parse(xhr.response))} else {reject(new Error(xhr.response))}})xhr.send()})// 3. 关联成功或失败函数,做后续处理p.then(result => {console.log(result)document.querySelector('.my-p').innerHTML = result.list.join('<br>')}).catch(error => {// 错误对象要用console.dir详细打印!!!console.dir(error)// 服务器返回错误提示消息,插入到p标签显示document.querySelector('.my-p').innerHTML = error.message})</script>
</body>

Promise链式调用

基本用法

依靠 then() 方法会返回一个新生成的 Promise 对象特性,继续串联下一环任务,直到结束

可解决回调函数嵌套问题

在这里插入图片描述

<body><script>/*** 目标:掌握Promise的链式调用* 需求:把省市的嵌套结构,改成链式调用的线性结构*/// 1. 创建Promise对象-模拟请求省份名字const p = new Promise((resolve, reject) => {setTimeout(() => {resolve('北京市')}, 2000)})// 2. 获取省份名字const p2 = p.then(result => {console.log(result)// 3. 创建Promise对象-模拟请求城市名字// return Promise对象最终状态和结果,影响到新的Promise对象return new Promise((resolve, reject) => {setTimeout(() => {resolve(result + '--- 北京')}, 2000)})})// 4. 获取城市名字p2.then(result => {console.log(result)})// then()原地的结果是一个新的Promise对象console.log(p2 === p)</script>
</body>
解决回调函数地狱问题

每个 Promise 对象中管理一个异步任务,用 then 返回 Promise 对象,串联起来

在这里插入图片描述

<body><form><span>省份:</span><select><option class="province"></option></select><span>城市:</span><select><option class="city"></option></select><span>地区:</span><select><option class="area"></option></select></form><script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script><script>/*** 目标:把回调函数嵌套代码,改成Promise链式调用结构* 需求:获取默认第一个省,第一个市,第一个地区并展示在下拉菜单中*/let pname = ''// 1. 得到-获取省份Promise对象axios({url: 'http://hmajax.itheima.net/api/province'}).then(result => {pname = result.data.list[0]document.querySelector('.province').innerHTML = pname// 2. 得到-获取城市Promise对象return axios({url: 'http://hmajax.itheima.net/api/city', params: { pname }})}).then(result => {const cname = result.data.list[0]document.querySelector('.city').innerHTML = cname// 3. 得到-获取地区Promise对象return axios({url: 'http://hmajax.itheima.net/api/area', params: { pname, cname }})}).then(result => {console.log(result)const areaName = result.data.list[0]document.querySelector('.area').innerHTML = areaName})</script>
</body>

Promise.all 静态方法

合并多个 Promise 对象,等待所有同时成功完成(或某一个失败),做后续逻辑

在这里插入图片描述

<script>/*** 目标:掌握Promise的all方法作用,和使用场景* 业务:当我需要同一时间显示多个请求的结果时,就要把多请求合并* 例如:默认显示"北京", "上海", "广州", "深圳"的天气在首页查看* code:* 北京-110100* 上海-310100* 广州-440100* 深圳-440300*/// 1. 请求城市天气,得到Promise对象const bjPromise = axios({ url: 'http://hmajax.itheima.net/api/weather', params: { city: '110100' } })const shPromise = axios({ url: 'http://hmajax.itheima.net/api/weather', params: { city: '310100' } })const gzPromise = axios({ url: 'http://hmajax.itheima.net/api/weather', params: { city: '440100' } })const szPromise = axios({ url: 'http://hmajax.itheima.net/api/weather', params: { city: '440300' } })// 2. 使用Promise.all,合并多个Promise对象const p = Promise.all([bjPromise, shPromise, gzPromise, szPromise])p.then(result => {// 注意:结果数组顺序和合并时顺序是一致console.log(result)const htmlStr = result.map(item => {return `<li>${item.data.data.area} --- ${item.data.data.weather}</li>`}).join('')document.querySelector('.my-ul').innerHTML = htmlStr}).catch(error => {console.dir(error)})</script>

async 函数

基本用法

  • 在 async 函数内,使用 await 关键字取代 then 函数,等待获取 Promise 对象成功状态的结果值
  • await替代 then 方法来提取 Promise 对象成功状态的结果
  • async/await使得异步代码看起来像同步代码,再也没有回调函数。但是改变不了JS单线程、异步的本质。(异步代码同步化)
<body><form><span>省份:</span><select><option class="province"></option></select><span>城市:</span><select><option class="city"></option></select><span>地区:</span><select><option class="area"></option></select></form><script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script><script>/*** 目标:掌握async和await语法,解决回调函数地狱* 概念:在async函数内,使用await关键字,获取Promise对象"成功状态"结果值* 注意:await必须用在async修饰的函数内(await会阻止"异步函数内"代码继续执行,原地等待结果)*/// 1. 定义async修饰函数async function getData() {// 2. await等待Promise对象成功的结果const pObj = await axios({url: 'http://hmajax.itheima.net/api/province'})const pname = pObj.data.list[0]const cObj = await axios({url: 'http://hmajax.itheima.net/api/city', params: { pname }})const cname = cObj.data.list[0]const aObj = await axios({url: 'http://hmajax.itheima.net/api/area', params: { pname, cname }})const areaName = aObj.data.list[0]document.querySelector('.province').innerHTML = pnamedocument.querySelector('.city').innerHTML = cnamedocument.querySelector('.area').innerHTML = areaName}getData()</script>
</body>

捕获错误

用 try catch 捕获同步流程的错误

<script>/*** 目标:async和await_错误捕获*/async function getData() {// 1. try包裹可能产生错误的代码try {const pObj = await axios({ url: 'http://hmajax.itheima.net/api/province' })const pname = pObj.data.list[0]const cObj = await axios({ url: 'http://hmajax.itheima.net/api/city', params: { pname } })const cname = cObj.data.list[0]const aObj = await axios({ url: 'http://hmajax.itheima.net/api/area', params: { pname, cname } })const areaName = aObj.data.list[0]document.querySelector('.province').innerHTML = pnamedocument.querySelector('.city').innerHTML = cnamedocument.querySelector('.area').innerHTML = areaName} catch (error) {// 2. 接着调用catch块,接收错误信息// 如果try里某行代码报错后,try中剩余的代码不会执行了console.dir(error)}}getData()</script>

Class

基本用法

ES6中的class其实就类似于ES5中的构造函数
比如下面两个写法是等价的:

<script>// es5构造函数// function Person(name,age){//   this.name=name//   this.age=age// }// // 给它一些共用的方法// Person.prototype.satName=function(){//   return this.name// }// let p1=new Person('zcy',18)// console.log(p1);// es6class Person{// 实例化的时候会被立即调用constructor(name,age){this.name=namethis.age=age}// 给它赋值方法// sayName(){//   return this.name// }// sayAge(){//   return this.age// }}// 通过Object.assign()一次性向类中添加多个方法Object.assign(Person.prototype, {sayName(){return this.name},sayAge(){return this.age}})let p1=new Person('zcy',18)console.log(p1);</script>

类的继承

1.Class 可以通过extends关键字实现继承,让子类继承父类的属性和方法

2super关键字调用父类中的构造函数,改变父类中的this指向,让父类中的this指向子类

3.子类在继承父类的方法后,可以重写父类的方法

<script>// 使用关键字class Animal{constructor(name,age){this.name=namethis.age=age}sayName(){return this.name}sayAge(){return this.age}}// 创建一个Dogclass Dog extends Animal{constructor(name,age,color){super(name,age)// Animal.call(this,name,age)this.color=color}sayColor(){return `${this.name}${this.age}岁了,它的颜色是${this.color}`}// 重写父类的方法sayName(){// super相当于Animal.prototypereturn this.name+super.sayAge()+this.color}}let d=new Dog('小白',10,'red')console.log(d.sayAge());console.log(d.sayName());</script>

Module 模块化

es6模块主要功能由两个命令构成:exportimport

export用于规定模块的对外接口

import用于输入其它模块提供的功能

export命令

一个模块就是一个独立文件。如果想从在不读取模块内部的某个变量,就必须使用export关键字输出该变量

//module/index.js
export const name = 'zhangsan ';
export const age = 18;
export const color = 'red ';
export const sayName = function() {console.log(fristName);
}//也可以这样
const name = 'zhangsan ';
const age = 18;
const color = 'red ';
const sayName = function() {console.log(fristName);
}
export {name,age,color,sayName}

import命令

使用export命令定义了模块的对外接口以后,其他 JS 文件就可以通过import命令加载这个模块

//main.js
import {name,age,color,sayName,fn} from './modules/index.js';

如果想为输入的变量重新取一个名字,import命令要使用as关键字,将输入的变量重命名

import * as obj from './modules/index.js';
console.log(obj);

export default 命令

使用export default命令为模块指定默认输出

//export-default.js
export default function(){console.log('foo');
}//或者写成
function foo() {console.log('foo');
}export default foo;

在其它模块加载该模块时,import命令可以为该匿名函数指定任意名字

//import-default.js
import customName from './export-default.js'
customNmae();//foo

如果想在一条import语句中,同事输入默认方法和其他接口,可以写成下面这样

import customName,{add} from 'export-default.js'
//export-default.js
export default function(){console.log('foo');
}export function add(){console.log('add')
}

export default也可以用来输出类

// MyClass.js
export default class Person{ ... }// main.js
import Person from 'MyClass';
let o = new Person();

Decorator

介绍

Decorator(装饰器)是一种设计模式,允许用户在不改变原类和使用继承的情况下,动态地扩展类属性和类方法

这里定义一个士兵,这时候他什么装备都没有

class soldier{ 
}

定义一个得到 AK 装备的函数,即装饰器

function strong(target){target.AK = true
}

使用该装饰器对士兵进行增强

@strong
class soldier{
}

这时候士兵就有武器了

soldier.AK // true

通过上述代码可得知Decorator的优点:

1.代码可读性变强,装饰器命名相当于一个注释

2.在不改变原有代码情况下,对原来功能进行扩展

用法

类的装饰

当对类本身进行装饰的时候,能够接受一个参数,即类本身

将装饰器行为进行分解,大家能够有个更深入的了解

@decorator
class A {}// 等同于class A {}
A = decorator(A) || A;

下面@testable就是一个装饰器,target就是传入的类,即MyTestableClass,实现了为类添加静态属性

@testable
class MyTestableClass {// ...
}function testable(target) {target.isTestable = true;
}MyTestableClass.isTestable // true

如果想要传递参数,可以在装饰器外层再封装一层函数

function testable(isTestable) {return function(target) {target.isTestable = isTestable;}
}@testable(true)
class MyTestableClass {}
MyTestableClass.isTestable // true@testable(false)
class MyClass {}
MyClass.isTestable // false
类属性的装饰

当对类属性进行装饰的时候,能够接受三个参数:

  • 类的原型对象
  • 需要装饰的属性名
  • 装饰属性名的描述对象

首先定义一个readonly装饰器

function readonly(target, name, descriptor){descriptor.writable = false; // 将可写属性设为falsereturn descriptor;
}

使用readonly装饰类的name方法

class Person {@readonlyname() { return `${this.first} ${this.last}` }
}

相当于以下调用

readonly(Person.prototype, 'name', descriptor);

如果一个方法有多个装饰器,就像洋葱一样,先从外到内进入,再由内到外执行

function dec(id){console.log('evaluated', id);return (target, property, descriptor) =>console.log('executed', id);
}class Example {@dec(1)@dec(2)method(){}
}
// evaluated 1
// evaluated 2
// executed 2
// executed 1

外层装饰器@dec(1)先进入,但是内层装饰器@dec(2)先执行

注意:

装饰器不能用于修饰函数,因为函数存在变量声明情况

var counter = 0;var add = function () {counter++;
};@add
function foo() {
}

编译阶段,变成下面

var counter;
var add;@add
function foo() {
}counter = 0;add = function () {counter++;
};

意图是执行后counter等于 1,但是实际上结果是counter等于 0

使用场景

基于Decorator强大的作用,我们能够完成各种场景的需求,下面简单列举几种:

使用react-redux的时候,如果写成下面这种形式,既不雅观也很麻烦

class MyReactComponent extends React.Component {}export default connect(mapStateToProps, mapDispatchToProps)(MyReactComponent);

通过装饰器就变得简洁多了

@connect(mapStateToProps, mapDispatchToProps)
export default class MyReactComponent extends React.Component {}

mixins,也可以写成装饰器,让使用更为简洁了

function mixins(...list) {return function (target) {Object.assign(target.prototype, ...list);};
}// 使用
const Foo = {foo() { console.log('foo') }
};@mixins(Foo)
class MyClass {}let obj = new MyClass();
obj.foo() // "foo"

下面再讲讲core-decorators.js几个常见的装饰器

1.@antobind

autobind装饰器使得方法中的this对象,绑定原始对象

import { autobind } from 'core-decorators';class Person {@autobindgetPerson() {return this;}
}let person = new Person();
let getPerson = person.getPerson;getPerson() === person;
// true

2.@readonly

readonly装饰器使得属性或方法不可写

import { readonly } from 'core-decorators';class Meal {@readonlyentree = 'steak';
}var dinner = new Meal();
dinner.entree = 'salmon';
// Cannot assign to read only property 'entree' of [object Object]

3.@deprecate

deprecatedeprecated装饰器在控制台显示一条警告,表示该方法将废除

import { deprecate } from 'core-decorators';class Person {@deprecatefacepalm() {}@deprecate('功能废除了')facepalmHard() {}
}let person = new Person();person.facepalm();
// DEPRECATION Person#facepalm: This function will be removed in future versions.person.facepalmHard();
// DEPRECATION Person#facepalmHard: 功能废除了

再由内到外执行

function dec(id){console.log('evaluated', id);return (target, property, descriptor) =>console.log('executed', id);
}class Example {@dec(1)@dec(2)method(){}
}
// evaluated 1
// evaluated 2
// executed 2
// executed 1

外层装饰器@dec(1)先进入,但是内层装饰器@dec(2)先执行

注意:

装饰器不能用于修饰函数,因为函数存在变量声明情况

var counter = 0;var add = function () {counter++;
};@add
function foo() {
}

编译阶段,变成下面

var counter;
var add;@add
function foo() {
}counter = 0;add = function () {counter++;
};

意图是执行后counter等于 1,但是实际上结果是counter等于 0

使用场景

基于Decorator强大的作用,我们能够完成各种场景的需求,下面简单列举几种:

使用react-redux的时候,如果写成下面这种形式,既不雅观也很麻烦

class MyReactComponent extends React.Component {}export default connect(mapStateToProps, mapDispatchToProps)(MyReactComponent);

通过装饰器就变得简洁多了

@connect(mapStateToProps, mapDispatchToProps)
export default class MyReactComponent extends React.Component {}

mixins,也可以写成装饰器,让使用更为简洁了

function mixins(...list) {return function (target) {Object.assign(target.prototype, ...list);};
}// 使用
const Foo = {foo() { console.log('foo') }
};@mixins(Foo)
class MyClass {}let obj = new MyClass();
obj.foo() // "foo"

下面再讲讲core-decorators.js几个常见的装饰器

1.@antobind

autobind装饰器使得方法中的this对象,绑定原始对象

import { autobind } from 'core-decorators';class Person {@autobindgetPerson() {return this;}
}let person = new Person();
let getPerson = person.getPerson;getPerson() === person;
// true

2.@readonly

readonly装饰器使得属性或方法不可写

import { readonly } from 'core-decorators';class Meal {@readonlyentree = 'steak';
}var dinner = new Meal();
dinner.entree = 'salmon';
// Cannot assign to read only property 'entree' of [object Object]

3.@deprecate

deprecatedeprecated装饰器在控制台显示一条警告,表示该方法将废除

import { deprecate } from 'core-decorators';class Person {@deprecatefacepalm() {}@deprecate('功能废除了')facepalmHard() {}
}let person = new Person();person.facepalm();
// DEPRECATION Person#facepalm: This function will be removed in future versions.person.facepalmHard();
// DEPRECATION Person#facepalmHard: 功能废除了

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com