课程目标
1.简单了解ECMAScript规范发展及历史 (每年6月发一版)
2.ES6及以后新增的常⽤API解析
3.简单了解一下Babel.js,写一个插件
课程要点
1.let 和 const
for(var i=0;i<=3;i++){
setTimeout(function() {
console.log(i)
}, 10);
}
//分别会输出什么? 为什么? 如何修改可以使其输出0,1,2,3?
for(var i = 0; i <=3; i++) { (function (i) {
setTimeout(function () {
console.log(i);
}, 10);
})(i);
}
for(let i=0;i<=3;i++){
setTimeout(function() {
console.log(i)
}, 10);
}
主要原因 setTimeout是异步, 在下⼀轮事件循环时,i变成4
重点 :⽽let引⼊了块级作⽤域的概念, 创建setTimeout函数时,变量i在作⽤域内。对于循环的每个迭代,引⽤的i是i的不同实例。(相当于执行4次宏任务)
2.箭头函数
(定义的时候一般是指向window)注意, 箭头函数不能被⽤作构造函数
(构造函数会⼲嘛? 改变this指向到新实例出来的对象. 箭头函数会⼲嘛?this指向是定义的时候决定的. )
4.模板字符串
重点是~~反斜线,变量用${}
// 编写render函数, 实现template render功能.
const year = '2021';
const month = '10';
const day = '01';
let template = '${year}-${month}-${day}';
let context = { year, month, day };
const str = render(template)({year,month,day}); //重点两个括号是高阶函数
console.log(str) // 2021-10-01
function render(template) {
return function(context) {
return template.replace(/\$\{(.*?)\}/g, (match, key) => context[key]);
} }
正则replace的中间那(.*?)是相当于match 匹配的值 key 所以匹配的是year /month/day
5.数组的解构 (数组是按顺序,对象是按属性名)
// 基础类型解构
let [a, b, c] = [1, 2, 3]
console.log(a, b, c) // 1, 2, 3
// 对象数组解构
let [a, b, c] = [{name: '1'}, {name: '2'}, {name: '3'}]
console.log(a, b, c) // {name: '1'}, {name: '2'}, {name: '3'}
// ...解构
let [head, ...tail] = [1, 2, 3, 4]
console.log(head, tail) // 1, [2, 3, 4]
// 嵌套解构
let [a, [b], d] = [1, [2, 3], 4]
console.log(a, b, d) // 1, 2, 4
// 解构不成功为undefined
let [a, b, c] = [1]
console.log(a, b, c) // 1, undefined, undefined
// 解构默认赋值
let [a = 1, b = 2] = [3]
console.log(a, b) // 3, 2
// 对象属性解构
let { f1, f2 } = { f1: 'test1', f2: 'test2' }
console.log(f1, f2) // test1, test2
// 可以不按照顺序,这是数组解构和对象解构的区别之⼀
let { f2, f1 } = { f1: 'test1', f2: 'test2' }
console.log(f1, f2) // test1, test2
// 解构对象重命名
let { f1: rename, f2 } = { f1: 'test1', f2: 'test2' }
console.log(rename, f2) // test1, test2
// 嵌套解构
let { f1: {f11}} = { f1: { f11: 'test11', f12: 'test12' } }
console.log(f11) // test11
// 默认值
let { f1 = 'test1', f2: rename = 'test2' } = { f1: 'current1', f2: 'current2'}
console.log(f1, rename) // current1, current2
重点是:结构的原理 (针对可迭代对象的Iterator接⼝,通过遍历器按顺序获取对应的值进⾏赋值. )
(实例属性就是new后接受值的实例,可调用的是constructor()中的方法和属性 class本身即Test可使用static中的属性,等同于test.xxx和test.prototype.xxx)
class Test {
_name = '';
constructor() {
this.name = 'lubai'; }
static getFormatName() {
return `${this.name} - xixi`; }
get name() {
return this._name; }
set name(val) {
console.log('name setter');
this._name = val; } }
console.log(new Test().name)
console.log(Test.getFormatName())
属性大都放在constructor中 因为它是基本类型,而function 大都放在外面因为是引用类型,new的时候引用同一个地址的方法就行,不需要重复创建
class Person {
constructor(name,sex){ //写在这里new的时候会多次生成浪费内存
this.name = name; //this指向实例
this.sex = sex;
this.say = ()=>{};
}
speak(){}
}
const zs = new Person('张三','男');
zs.say();
zs.speak();
//等同下面的 构造函数
function Person (name,sex){
this.name = name; //this指向实例
this.sex = sex;
this.say = function (){};
}
Person.prototype.speak = function (){};
const ls = new Person('李四',女);
ls.say();
ls.speak();
两种定义形式
声明的形式. //最常用
class Person {}
表达式形式
const Person = class {};
//实例属性
class Person {
//下面的也是实例属性和方法
name = '王五';
getName = function (){
return this.name;
}
constructor (sex){
this.sex = sex; //this指向实例
}
}
//静态方法 (也就是类的方法)
class Person {
static speak(){
this.age = 16; //this指向类
}
}
Person.speak();
//静态属性 (类的属性)(目前静态属性 还不能使用关键字static)
class Person{};
Person.version = '1.1'; //或者用静态function来return出来
1.以_开头的表示私有
2.将私有的属性和方法移除类
补充知识点