一、let 和 const
let:变量声明, const:只读常量声明(声明的时候赋值)。
let 与 var 的区别:
let、const 作用于
块级作用域
: 作用域在{}内,可作为局部变量(常量)、全局变量(常量)。var 作用于
全局作用域
:除非使用闭包实现局部变量。var 声明的
全局变量
与全局window对象的属性
是等价的。let 声明的全局变量
则不然。
二、变量的解构赋值(数组解构、对象解构)
数组解构赋值:用于
解构函数返回多数据
对象解构赋值:用于解构JSON数据
函数参数的解构赋值,用到解构默认值
解构赋值特点:
完全解构:等号两边模式匹配,如果解构不成功变量就等于undefined.
不完全解构:左边的模式只匹配一部分等号右边的数据。
解构赋值默认值:数据成员必须是undefined,默认值才能生效.
数组解构赋值注意:
- 在使用数组解构赋值的时候,如果等号右边不是可遍历的结构(可实现Iterator),会报错。
对象解构赋值需要注意:
注意解构时
模式
与变量
的区分。只有变量才能获取赋值。-
需要解构赋值的变量已经提前声明了,需要在解构赋值表达式上加圆括号。(为解析器会将起首的大括号,理解成一个代码块,而不是赋值语句。)
let foo; ({foo} = {foo: 1}); // 成功
用途
-
交换变量的值
[x,y] = [y,x]
从函数返回多个值
函数的参数定义、函数的参数的默认值
提取JSON数据
-
遍历Map结构
var map = new Map(); map.set('first', 'hello'); map.set('second', 'world'); for (let [key, value] of map) { console.log(key + " is " + value); }
-
输入模块的指定方法
const { SourceMapConsumer, SourceNode } = require("source-map");
ES6扩展
一、字符串的扩展
Unicode表示法:
\uxxxx
超过2字节存储的字符处理
JavaScript内部,字符以UTF-16的格式储存,每个字符固定为2个字节。对于那些需要4个字节储存的字符(Unicode码点大于0xFFFF的字符),JavaScript会认为它们是两个字符。
* `codePointAt()` 代替 `charCodeAt()`
* `String.fromCodePoint()` 代替`String.fromCharCode()`
* `for...of` 代替 `for(let i=0;i<length;i++)`
* `at()` 代替 `charAt()`
-
字符查找处理扩展
传统上,JavaScript只有
indexOf
方法,可以用来确定一个字符串是否包含在另一个字符串中-
includes()
:返回布尔值,表示是否找到了参数字符串 -
startsWith()
:返回布尔值,表示参数字符串是否在源字符串的头部 -
endsWith()
:返回布尔值,表示参数字符串是否在源字符串的尾部
-
-
模板字符串
`Hello ${name}, how are you ${time}?`
-
字符串原样输出
String.raw`Hi\\n`
-
标签模板
模板字符串
紧跟在一个函数名
后面,该函数将被调用来处理这个模板字符串。这被称为标签模板
功能
标签模板
的一个重要应用,就是过滤HTML字符串,防止用户输入恶意内容。tag`Hello ${ a + b } world ${ a * b }`; // 等同于 tag(['Hello ', ' world ', ''], 15, 50); function tag(stringArr,value1,value2){ ... } //等同于 function tag(stringArr,...values){ ... }
-
其他扩展
-
repeat()
:返回一个新字符串,表示将原字符串重复n次 - 自动补全
padStart()
、padEnd()
'x'.padStart(4, 'ab') // 'abax' 'x'.padEnd(4, 'ab') // 'xaba'
-
二、数值的扩展
- 二进制和八进制的表示:分别用前缀
0b
(或0B
)和0o
(或0O
)表示。2.
如果要将0b和0o前缀的字符串数值转为十进制,要使用Number方法:Number(0b111)
Number.isFinite()
用来检查一个数值是否为有限的(finite)Number.isNaN()
用来检查一个值是否为NaN。Number.isInteger()
用来判断一个值是否为整数。Number.parseInt()
,Number.parseFloat()
三、数组的扩展
Array.from()
将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括ES6新增的数据结构Set和Map)
* 为什么要转换成真正的数组:可以使用forEach方法
* Array.from还可以接受第二个参数,作用类似于数组的map方法
* 计算包含 `超过2个字节的字符` 的字符串的长度:`Array.from(string).length;`
Array.of()
方法用于将一组值,转换为数组
Array.of(3, 11, 8,'a') // [3,11,8,'a']
-
数组实例的
find()
和findIndex()
-
find()
用于找出第一个符合条件的数组成员,没有则返回undefined -
findIndex()
第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1
-
-
数组实例的
fill()
['a', 'b', 'c'].fill(7) // [7, 7, 7] new Array(3).fill(7) // [7, 7, 7] ['a', 'b', 'c'].fill(7, 1, 2) // ['a', 7, 'c'] 第二个和第三个参数,用于指定填充的起始位置和结束位置
-
数组实例的
entries()
,keys()
和values()
for (let index of ['a', 'b'].keys()) { console.log(index); } // 0 // 1 for (let elem of ['a', 'b'].values()) { console.log(elem); } // 'a' // 'b' for (let [index, elem] of ['a', 'b'].entries()) { console.log(index, elem); } // 0 "a" // 1 "b"
-
数组实例的
includes()
(属于ES7,Babel支持)返回一个布尔值,表示某个数组是否包含给定的值,字符串的
includes
方法类似 -
数组的空位 :
Array(3) // [, , ,]
- ES6则是明确将空位转为undefined
- ES5 对空位的处理 ,大多数情况下会忽略空位
数组实例的
copyWithin()
在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。
Array.prototype.copyWithin(target, start = 0, end = this.length)
[1, 2, 3, 4, 5].copyWithin(0, 3)
// [4, 5, 3, 4, 5]
// 将3号位复制到0号位
[1, 2, 3, 4, 5].copyWithin(0, 3, 4)
// [4, 2, 3, 4, 5]
// -2相当于3号位,-1相当于4号位
[1, 2, 3, 4, 5].copyWithin(0, -2, -1)
// [4, 2, 3, 4, 5]
// 将2号位到数组结束,复制到0号位
var i32a = new Int32Array([1, 2, 3, 4, 5]);
i32a.copyWithin(0, 2);
// Int32Array [3, 4, 5, 4, 5]
三、函数的扩展
-
参数的默认值
- 默认值参数
- 解构赋值默认值 作为参数
- 默认值的参数位置:末尾
- 函数的length属性:参数的个数,制定默认值后失真
- 作用域:如果参数默认值是一个变量,先是当前函数的作用域,然后才是全局作用域
rest参数
...
name属性:函数的函数名
-
箭头函数
=>
- 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象(所在的函数体内)。
- 不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
- 不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用Rest参数代替。
- 不可以使用yield命令,因此箭头函数不能用作Generator函数。
-
函数绑定 (ES7)
::
取代call
、apply
、bind
this的绑定。foo::bar; // 等同于 bar.bind(foo); foo::bar(...arguments); // 等同于 bar.apply(foo, arguments); --------------------------------- var method = obj::obj.foo; // 等同于 var method = ::obj.foo; ------------------------------------ 采用链式写法: let { find, html } = jake; document.querySelectorAll("div.myClass") ::find("p") ::html("hahaha");
* apply 、 call 、bind 三者都是用来改变函数的this对象的指向的;
* apply 、 call 、bind 三者第一个参数都是this要指向的对象,也就是想指定的上下文;
* apply 、 call 、bind 三者都可以利用后续参数传参;
* bind 是返回对应函数,便于稍后调用;apply 、call 则是立即调用 。
-
扩展运算符
...
- 合并数组
- 与结构赋值结合
- 将字符串转为真正的数组 能够正确识别32位的Unicode字符
- 任何Iterator接口的对象,都可以用扩展运算符转为真正的数组(Map和Set结构,Generator函数)
-
尾调用优化、尾部递归优化
调用栈太多,造成溢出,那么只要减少调用栈,就不会溢出。
Symbol
凡是属性名属于Symbol类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。
ES6有7种原始数据类型:
Undefined 、Null、布尔值(Boolen) 、字符串(String) 、数值(Number) 、对象(Object) 、Symbol
一、基本
-
可以显示的转为字符串
var sym = Symbol('My symbol'); String(sym) // 'Symbol(My symbol)' sym.toString() // 'Symbol(My symbol)'
-
可以转为布尔值,不能转换为数值
var sym = Symbol(); Boolean(sym) // true !sym // false if (sym) { // ... } Number(sym) // TypeError sym + 2 // TypeError
二、Symbol类型的变量作为属性的名
-
Symbol类型的变量作为属性名的使用
var mySymbol = Symbol(); // 第一种写法 var a = {}; a[mySymbol] = 'Hello!'; // 第二种写法 var a = { [mySymbol] : 'Hello!' }; // 第三种写法 var a = {}; Object.defineProperty(a, mySymbol, { value: 'Hello!' }); // 以上写法都得到同样结果 a[mySymbol] // "Hello!" 注意:注意,Symbol值作为对象属性名时,不能用点运算符。 a.mySymbol 相当于 a['mySymbol'] //属性名为字符串
-
Symbol类型的变量作为属性名,遍历属性名
Symbol类型的变量作为属性名,该属性不会出现在
for...in
、for...of
中。不会被
Object.keys()
、Object.getOwnPropertyNames()
、JSON.stringify()
返回.Object.getOwnPropertySymbols()
方法,可以获取指定对象的所有Symbol属性名.
三、
Symbol.for()
,Symbol.keyFor()
-
Symbol.for()
- 使用同一个Symbol值。
- 不会每次调用返回新的Symbol类型的值,会先检查给定的key是否已经存在,如果不存在才回建立一个新的值.
-
Symbol.for()
为Symbol值登记的名字,是全局环境的。可以在不同的frame或service worker中取同一个值。
-
Symbol.keyFor()
- 返回一个已登记的Symbol类型值的key
四、用途
- 实现类似enum的功能,内部的值不重复。
- 模块的Singleton模式
// mod.js
const FOO_KEY = Symbol.for('foo');
function A() {
this.foo = 'hello';
}
if (!global[FOO_KEY]) {
global[FOO_KEY] = new A();
}
module.exports = global[FOO_KEY];
注意:const FOO_KEY = Symbol('foo'); 如果多次执行这个脚本,每次得到的FOO_KEY都是不一样的。
五、ES6内置了11个Symbol值
指向语言内部使用的方法
-
Symbol.hasInstance
-
foo instanceof Foo
相当于Foo[Symbol.hasInstance](foo)
-
-
Symbol.isConcatSpreadable
使用Array.prototype.concat()时,是否可以展开 Symbol.species
-
Symbol.match
: 相当于str.match(myObject)
-
Symbol.replace
:相当于String.prototype.replace(searchValue, replaceValue)
-
Symbol.search
: 相当于String.prototype.search
-
Symbol.split
: 相当于String.prototype.split
-
Symbol.iterator
:指向该对象默认的遍历器方法 -
Symbol.toPrimitive
: 该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值。- Number:该场合需要转成数值
- String:该场合需要转成字符串
- Default:该场合可以转成数值,也可以转成字符串
-
Symbol.toStringTag
: 相当于Object.prototype.toString
-
Symbol.unscopables
: 该对象指定了使用with关键字时,哪些属性会被with环境排除。
Set和Map数据结构
一、Set
它类似于数组,但是成员的值都是唯一的,没有重复的值。
-
Set结构的实例属性
-
Set.prototype.constructor
:构造函数,默认就是Set函数 -
Set.prototype.size
:返回Set实例的成员总数
-
-
Set 的操作方法
-
add(value)
: 添加某个值,返回Set结构本身。 -
delete(value)
: 删除某个值,返回一个布尔值,表示删除是否成功。 -
has(value)
: 返回一个布尔值,表示该值是否为Set的成员。 -
clear()
:清除所有成员,没有返回值。
-
-
Set 的遍历方法
keys()
values()
entries()
forEach()
-
Set 的遍历实例
let set = new Set(['red', 'green', 'blue']); for (let item of set.keys()) { console.log(item); } // red // green // blue for (let item of set.values()) { console.log(item); } // red // green // blue for (let item of set.entries()) { console.log(item); } // ["red", "red"] // ["green", "green"] // ["blue", "blue"] set.forEach((value,key) => console.log(value)); //red //green //blue
二、WeakSet
-
与Set的区别
- WeakSet的成员只能是对象,而不能是其他类型的值
- WeakSet中的对象都是弱引用
- WeakSet是不可遍历的
-
WeakSet 的构造函数
- WeakSet可以接受一个数组或类似数组的对象作为参数。
- 实际上,任何具有iterable接口的对象,都可以作为WeakSet的参数。
- 该数组的所有成员,都会自动成为WeakSet实例对象的成员。
-
WeakSet 操作方法
WeakSet.prototype.add(value)
WeakSet.prototype.delete(value)
WeakSet.prototype.has(value)
WeakSet没有遍历方法,没有
size
属性和forEach
属性.
三、Map
-
Map与Object的区别
- Obejct结构提供 "字符串-值" 的对应
- Map结构提供 "值-值"的对应
-
构造函数
- Map接受一个数组作为参数,成员是一个个表示键值对的数组.
var map = new Map([ ['name', '张三'], ['title', 'Author'] ]);
-
Map的属性与操作方法
-
size
: 返回Map结构的成员总数 set(key,value)
-
get(key)
: 如果找不到key,返回undefined has(key)
delete(key)
clear()
-
-
Map的遍历方法,Map的顺序是插入顺序
-
keys()
: 返回键名的遍历器 -
values()
: 返回键值的遍历器 -
entries()
: 返回所有成员的遍历器 -
forEach()
: 遍历Map的所有成员
-
-
Map与其他数据结构的互相转换
Map 转换为 数组
数组 转换为 Map
Map 转换为 对象
对象 转换为 Map
-
Map 转换为 JSON :
JSON.stringify(value)
- 所有键名为字符串: 先转换为 对象(Object),再转换为 JSON
- 键名不为字符串: 先转换为 数组,在转换为JSON
-
JSON 转换为 Map :
JSON.parse(value)
- 所有键名为字符串: 先转换为 对象(Object),再转换为Map
- 整个JSON是一个数组,每个数组成员有两个成员的数组:转换为 数组后,再转换为Map
四、WeakMap
-
WeakMap 的操作方法
get()
set()
has()
delete()
-
WeakMap 与 Map的区别
- 没有遍历操作,也没有
size
属性 - 只接受 对象 作为键名。键名所指向的对象,不计入垃圾回收机制.
- 没有遍历操作,也没有
-
主要的应用场合,预防内存泄漏
- DOM节点作为键名
- 部署私有的属性
let _counter = new WeakMap(); let _action = new WeakMap(); class Countdown { constructor(counter, action) { _counter.set(this, counter); _action.set(this, action); } dec() { let counter = _counter.get(this); if (counter < 1) return; counter--; _counter.set(this, counter); if (counter === 0) { _action.get(this)(); } } } let c = new Countdown(2, () => console.log('DONE')); c.dec() c.dec() // DONE
Iterator 和 for...of循环
一、Iterator
-
Iterator接口的描述
- 每次调用next方法,遍历返回
{value:'',done:false}
,直到done为true - 使用
for...of
可以直接遍历。 - 一个数据结构只要具有
Symbol.iterator
属性,就可以认为是“可遍历的”(iterable)
- 每次调用next方法,遍历返回
-
原生具备Iterator接口的数据结构
- 数组
- 某些类似数组的对象(存在数值键名和length属性)
- Set 和 Map
Generator函数
-
Generator 基本示例
function* testGenerator(){ yield 'hello'; let tmp = yield 'world'; console.log(tmp); return 'ending'; } let g = testGenerator(); g.next(); //{ value: 'hello', done: false } g.next(); //{ value: 'world', done: false } g.next(123); //123 //{ value: 'ending', done: true } g.next(); //{ value: undefined, done: true } for(let item of testGenerator()){ console.log(item); } //hello //world //undefined
-
yield
yield不能用于普通的函数中,不用用于forEach函数中。
yield语句如果用在一个表达式中,必须放到圆括号里面。(就是调用下一次next,传递的值)
与Iterator接口的关系
Generator函数就是遍历器生成函数,可以把Generator赋值给对象的
Symbol.iterator
属性,是该对象具有Iterator接口
- next方法的参数
next方法可以带一个参数,该参数作为上一个yield语句的返回值
- for...fo循环
自动遍历Generator函数生成的Iterator对象,不需要调用next方法
- Generator.prototype.throw()
Generator函数返回的遍历器对象,都有一个throw方法.
实现函数体外抛出错误,Generator函数体内捕获. 主要用于 异步操作 的错误捕获。
也可以Generator体内抛出错误,体外捕获。
var g = function* () {
try {
yield;
} catch (e) {
console.log('内部捕获', e);
}
};
var i = g();
i.next();
try {
i.throw('a');
i.throw('b');
} catch (e) {
console.log('外部捕获', e);
}
// 内部捕获 a
// 外部捕获 b
注意:throw命令与i.throw方法是无关的
- Generator.prototype.return()
终结遍历Generator函数
- yield* 语句
用来在一个Generator函数里面执行另一个Generator函数。
```
function *foo() {
yield 2;
yield 3;
return "foo";
}
function *bar() {
yield 1;
var v = yield *foo();
console.log( "v: " + v );
yield 4;
}
var it = bar();
it.next()
// {value: 1, done: false}
it.next()
// {value: 2, done: false}
it.next()
// {value: 3, done: false}
it.next();
// "v: foo"
// {value: 4, done: false}
it.next()
// {value: undefined, done: true}
```
-
作为对象属性的Generator函数
let obj = { * myGeneratorMethod() { ··· } 或 myGeneratorMethod: function* () { // ··· } };
Generator函数的 this
让Generator函数返回一个正常的对象实例,既可以用next方法,也可以获得正常的this
```
function* F() {
this.a = 1;
yield this.b = 2;
yield this.c = 3;
}
var obj = {};
var f = F.call(obj); //统一成一个对象, F.call(F.prototype);
f.next(); // Object {value: 2, done: false}
f.next(); // Object {value: 3, done: false}
f.next(); // Object {value: undefined, done: true}
//两个对象
obj.a // 1
obj.b // 2
obj.c // 3
//统一成一个对象后
f.a //1
f.b //2
f.c //3
```
- Generator函数作为状态机
运行一次next,获取有序的下一个状态
-
应用
- 异步操作的同步表达
- 利用next传参数的方式,将异步返回的数据,返回到Generator函数中。
- 然后进行下一个next的操作。
- 控制流管理
- 异步工作流,主要配合Promise使用.
- 部署Iterator接口,Generator函数是遍历生成器。
- 作为数据结构,可以看作是一个数组的结构
- 异步操作的同步表达
Promise对象
一、Promise基本简介
-
Promise 特点
- Promise对象的状态有三种:Pending(进行中)、Resolved(已完成)、Rejected(已失败)
- Promise对象的状态改变有2种:从Pending----->Resolved、从Pending------>Rejected
- 当Promise对象的状态已经改变后,再添加Promise对象的回调函数,也会立即执行回调。(不会因为错过它,再去监听,而得不到结果)
-
Promise 缺点
- 一旦新建它就会立即执行,不能中途取消
- 如果不设回调函数,Promise内部抛出的错误,不能反应到外部
- 当处于Pending中,无法得知进度。
二、Promise 使用
-
Promise 创建与回调监听
var promise = new Promise(function(resolve, reject) { // ... some code if (/* 异步操作成功 */){ resolve(value); } else { reject(error); } }); //回调处理 promise.then(function(value) { // success }, function(error) { // failure });
-
Promise.prototype.then()
- then 返回一个Promise对象,所以可以采用链式写法
-
Promise.prototype.catch()
-
Promise.prototype.catch
方法是.then(null,rejection)
的别名,用于指定发生错误时的回调函数 - Promise对象的状态变为Rejected,就会调用catch方法指定的回调函数
- Promise对象在运行中抛出异常,也会调用catch方法指定的回调函数
- Promise对象的错误总是被下一个catch语句捕获。
- 一般不要在
then
方法里面定义Rejected状态的回调函数,总是用catch方法 - 如果没有下一个的catch方法,会导致错误不会被捕获,也不会传递到外层
var promise = new Promise(function(resolve, reject) { throw new Error('test'); }); promise.catch(function(error) { console.log(error); }); // Error: test
-
-
Promise.all()
-
var p = Promise.all([p1, p2, p3]);
只有
p1
、p2
、p3
的状态都变成fulfilled
,p
的状态才会变成fulfilled
.此时p1
、p2
、p3
的返回值组成一个数组,传递给p
的回调函数.只要
p1
、p2
、p3
之中有一个被rejected
,p
的状态就变成rejected
.此时第一个被rejected
的实例返回值,会传递给p
的回调函数
-
// 生成一个Promise对象的数组
var promises = [2, 3, 5, 7, 11, 13].map(function (id) {
return getJSON("/post/" + id + ".json");
});
Promise.all(promises).then(function (posts) {
// ...
}).catch(function(reason){
// ...
});
-
Promise.race()
-
var p = Promise.race([p1,p2,p3]);
- 要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的Promise实例的返回值,就传递给p的回调函数。
- 应用场合:指定的某个时间内没有获取结果,就将Promise的状态变为reject.
-
-
Promise.resolve()
Promise.resolve('foo') // 等价于 new Promise(resolve => resolve('foo'))
- 参数是一个Promise实例
- 原封不动返回这个实例
- 参数是一个
thenable
对象- 首先将这个对象转换为Promise对象,然后立即执行
thenable
对象的then
方法.
- 首先将这个对象转换为Promise对象,然后立即执行
- 参数不是具有
then
方法的对象,或根本不是对象,或不带任何参数- 直接返回一个
Resolved
状态的Promise对象,在本轮的“时间循环”结束时执行。
- 直接返回一个
- 参数是一个Promise实例
-
Promise.reject()
var p = Promise.reject('出错了'); // 等同于 var p = new Promise((resolve, reject) => reject('出错了'))
Generator函数 与 Promise结合,可以实现异步操作的同步化实现。
Class
一、Class的基本使用
//定义类
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
-
ES6定义类的特性
- ES6的类,完全看做构造函数的另一种写法
Point.prototype.constructor === Point // true
- 类所有的方法,都定义在类的prototype属性上.
- 类实例调用的方法,其实都是调用原型上的方法
- ES6的类,完全看做构造函数的另一种写法
-
类的实例对象
- 与ES 5一样,实例的属性除非显示的定义在其本身(即定义在
this
对象上),否则都定义在原型上 (prototype
上)。 - 与ES 5一样,类的所有实例共享一个原型对象
- 需要首先定义类后,才能使用类。
- 与ES 5一样,实例的属性除非显示的定义在其本身(即定义在
-
私有方法
- 命名约定,方法名前加下划线。
- ES6 利用
Symbol
值的唯一性,将私有的方法的名字命名为一个Symbol
值。
const bar = Symbol('bar'); const snaf = Symbol('snaf'); export default class myClass{ // 公有方法 foo(baz) { this[bar](baz); } // 私有方法 [bar](baz) { return this[snaf] = baz; } // ... };
this的指向
类的方法内部如果含有
this
,它默认指向类的实例。
如果单独取出类的实例的一个方法,来单独使用,会因为找不到this
指定的方法或属性(也就不在一个上下文)报错。
* 在构造方法中绑定`this`
* 使用箭头函数,会自动绑定 `this`
* 使用`Proxy`,获取方法的时候,自动绑定`this`
二、Class的继承
class ColorPoint extends Point {
constructor(x, y, color) {
super(x, y); // 调用父类的constructor(x, y)
this.color = color;
}
toString() {
return this.color + ' ' + super.toString(); // 调用父类的toString()
}
}
子类必须在
constructor
方法中调用super
方法,否则新建实例时会报错。在子类的
constructor
构造函数中,只有调用super
后,才能调用this
关键字.
三、 类的prototype属性和proto属性
每个对象都有
__proto__
属性,指向对应的构造函数的prototype
属性.
Class作为构造函数,同时有prototype
属性和__proto__
属性.
- 子类的
__proto__
属性,表示构造函数的继承,总是指向父类。 - 子类的
prototype
属性的__proto__
属性,总是指向父类的prototype
属性。
class A {
}
class B extends A {
}
B.__proto__ === A // true
B.prototype.__proto__ === A.prototype // true
四、super 关键字
super
作为函数,代表父类的构造函数-
super
作为对象时,指向父类的原型对象.- 由于
super
指向父类的原型对象,所以定义在父类实例上的方法或属性,无法通过super
调用。
- 由于
ES6有一个特别的规定,通过
super
调用父类的方法时,super
会绑定子类的this
.
五、Class的取值函数(getter) 和 存值函数(setter)
class MyClass {
constructor() {
// ...
}
get prop() {
return 'getter';
}
set prop(value) {
console.log('setter: '+value);
}
}
六、Class的静态方法
父类的静态方法,可以被子类继承.
静态方法也是可以从super对象上调用的.
class Foo {
static classMethod() {
return 'hello';
}
}
class Bar extends Foo {
static classMethod() {
return super.classMethod() + ', too';
}
}
Bar.classMethod();
七、ES7的Class的静态属性和实例属性
ES6明确规定,Class内部只有静态方法,没有静态属性。
-
类的实例属性
class MyClass { myProp = 42; constructor() { console.log(this.myProp); // 42 } }
-
类的静态属性
class MyClass { static myStaticProp = 42; constructor() { console.log(MyClass.myProp); // 42 } }
八、new.target属性
返回new命令作用于的那个构造函数
如果构造函数不是通过new命令调用的,new.target会返回undefined
Class内部调用new.target,返回当前Class。
子类继承父类时,new.target会返回子类。
ES7 类的修饰Decorator
动态语言特性
- Object.assign
- Object.keys
- Object.getOwnPropertyNames
- Object.create
- Object.name
- Object.setPrototypeOf
- Object.getPrototypeOf() 从子类获取父类
- Object.getOwnPropertyDescriptor
- Object.prototype.hasOwnProperty
- Object.prototype.proto