const命令:
声明一个只读常量,一旦声明,声明的值就不能改变
声明的常量和let一样,不可重复声明
本质:并不是变量的值不得改动,而是变量指向的那个内存地址不得改动
const只能保证这个指针固定,它指向的数据结构变不变是无法控制的
对象冻结:object.freeze方法
ES5只有两种声明变量的方法:var 和 function
ES6一共六种声明变量的方法:
let,const,import,class,var,function
var,function声明全局变量,依旧是顶层对象的属性
let,const,classes命令声明的全局变量不属于顶层对象的属性
var a = 1;
window.a;
是正确的
let b = 2
window.b
会报错
现在想要获取顶层变量一般都使用this去获取,但是是有局限性的
1.全局环境中this获取顶层变量,但是在node和es6的环境中,this只能返回当前模块
2.函数中的this,如果函数不是作为对象的方法运行,而是单纯作为函数运行,this会指向顶层对象,但是在严格环境下会报未定义的错误
----------------这句不是很理解
3.new function('return this')总是返回全局对象,但浏览器用了CSP(Content Security Policy,内容安全策略),那么eval,new Function 这些方法都可能无法使用
解构赋值虽然方便,但是解析并不容易,es6规则:
只要有可能导致解构的歧义,就不能使用圆括号
解构的用途
1.交换变量
let x = 1;
let y = 2;
[x,y] = [y,x];
2.从函数返回多个值
函数只能返回多个值,要想返回很多值,只能将它们放在数组或者对象里返回
3.函数参数的定义
4.提取json数据
5.遍历map解构
const map = new Map();
map.set('first', 'hello');
map.set('second', 'world');
for (let [key, value] of map) {
console.log(key + " is " + value);
}
6.输入模块的指定方法
加载模块时,往往需要指定输入哪些方法。解构赋值使得输入语句非常 清晰。
const { SourceMapConsumer, SourceNode } = require("source-map");
1.es6加强了对Unicode的支持,拓展了字符串对象
codePointAt()
能够正确处理4个字节存储的字节,返回一个字节的码点
codePointAt 方法返回的是码点的十进制值,如果想要十六进制的 值,可以使用 toString 方法转换一下。
let s = 'a' ;
s.codePointAt(0).toString(16) // "20bb7" s.codePointAt(2).toString(16) // "61"
normalize用来将字符的不同表示方式统一为同样的样式
'\u01D1'.normalize() === '\u004F\u030C'.normalize() // true
es6提供了判断一个字符串中是否包含其他字符串的更多方法:
includes(),startsWith(),endWith()
repeat() 返回一个新字符
string.repeat(3);
padStart(),padEnd()
ES2017 引入了字符串补全长度的功能。如果某个字符串不够指定长度, 会在头部或尾部补全。 padStart() 用于头部补全, padEnd() 用于尾 部补全。
'x'.padStart(5, 'ab') // 'ababx' 'x'.padStart(4, 'ab') // 'abax'
'x'.padEnd(5, 'ab') // 'xabab' 'x'.padEnd(4, 'ab') // 'xaba'
RegExp构造函数:
match(),replace().search(),split()
ES6 对正则表达式添加了 u 修饰符,含义为“Unicode模式”,用来正确 处理大于 \uFFFF 的 Unicode 字符。也就是说,会正确处理四个字节的 UTF-16 编码。
/^\uD83D/u.test('\uD83D\uDC2A') // false
/^\uD83D/.test('\uD83D\uDC2A') // true
除了 u 修饰符,ES6 还为正则表达式添加了 y 修饰符,叫做“粘 连”(sticky)修饰符。 y 修饰符的作用与 g 修饰符类似,也是全局匹配,后一次匹配都从上 一次匹配成功的下一个位置开始。不同之处在于, g 修饰符只要剩余位 置中存在匹配就可,而 y 修饰符确保匹配必须从剩余的第一个位置开 始,这也就是“粘连”的涵义。
var s = 'aaa_aa_a'; var r1 = /a+/g; var r2 = /a+/y;
r1.exec(s) // ["aaa"] r2.exec(s) // ["aaa"]
r1.exec(s) // ["aa"] r2.exec(s) // null
lastIndex属性:
lastIndex 属性指定每次搜索的开始位置
const REGEX = /a/y;
REGEX.lastIndex = 2;
REGEX.exec('xaya') // null
REGEX.lastIndex = 3;
const match = REGEX.exec('xaxa');
match.index;
REGEX.lastIndex
mathc用法:
单单一个 y 修饰符对 match 方法,只能返回第一个匹配,必须 与 g 修饰符联用,才能返回所有匹配。
'a1a2a3'.match(/a\d/y) // ["a1"]
'a1a2a3'.match(/a\d/gy) // ["a1", "a2", "a3"]
sticky属性:
与 y 修饰符相匹配,ES6 的正则对象多了 sticky 属性,表示是否设 置了 y 修饰符。
var r = /hello\d/y;
r.sticky // true
新增flags属性,返回郑子表达式的修饰符
// ES6 的 flags 属性
// 返回正则表达式的修饰符 /abc/ig.flags
// 'gi'
正则表达式中,点( . )是一个特殊字符,代表任意的单个字符,但是 行终止符(line terminator character)除外。 以下四个字符属于”行终止符“。
U+000A 换行符( \n )
U+000D 回车符( \r )
U+2028 行分隔符(line separator)
U+2029 段分隔符(paragraph separator)
为了让.可以匹配任意单个字符
引入 /s 修饰 符,使得 . 可以匹配任意单个字符。
/foo.bar/s.test('foo\nbar') // true
这种模式成为dotAll模式,点代表一切字符
所以,正则表达式 还引入了一个 dotAll 属性,返回一个布尔值,表示该正则表达式是否 处在 dotAll 模式。
const re = /foo.bar/s;
re.dotAll
先行断言:
x只有在y前面才匹配 /x(?=y)/
只匹配百分号前的数字 /\d+(?=%)/
先行否定断言
x只有不在y前面才匹配 /x(?!y)/
只匹配不在百分号之前的数字 /\d+(?!%)/
后行断言
与先行断言正好相反
x只有在y后面才匹配 /(?<=y)x/
只匹配美元符号之后的数字 /(?<=\$)\d+/
后行否定断言:x只有不在y后面才匹配 /(?
只匹配不在美元符号后面的数字 /(?
const RE_DOLLAR_PREFIX = /(?<=\$)foo/g;
'$foo %foo foo'.replace(RE_DOLLAR_PREFIX, 'bar'); // '$bar %foo foo'
上面代码中,只有在美元符号后面的 foo 才会被替换
首先,”后行断言“的组匹配,与正常情况下结果是不一样的。
/(?<=(\d+)(\d+))$/.exec('1053') // ["", "1", "053"]
/^(\d+)(\d+)$/.exec('1053') // ["1053", "105", "3"]
上面代码中,需要捕捉两个组匹配。没有”后行断言”时,第一个括号是 贪婪模式,第二个括号只能捕获一个字符,所以结果是 105 和 3 。 而”后行断言”时,由于执行顺序是从右到左,第二个括号是贪婪模式, 第一个括号只能捕获一个字符,所以结果是 1 和 053 。
其次,”后行断言”的反斜杠引用,也与通常的顺序相反,必须放在对应 的那个括号之前。
/(?<=(o)d\1)r/.exec('hodor') // null
/(?<=\1d(o))r/.exec('hodor') // ["r", "o"]
上面代码中,如果后行断言的反斜杠引用( \1 )放在括号的后面,就 不会得到匹配结果,必须放在前面才可以。因为后行断言是先从左到右 扫描,发现匹配以后再回过头,从右到左完成反斜杠引用。
Unicode属性类
\p{...} 和 \P{...}
允许正则表达式匹配符合Unicode某种属性的所有字符
具名组匹配
正则表达式使用圆括号进行组匹配
允许每个匹配组都有一个名字,方便之后的查看和引用
如果要在正则表达式内部引用某个“具名组匹配”,可以使用 \k<组名 > 的写法。
const RE_TWICE = /^(?
RE_TWICE.test('abc!abc') // true
RE_TWICE.test('abc!ab') // false
数字引用( \1 )依然有效
const RE_TWICE = /^(?
RE_TWICE.test('abc!abc') // true
RE_TWICE.test('abc!ab') // false
\1和\k可以同时使用
javaScript准确表示的整数范围在-2^53到2^53之间,超过这个范围,无法精确表示这个值
number.isSafeInteger()判断一个整数是否落在这个范围之内
Ingeter整数类型,只能表示整数,没有位数的限制,任何位数的整数都可以精确表示:1n+3n=4n
参数默认值位置
function f(x, y = 5, z) { return [x, y, z]; }
f() // [undefined, 5, undefined]
f(1) // [1, 5, undefined]
f(1, ,2) // 报错
f(1, undefined, 2) // [1, 5, 2]
有默认值的参数都不是尾参数,无法忽略改参数,如果传入undefined,将触发改参数等于默认值,null则没有这个效果
注意指定了默认值后,函数的length属性将失真,变为0
(function(a){}).length //1
(function(b=1){}).length //0
(function(c,d,e=4){}).length//2
rest参数,用于获取函数的多余参数
function add(...values) {}
函数的length属性,也不包括rest参数
因为参数要先于方法执行,所以遇到以下情况时,会发生错误
function a(value = 070){
'use strict';
return value;
}
当给参数附完值之后,进入方法体中,采用严格模式,因为严格模式下八进制是不能带0的,所以报错
为了避免这种情况,采用两种方法:
1.使用全局严格模式
2.把函数抱在一个五参数的立即执行函数里面
const doSomething = (function () { 'use strict'; return function(value = 42) { return value; }; }());
name属性,返回函数名
es6允许使用箭头=>定义函数
var f = v =>v
等价于
var f = function(v){
return f;
}
var sum = (num1,num2) => num1 + num2;
var sum = function(num1,num2){
return num1 + num2;
}
使用箭头函数有几个使用注意点
1.this所指的对象不是使用时的对象而是定义时的对象
2.不可以当做构造函数,使用new会报错
3.不可以使用arguments对象,如果要,可以用rest对象代替
4.不可以使用yield命令,因此箭头函数不能做Generator函数
双冒号运算符:
函数绑定运算符是并排的两个冒号,左边是对象,右边是方法,自动将左边的对象绑定到方法中
foo::bar 等同于
bar.bind(foo)
foo::bar(...arguments);
bar.apply(foo,arguments);
尾调用优化
尾调用(tail call)某个函数的最后一步调用了另一个函数
函数调用会在内存中形成调用记录,比如从A调用B,在A中形成一个B的调用帧(call frame),B中在调用C,会在B中形成C的调用帧,所有调用帧会形成调用栈(call stack)
es6只要使用尾递归就永远不会出现栈溢出
尾调用模式仅在严格模式下生效
蹦床函数(trampoline)
function trampoline(f){
while(f && f instanceof Function){
f = f()
}
return f;
}
之前函数参数中是不允许出现尾逗号的,但在新版本中允许尾逗号的出现
const a1=[1,2];
const a2 = a1;
a2[0] = 2;
a1 //[2,2]
直接赋值,获取的是指向a1的指针,改变a2会直接改变a1的值
所以需要使用变通的方法
a2 = a1.concat();
拓展运算符提供了赋值数组的方法
a2 = [...a1]
[...a2] = a1
合并数组:
es5:
[1,2].concat(more)
es6:
[1,2,...more]
在es6中Array,from会将类似数组的对象转为真正的数组
let arrayLike = {
'0':'a',
'1':'b',
'2':'c'
}
let arr2 = Array.from(arrayLike);
类似数组的对象就是拥有length属性的对象,都可以通过array.from转为数组
如果浏览器不支持,则使用array.prototype.slice方法
array.from([1,2,3],(x)=>x*x)
可以使用第二个参数,对其进行处理
array.of可以将一组值转化为数组
Array() // []
Array(3) // [, , ,]
Array(3, 11, 8) // [3, 11, 8]
上面代码中, Array 方法没有参数、一个参数、三个参数时,返回结 果都不一样。只有当参数个数不少于2个时, Array() 才会返回由参数 组成的新数组。参数个数只有一个时,实际上是指定数组的长度。
copyWithin(target,start,end);
target:替换的位置
start:从哪里替换
end:没有指定则为数组默认长度
[1,2,3,4,5].copywithin(0,3)//[4,5,3,4,5]
fill()方法,填充数组
['a','b','c'].fill(7,1,2) //['a',7,'c']
includes返回一个布尔值,表示某个函数是否包含给定的值
[1,2,3].includes(2)
使用indexOf的缺点:
内部严格使用相等运算符(===)进行判断,这会导致对NaN的误判
[NaN].indexOf(NaN) // -1
对象的拓展
const foo = 'value'
const bar = {foo} // bar = {foo : 'value'}
相当于
const bar = {foo: foo}
方法简写:
const a = {
method(){
return "this is a function"
}
}
相当于
const a = {
method() : function(){
return "this is a function"
}
}
name:
bind方法创造的函数,name会返回bound+name,function创造的函数,name属性返回anonymous属性
相等:
es5中相等方法只有两种,一种是(==)还有一种是严格相等(===)
但都有缺点:
前者自动转换数据类型,后者NaN不等于自身,+0等于-0
es6增加了object.is(A,B)方法
与(===)的行为一致,但NaN相等,+0 与 -0不相等
+0 === -0 //true
NaN === NaN // false
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
object.assign()用于方法合并
const target = {a :1}
const source1 = {b:2}
const source2 = {c:3}
object.assign(target,source1,source3);
target //{a:1,b:2,c:3}
如果对象相同,后面会覆盖前面,如果该参数不是对象,会将其转换为对象,然后返回
undefined 和 null 无法转换为对象,所以会报错
const v1 = 'abc';
const v2 = true;
const v3 = 10;
const obj = Object.assign({}, v1, v2, v3);
console.log(obj); // { "0": "a", "1": "b", "2": "c" }
v1 是字符串,v2是布尔类型,v3是数字,结果只有字符串合入了目标对象,数值和布尔值都会被忽略
这是因为因为只有字符串的包装对象,会产生枚举属性
注意:
object.assign实行的是浅拷贝,就是如果源对象的某个属性是引用,那么拷贝的也是引用,也就是说引用的值改变了,那就都跟着变化
同名属性采用替换原则
Object.getOwnPropertyDescriptor(class {foo() {}}.prototype, 'foo').enumerable // false
另外,ES6 规定,所有 Class 的原型的方法都是不可枚举的。
大多数时候,我们至关心对象自身的属性,多以会用object.keys()代替
_proto_属性,用来读取或者设置当前对象的prototype对象
const obj={
method:function(){...}
}
obj._proto_=someOtherObj;
最好使用
object.setPrototypeOf() 写操作
object.getPrototypeOf() 读操作
object.create() 生成操作代替
object.setPrototypeOf是es6正式推荐的设置原型对象的方法
object.getPrototypeOf()获取一个对象的原型对象
super关键字
只能用在对象的方法之中,用在其他地方会报错
对象也可以用解构赋值
但是必须在参数最后一个,也是浅拷贝
克隆完整对象:
const a = object.assign(
object.create(object.getPrototypeof(obj))
)
对象的拓展运算符后面也可以跟表达式
NULL传导运算符
const firstName = message?.body?.user?.firstName || 'default';
只要有一个返回null,都会返回undefined
Symbol:保证每一个属性都是独一无二的,是es6引入symbol的原因
JavaScript一共有7种属性
1.null
2.undefined
3.boolean
4.string
5.number
6.object
7.symbol
let s = Symbol();
typeOf s;
symbol函数前不能使用new命令,否则会报错
symbol函数的参数只是表示对当前symbol值的描述,因此相同参数的symbol函数的返回值是不相等的
symbol不能与其他值进行运算
symbol作为属性名时,该属性属于公开属性,不是私有属性
魔术字符串:在代码中多次出现的,与代码形成强耦合的字符串或者数值
一般都会将其改为变量
symbol.for,symbol,keyFor
let s1= Symbol.for('foo')
let s2 = Symbol.for('foo')
s1 === s2 //true
Symbol和Symbol.for的区别是:
Symbol.for会在全局创建一个供搜索的变量,可以被搜索到,这样每次调用都会是这一个值,但如果不用for,那么每次调用的都会不一样
symbol.keyfor返回的是已登记的symbol类型值的key
Symbol.for为Symbol值登记的名字,是全局环境的,可以在不同的iframe或者service worker中取到同一个值
Singleton模式指的是调用一个类,任何时候返回的都是同一个实例
Symbol.hasInstance:判断是否为该对象的实例
Symbol.isConcatSpreadable:表示该对象用于Array.prototype.concat()是否可以展开
Symbol.species
对象的symbol.species属性,指向当前对象的构造函数。
Symbol.iterator
指向该对象的默认遍历器方法
Set用法:
es6提供了新的数据结构Set
类似于数组,但是成员都是唯一的,没有重复值
const s= new Set()
[2,3,3,6,8].forEach(x=>s,add(x))
let set = new Set()
set.add({});
set.add({});
set.size //2
由于两个空对象不相等,所以它们被视为两个值
Set实例的操作方法:
add(value),delete(value),has(value),clear()
WeakSet结构与Set类似,也是不重复的值的集合
但WeakSet的成员只能是对象,es6中WeakSet不可遍历,WeakSet中的数据不会计入内存回收机制,所以删除实例的时候,不用考虑,也不会出现内存泄漏
Map 键值对
const map = new Map([['name','a'],['title','Author']]);
map.size
map.has('name')
map.get('name')
Set 和 Map都可以生成新的Map对象
Map遍历方法:
keys,values,forEach,entries()
map.forEach(function(value, key, map){
console.log("key:%s,Value:%s",key,value)
})
Map 转数组
const mapDemo = new Map().set(true,7).set({foo:3},['abc'])
[...mapDemo] //转换成数组
数组转Map
Map转为对象
strMapToObj(mapDemo)
对象转map
strObjToMap({yes:true},{no:false});
Map转为Json
strMapToJson(mapDemo);
Map转为数组JSON
strMapToArrayJson(mapDemo);
Json转为Map
jsonToStrMap('{"yes":true,"no":false}')
WeakMap弱引用只是健名,而不是键值,键值依然是正常引用
WeakMap只有四个方法:
get,set,has,delete
weakMap部署私有属性
Proxy:用于修改某些操作的默认行为
proxy实际上重载了点运算符,用自己的定义覆盖了语言的原始定义
var proxy = new Proxy(target,handler);
var proxy = new Proxy({},{
get :function(target,property){
return 35;
}
})
let obj = object.create(proxy);
obj.time //35
Proxy操作一览表
get(garget,propKey,receiver):拦截器对象属性的读取
set(target,proKey,value,receiver):拦截器属性的设置 proxy.foo = v
has(target,proKey):拦截 prokey in proxy操作,返回一个布尔值
deleteProperty(target,propKey):拦截 delete proxy[propKey],返回一个boolean值
ownKeys(target):object.getOwnePropertyNames(proxy),Object,getOwnPropertySymbols(proxy),Object.keys(proxy)
返回一个数组
has()只对in()生效
construct()用于拦截new命令
deleteProperty()用于拦截delete操作
Reflcet 也是ES6为了操作对象而提供的新的API
Object,defineProperty(obj,name,desc)在无法定义属性时,会抛出一个错误
Reflect对象上可以拿到语言内部的方法
Proxy实现观察值模式
使用observable和observe两个函数
promise:
就是一个容器,里面保存着某个为了才会结束的时间,从语法上说,promise是一个对象,从它可以获取异步操作的消息
无法取消promise,一旦新建就会立即执行,无法中途取消。
如果不设置回调函数,promise无法自己抛出错误,无法反应到外部
当处于pending状态时,无法得知目前进展到拿一个阶段
promise.prototype.catch方法是.then(null,regection)的别名,用于指定发生错误时的回调函数
建议使用().then().catch().catch()
promise.all()用于将多个promise实例,包装成一个新的promise实例
var p = Promise.resolve(''Hello")
p.then(function(s){
console.log(s);
})
done()总是处于回调链的尾端,保证抛出任何可能出现的错误
finally()不管对象状态如何,都会执行
Iterator遍历器:
Iterator接口就是为所有数据结构,提供一种统一的访问机制,即for...of
yield*:它会调用该结构的遍历器接口
forEach循环缺点是无法中途跳出,break和return命令都不好用
for..in循环:数组的健名是数字,但它以字符串来循环
会遍历手动添加的其他健
在某些情况下,会无顺序的遍历健名
for..of可以与break,continue,return配合使用
Genenrator.prototype.throw() 可以在函数体
一旦Generator执行过程中抛出错误,且没有被内部捕获,就不会在执行下去了,javascript引擎人呢我这个Generator已经运行结束了。
Generator.prototype.return() 可以返回给定的值,并且终结遍历Generator函数
如果Generator函数内部有try...fninally代码块,那么return方法会推迟到finally代码块执行完在执行
yield*
如果在Generator函数内部,调用另一个Generator函数,默认情况下是没有效果的
这个需要用到yield*,去调用Gneerator函数
如果yield表达式后面跟的是一个遍历器对象,需要在yield表达式后面加上星号,这个就被成为yield*表达式
let obj = { * myGeneratorMethod() { ··· } };
如上述所示,属性前带星号,表示是个Generator函数,等价于
let obj = { myGeneratorMethod: function* () { // ··· } };
Generator是实现状态机的最佳结构
协程适合用于多任务运行的环境,但是运行的协诚只能有一个,其他协程都处于暂停状态。
JavaScript语言的执行环境是单线程的,如果没有异步编程,更不无法使用
function* asyncJob() { // ...其他代码 var f = yield readFile(fileA); // ...其他代码 }
在asyncJob中,当函数运行到yield时,会将执行权交给其他协程,等到执行权返回再继续执行
将参数出入一个临时函数,临时函数在传入函数体,这个临时函数就叫做thunk函数
thunkify模块
生产环境的转换器建议使用thunkify模块
co模块:用于generator函数的自动执行
处理stream:
node提供stream模式读写数据,一次只处理数据的一部分,会释放三个事件:
data事件:下一块数据库已经准备好了
end事件:整个数据量处理完了
error事件:发生错误
async函数:
1.内置执行器
2.更好的语义
3.更广的适用性
4,返回值是promise,这样就可以使用then进行下一步操作
await命令,await命令后面是一个promise对象,如果不是,会被转为一个立即resolve的promise对象
多个await命令后面的异步操作,如果不存在继发关系,最好让它们同时触发
let [foo,bar] = await Promise.all(getFoo(),getBar());
如果希望多个请求并发执行,可以使用promise.all方法
fetch方法,远程读取url
fetch(url);
async function logInOrder(urls) { // 并发读取远程URL
const textPromises = urls.map(async url =>
{ const response = await fetch(url); return response.text(); }); // 按次序输出
for (const textPromise of textPromises)
{ console.log(await textPromise); } }
虽然map方法的参数是async函数,但它是并发执行的,应为只有async函数是继发执行,外部不受影响
for awat...of
遍历异步的Iterator接口
异步Generator函数内部可以同时使用await和yield命令,await命令用于将外部操作产生的值输入函数内部,yield命令用于将函数内部的值输出
javascript的四种函数方式,普通型函数,generator函数,async函数,异步generator函数
如果是一系列按照顺序执行的异步操作比如读取文件,写入新内容,在存入硬盘,可以使用async函数
如果是一系列产生相同数据结构的异步操作,可以使用异步generator函数
constructor方法:构造方法,this关键字则代表实例对象
类和模块内部就是严格模式,所以不需要use strice指定运行模式
类必须使用new调用,否则会报错,这个是它跟普通构造函数的一个主要区别
在生产环境,我们可以使用object.getPrototyoeOf方法来获取实例对象的原型
Class表达式
const MyClass = class Me{
getClassName(){
return Me,name;
}
}
上述定义了一个类,但类的名字不是Me,而是MeClass方法
在内部可以使用Me来指代当前类
不存在变量提升:
类不存在变量提升
new Foo();
class Foo{};
上面代码中,Foo类使用在前,定义在后,这样会报错
因为Es6不会自动将类的声明提升到代码头部
this 的指向
class Logger{
printName(name = 'there'){
this,print('hahha')
}
print(text){
console.log(text)
}
}
const logger = new Logger();
const {printName} = logger;
printName();//会报错,找不到print方法
修改方法,在方法中绑定this
thsi.printName = this.printName.bind(this);
或者使用箭头函数
this.printName = (name = 'there') =>{
this.print('hello')
}
因为此时this指向的不是内部,而是当前环境
class的静态方法
所有类中定义的方法都会被实例继承,但是如果前面加了static,那么这个方法就不会被实例继承,而是通过类来调用,这就成为静态方法
类的实例属性:用等号,写入类的定义中
new.target 用在构造函数之中,返回new命令作用于那个构造函数
class可以通过extends关键字实现继承
super关键字
class A {}
class B extends A{
constructor(){
super();
}
}
子类B的构造函数之中的super(),代表调用父类的构造函数,这个是必须要求
在子类构造函数中,supper指向父类的原型对象,所以定义在父类实例上的方法或者属性,是无法通过super调用的
Mixin:多个对象合成一个新的对象
修饰器只能用于类和类的方法,不能用于函数,因为存在函数提升
core-decorators.js
第三方模块,提供了几种常用的装饰器
@autobind:使得方法中的this对象,绑定原始对象
@readonly:使得属性或方法不可写
@override:检查子类的方法是否正确覆盖了父类的同名方法,如果不正确,会报错
@deprecate:在控制台显示一条信息,显示此方法已被废弃
@supressWarinings:抑制@deprecate导致的输出waring的行为,但是异步代码发出的调用除外
const Foo = {
foo(){
console.log('foo')
}
}
class MyClass{}
Object.assign(MyClass.prototype,Foo);
let obj = new MyClass();
obj.foo();
通过object.assign方法,可以将Foo方法放进myClass类中
Trait也是一种修饰器,效果与Mixin类似,但是提供了更多功能,比如防止同名方法的冲突,排除混入某些方法,为混入的方法起别名等
@traits(TFoo, TBar::alias({foo: 'aliasFoo'}))
@traits(TExample::excludes('foo','bar')::alias({baz:'exa mpleBaz'}))
以上为起别名和排除方法
Babel转码器的支持
在线转码网址:
https://babeljs.io/repl/
Modeule
在Es6之前,javascript一直没有模块这个概念,所以用的是CommonJs和AMD两种,在es6之后,有了模块功能,可以在编译时就确定模块的依赖关系,以及输入和输出的变量,CommonJs和AMD都只能在运行时确定这些东西,
// ES6模块 import { stat, exists, readFile } from 'fs';
表示只加载fs中的这三个方法,其他的都不加载
ES6自动采用严格模式
1.变量必须声明后使用
2.函数的参数不能有同名属性
3.不能使用with语句
4.不能对只读属性赋值,否则报错
5.不能使用前缀0表示八进制数,否则报错
6.不能给只读属性赋值
7.不能删除不能删除的属性
8.eval不会再外层作用域引入变量
9.arguments和eval不能重新被赋值
10.argument不会自动反应函数参数的变化
11.不能使用argument.callee
12.不能使用argument.caller
13.禁止this指向全局对象
14.不能使用 fn.caller 和 fn.arguments 获取函数调用的堆栈
15.增加了保留字(比如 protected 、 static 和 interface )
export命令
模块功能主要由两个命令构成,export和import.
export命令主要规定模块的对外接口
import用于输入其他模块提供的功能
默认情况下,浏览器试同步加载javaScript脚本,即渲染引擎遇到
打开对应属性,就会异步加载
defer和async属性的区别:
前者要等到整个页面正常渲染结束,才会执行
后者一旦下载完,渲染引擎就会中断渲染,执行这个脚本后,在继续渲染
defer是渲染完就执行
async是下载完就执行
如果有多个defer脚本,会按照它们在页面出现的顺序加载,多个async脚本是不能保证加载顺序的
模块加载规则:
需要加入type="module"才可以
模块加载默认为defer模式
模块一旦使用了async属性,