ECMAScript发展历史
(1)ECMA-262 第1版:去除了对针对浏览器的特性,支持Unicode标准(多语言开发),对象也变成了和平台无关的。(1997年)
(2)ECMA-262 第2版:没有增删改,就是编辑加工工作。(1998年6月)
(3)第三版ECMAScript3新增了对正则表达式、新控制语句、try-catch异常处理的支持,修改了字符处理、错误定义和数值输出等内容。标志着ECMAScript成为了一门真正的编程语言。(1999年12月)
(4)第四版于2008年7月发布前被废弃, 但是它的大部分内容被ES6继承了。
(5)第五版ECMAScript5力求澄清第3版中的歧义,并添加了新的功能。新功能包括:原生JSON对象、继承的方法、高级属性的定义以及引入严格模式。
(6)第六版ECMAScript6是继ES5之后的一次主要改进,增添了许多必要的特性,例如:模块和类以及一些实用特性,Maps、Sets、Promises、生成器(Generators)等。
ECMAScript5部分新增特性简介
一、浏览器支持:
Chrome13+、FireFox4+、Safari 5.1、IE9
IE9不支持严格模式
Safari5.1*不支持function.prototype.bind方法
二、JSON对象
JSON.parse(jsonstr) 将json字符串转化成json对象
JSON.stringify(jsonobj) 将json对象转化成json字符串
eval() :
它可以编译执行任何JavaScript程序,因此产生了安全性问题。当使用可信任与完善的源代码时才可以使用eval函数。
json2.js :
https://github.com/douglascrockford/JSON-js/blob/master/json2.js
三、新增Object接口
对象 | 构造器 | 说明 |
---|---|---|
Object | getPrototypeOf | 返回对象的原型 |
Object | GetOwnPropertyDescriptor | 返回对象自有属性的属性描述符 |
Object | getOwnPropertyNames | 返回一个数组,包括对象所有自有属性名称集合(包括不可枚举的属性) |
Object | create | 创建一个拥有置顶原型和若干个指定属性的对象 |
Object | defineProperty | 给对象定义一个新属性,或者修改已有的属性,并返回 |
Object | defineProperties | 在一个对象上添加或修改一个或者多个自有属性,并返回该对象 |
Object | seal | 锁定对象。阻止修改现有属性的特性,并阻止添加新属性。但是可以修改已有属性的值。 |
Object | freeze | 冻结对象,阻止对对象的一切操作。冻结对象将永远不可变。 |
Object | preventExtensions | 让一个对象变的不可扩展,也就是永远不能再添加新的属性。 |
Object | isSealed | 判断对象是否被锁定 |
Object | isFrozen | 判断对象是否被冻结 |
Object | isExtensible | 判断对象是否可以被扩展 |
Object | keys | 返回一个由给定对象的所有可枚举自身属性的属性名组成的数组 |
Objec.defineProperty 设置对象属性:
value, writable, enumerable, configurable
Object.create 兼容性处理:
if(!Object.create){
Object.create = function(proto){
function F(){};
F.prototype = proto;
return new F();
}
}
缺点:无法继承“父类”自身的属性
经典的继承:
function SuperClass(name){
this.name = name;
}
SuperClass.prototype.sayName = function(){
alert(this.name);
}
function SubClass(name,age){
SuperClass.call(this,name);
this.age = age;
}
SubClass.prototype = SuperClass.prototype;//错误的 在SubClass.prototype上面添加属性的时候,SuperClass.prototype也会被修改。
SubClass.prototype = new SuperClass(); //不好,不能给SuperClass传参
SubClass.prototype = Object.create(SuperClass.prototype); //原型链写不向上查找的特性
SubClass.prototype.constructor = SubClass;
SubClass.prototype.sayAge = function(){
alert(this.age);
}
var sub = new SubClass("nie",19);
sub.sayAge();
sub.sayName();
四、新增Array接口
对象 | 构造器 | 说明 |
---|---|---|
Array.prototype | indexOf | 返回根据给定元素找到的第一个索引值,否则返回-1 |
Array.prototype | lastIndexOf | 方法返回指定元素在数组中的最后一个的索引,如果不存在则返回 -1 |
Array.prototype | every | 测试数组的所有元素是否都通过了指定函数的测试 |
Array.prototype | some | 测试数组中的某些元素是否通过了指定函数的测试 |
Array.prototype | forEach | 让数组的每一项都执行一次给定的函数 |
Array.prototype | map | 返回一个由原数组中的每个元素调用一个指定方法后的返回值组成的新数组 |
Array.prototype | filter | 利用所有通过指定函数测试的元素创建一个新的数组,并返回 |
Array.prototype | reduce | 接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终为一个值 |
Array.prototype | reduceRight | 接受一个函数作为累加器,让每个值(从右到左,亦即从尾到头)缩减为一个值 |
另外,还有一个 Array.isArray(),用来判断某一对象是否为数组。(typeof判断的话,返回object,用instanceof判断的话,IE上的返回值不正确)
低版本浏览器判断数组的方法:
function isArray(o) {
return Object.prototype.toString.call(o) ==="[object Array]";
}
五、Function.prototype.bind
bind()方法会创建一个新函数,称为绑定函数.当调用这个绑定函数时,绑定函数会以创建它时传入bind()方法的第一个参数作为 this,传入 bind() 方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数。
这个方法可以改变this的指向,为函数自定义 this指针。
作用和call,apply类似,区别是 bind将会返回一个新的函数,而 call或者 apply并不会返回一个新的函数,它们将会使用新的 this指针直接进行函数调用
兼容性解决:
if(!Function.prototype.bind){
Function.prototype.bind = function(context){
var self = this;
var args = Array.prototype.slice.call(arguments);
return function(){
self.apply(context,args.slice(1));
}
}
}
六、String.prototype.trim()
String.prototype.trim = function(){
return this.replace(/^\s+|\s+$/g,"");
}
ECMAScript6部分新增特性简介
一、 let命令和const命令
1、let命令
(1)、let命令,用来声明变量。用法和var类似,区别是let声明的变量只在let所在的代码块中起作用。
if(true){
let a = 0;
var b =1;
}
console.log(a) // ReferenceError: a is not defined
console.log(b) //1
(for循环的计数器很适合用let命令。)
(2)、let命令不会产生变量提升
console.log(a); //undefined
console.log(b);// ReferenceError: b is not defined
var a= 0;
let b =1;
(3)、暂时性死区,代码块内若使用了let命令,则在使用let命令声明变量之前,该变量都是不可用的,在语法上称为“暂时性死区”(temporal dead zone)
var a = 0;
if(true){
console.log(a);// ReferenceError: a is not defined
let a = 0;
}
在let命令声明变量之前,都是变量的“死区”
if(true){
a = 1; // ReferenceError: a is not defined
console.log(a); // ReferenceError: a is not defined
let a;
console.log(a);//undefined
a= 123;
console.log(a);//123
}
(4) let不允许在相同作用域内,重复声明同一个变量
if(true){
var a= 0;
let a = 1;
console.log(a);
}// SyntaxError: Identifier 'a' has already been declared
function testFun(arg){
let arg = 0;
}
testFun(1); // SyntaxError: Identifier 'arg' has already been declared
function testFun2(arg){
let arg = 0;
}
testFun2(1);//不报错
(5) 块级作用域的出现,实际上使得获得广泛应用的立即执行匿名函数(IIFE)不再必要了。
//匿名函数写法
(function(){
var temp = 0;
})();
//块级作用域写法
{
let temp = 0;
}
2、const命令
(1)、const声明一个只读的常量。一旦声明,常量的值就不能改变,而且声明的时候必须立即初始化。
const a = 1;
console.log(a);
a= 2;//TypeError: Assignment to constant variable.
const b;//SyntaxError: Missing initializer in const declaration
(2)、const命令的一些特性:块级作用域,不会变量提升,同一作用域内不能重复定义。
(3)、const声明引用型变量时,变量的地址是不能改变的。
const obj = {};
obj.name="nie";
obj = {};// TypeError: Assignment to constant variable.
(4) ES5之中,全局变量会作为全局对象的属性,ES6中全局变量将逐步和全局对象的属性分离,let命令,const命令,class命令声明的全局变量,不属于全局对象的属性。
var a = 123;
console.log(window.a);//123
let b =1;
console.log(window.b);//undefined
二、变量的解构赋值
1、 数组的解构赋值:只要等号两边的模式相同,左边的变量就会被赋予对应的值
let [a,b,c] = [1,2,3];
console.log(a);//1
console.log(b);//2
console.log(c);//3
let[d,[e,[f]]] = [1,[2,[3]]];
console.log(d);//1
console.log(e);//2
console.log(f);//3
let[g,h,...i] = [1,2,3,4];
“...i”表示数组,只能放到最后。
let[j,...k,l] = [1,2,3,4,5];// SyntaxError: Rest element must be last element in array
只要某种数据结构具有Iterator接口,都可以采用数组形式的解构赋值
2、对象的解构赋值
var person = {
"name":"nie",
"gender":"male"
}
var {name} = person;
console.log(name);
var {name,gender} = person;
console.log(name);
console.log(gender);
var{name:na,gender:gen} = person;
三、数组的扩展
1、 Array.from()
Array.from方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括ES6新增的数据结构Set和Map)。
var objArrLike = {
'0':1,
'1':2,
'2':3,
length:3
}
ES5:
var arr = Array.prototype.slice.call(objArrLike);
ES6 :
var arr = Array.from(objArrLike); //[1,2,3]
Array.of : 方法用于将一组值,转换为数组
在ES6中Array还有其他的很多扩展可以自行查找资料
四、函数的扩展
1、可以为函数的参数指定默认值。
ES5:
function testFun(x,y){
y = y||"iflytek";
console.log(x,y);
}
testFun("Hello") //Hello iflytek
ES6:
function testFun(x,y="iflytek"){
console.log(x,y);
}
testFun("Hello"); //Hello iflytek
2、与解构赋值默认值结合使用
function testFun({x,y = 5}){
console.log(x,y);
}
testFun({x:1,y:2}); //1 2
也可以用数组的解构赋值对函数参数进行默认值赋值
3、指定了默认值以后函数的长度length将失真(arguments.callee.length) 有相同的效果
(function testFun(a,b,c =2){}).length // 2
function testFun(a,b,c){
console.log(arguments.callee.length);
} //3
4、rest参数,形式为“...变量名”,用于获取函数的多余参数,rest参数搭配的变量是一个数组。
function sortNums(){
return Array.prototype.slice.call(arguments).sort();
}
sortNums(3,2,1);//[1,2,3]
var sortNums = (...restArgs)=>{
return restArgs.sort();
}
sortNums(3,2,1) //[1,2,3]
注意,rest参数之后不能再有其他参数(即只能是最后一个参数),否则会报错。
5、扩展运算符(...) 相当于rest参数的逆运算,将数组转化成逗号分隔的参数序列 注意和[].join(‘,’)的区别
console.log(1,2,...[3,4,5],6) //1 2 3 4 5 6
扩展运算符可以展开数组,所以不需要apply方法将数组转化成函数的参数了
ES5:
var args = [1,2,3]
function testFun(x,y,z){
console.log(x,y,z);
}
testFun.apply(null,args); //1 2 3
ES6:
testFun(...args);//1 2 3
6、扩展运算符的应用:
(1)、合并数组
ES5:
[1,2].concat([3,4]);//[1,2,3,4]
ES6:
[1,2,...[3,4]] //[1,2,3,4]
(2)、将字符串转化成字符串数组
[...'123'] //['1','2','3']
注:任何Iterator接口的对象,都可以用扩展运算符转为真正的数组
7、箭头函数
ES6允许使用“箭头”(=>)定义函数
var f = (x)=>x;
var f = function(x){
return x;
}
var add = (x,y)=>{
return x+y;
}
var add = function(x,y){
return x+y;
}
注意:
(1)、函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
(2)、不可以当做构造函数,不可以使用new命令,报错。
(3)、不可以用arguments对象,该对象在函数体内不存在,用rest参数代替。
(4)、不可以使用yield命令,因此箭头函数不能用作Generator函数。
var id = 1;
function test(){
setTimeout(function(){
console.log(this.id);
});
}
test.call({id:2}) //1
function test(){
setTimeout(()=>{
console.log(this.id);
});
}
test.call({id:2}) //2
五、对象的扩展
1、 ES6允许直接写入变量和函数,作为对象的属性和方法。ES6允许对象之中只写属性名,不写属性值。此时,属性值等于属性名所代表的变量。
var name = "iflytek";
var person = {
name,
gender:'male',
sayName(){
console.log(name),
}
}
2、 属性名表达式,ES6允许字面量定义对象时,用方法二(表达式)作为对象的属性名,即把表达式放在方括号内
ES5:
var person={
name:"nie",
gender:"male"
}
ES6:
var person = {
["name"]:"nie",
["gen"+"der"]:"male"
}
增强的对象字面量
对象字面量被增强了,写法更加简洁与灵活,同时在定义对象的时候能够做的事情更多了:
(1)可以在对象字面量里面定义原型
(2)定义方法可以不用function关键字
(3)直接调用父对象方法
var person = {
name:"nie",
sayName(){
console.log(this.name);
}
}
var malePerson = {
__proto__:person,
gender:"male",
sayGender(){
console.log(this.gender);
}
}
malePerson.name;//nie
malePerson.sayName();//nie
六、Symbol类型
ES6引入了一种新的原始数据类型Symbol,表示独一无二的值。它是JavaScript语言的第七种数据类型,前六种是:Undefined、Null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。
对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增的Symbol类型。凡是属性名属于Symbol类型,就都是独一无二的,可以保证不会与其他属性名产生冲突
var symbolStr = Symbol(); //作为对象的属性,用法和字符串一样的
第一种写法:
var a={}
a[symbolStr] = "iflytek";
第二种写法:
var a = {
[symbolStr]:"iflytek"
}
第三种写法:
var a= {};
Object.defineProperty(a,symbol,{value:"iflytek"})
a[symbolStr]//iflytek
七、Proxy概述
Proxy用于修改某些操作的默认行为,等同于在语言层面做出修改。Proxy可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。
实例:
var target = {name:"nie"};
var obj = new Proxy(target,{
set:function(target,key,reciver){
console.log("set "+ key +"value :" +reciver);
//target[key] = reciver;
return Reflect.set(target,key,reciver);
}
});
下面是Proxy支持的拦截操作一览。
对于可以设置、但没有设置拦截的操作,则直接落在目标对象上,按照原先的方式产生结果。
(1) get(target, propKey, receiver)
拦截对象属性的读取,比如proxy.foo和proxy['foo']。
最后一个参数receiver是一个对象,可选,参见下面Reflect.get的部分。
(2) set(target, propKey, value, receiver)
拦截对象属性的设置,比如proxy.foo = v或proxy['foo'] = v,返回一个布尔值。
(3) has(target, propKey)
拦截propKey in proxy的操作,以及对象的hasOwnProperty方法,返回一个布尔值。
(4) deleteProperty(target, propKey)
拦截delete proxy[propKey]的操作,返回一个布尔值。
(5) ownKeys(target)
拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy),返回一个数组。该方法返回对象所有自身的属性,而Object.keys()仅返回对象可遍历的属性。
(6) getOwnPropertyDescriptor(target, propKey)
拦截Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。
(7) defineProperty(target, propKey, propDesc)
拦截Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs),返回一个布尔值。
(8) preventExtensions(target)
拦截Object.preventExtensions(proxy),返回一个布尔值。
(9) getPrototypeOf(target)
拦截Object.getPrototypeOf(proxy),返回一个对象。
(10) isExtensible(target)
拦截Object.isExtensible(proxy),返回一个布尔值。
(11) setPrototypeOf(target, proto)
拦截Object.setPrototypeOf(proxy, proto),返回一个布尔值。
如果目标对象是函数,那么还有两种额外操作可以拦截。
(12) apply(target, object, args)
拦截Proxy实例作为函数调用的操作,比如proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)。
(13) construct(target, args)
拦截Proxy实例作为构造函数调用的操作,比如new proxy(...args)。
八、Reflect概述
(1) 将Object对象的一些明显属于语言内部的方法(比如Object.defineProperty),放到Reflect对象上。现阶段,某些方法同时在Object和Reflect对象上部署,未来的新方法将只部署在Reflect对象上。
(2) 修改某些Object方法的返回结果,让其变得更合理。比如,Object.defineProperty(obj, name, desc)在无法定义属性时,会抛出一个错误,而Reflect.defineProperty(obj, name, desc)则会返回false。
(3) 让Object操作都变成函数行为。某些Object操作是命令式,比如name in obj和delete obj[name],而Reflect.has(obj, name)和Reflect.deleteProperty(obj, name)让它们变成了函数行为。
(4) Reflect对象的方法与Proxy对象的方法一一对应,只要是Proxy对象的方法,就能在Reflect对象上找到对应的方法。这就让Proxy对象可以方便地调用对应的Reflect方法,完成默认行为,作为修改行为的基础。也就是说,不管Proxy怎么修改默认行为,你总可以在Reflect上获取默认行为。
Reflect对象的方法清单如下,共13个。
• Reflect.apply(target,thisArg,args)
• Reflect.construct(target,args)
• Reflect.get(target,name,receiver)
• Reflect.set(target,name,value,receiver)
• Reflect.defineProperty(target,name,desc)
• Reflect.deleteProperty(target,name)
• Reflect.has(target,name)
• Reflect.ownKeys(target)
• Reflect.isExtensible(target)
• Reflect.preventExtensions(target)
• Reflect.getOwnPropertyDescriptor(target, name)
• Reflect.getPrototypeOf(target)
• Reflect.setPrototypeOf(target, prototype)
上面这些方法的作用,大部分与Object对象的同名方法的作用都是相同的,而且它与Proxy对象的方法是一一对应的。
九、Set/Map 概述
1、ES6提供了新的数据结构Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。
3、 JavaScript的对象(Object),本质上是键值对的集合(Hash结构),但是传统上只能用字符串当作键。这给它的使用带来了很大的限制。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object结构提供了“字符串—值”的对应,Map结构提供了“值—值”的对应,是一种更完善的Hash结构实现。如果你需要“键值对”的数据结构,Map比Object更合适。
十、数据结构的默认Iterator接口
Iterator接口的目的,就是为所有数据结构,提供了一种统一的访问机制,即for...of循环(详见下文)。当使用for...of循环遍历某种数据结构时,该循环会自动去寻找Iterator接口。
ES6规定,默认的Iterator接口部署在数据结构的Symbol.iterator属性,或者说,一个数据结构只要具有Symbol.iterator属性,就可以认为是“可遍历的”(iterable)。调用Symbol.iterator方法,就会得到当前数据结构默认的遍历器生成函数。Symbol.iterator本身是一个表达式,返回Symbol对象的iterator属性,这是一个预定义好的、类型为Symbol的特殊值,所以要放在方括号内(请参考Symbol一章)。
在ES6中,有三类数据结构原生具备Iterator接口:数组、某些类似数组的对象、Set和Map结构。for...of循环会自动遍历它们。除此之外,其他数据结构(主要是对象)的Iterator接口,都需要自己在Symbol.iterator属性上面部署,这样才会被for...of循环遍历。
let obj = {
data:['a','b'],
[Symbol.iterator]:function(){
const self = this;
let index = 0;
return {
next(){
if(index<self.data.length){
return {
value:self.data[index++],
done:false
};
}else{
return {value:undefined,done:true};
}
}
}
}
}
for(item of obj){
console.log(item);//a b
}
十一、Generator函数
1、调用Generator函数,返回一个遍历器对象,代表Generator函数的内部指针。以后,每次调用遍历器对象的next方法,就会返回一个有着value和done两个属性的对象。value属性表示当前的内部状态的值,是yield语句后面那个表达式的值;done属性是一个布尔值,表示是否遍历结束。
2、yield语句
由于Generator函数返回的遍历器对象,只有调用next方法才会遍历下一个内部状态,所以其实提供了一种可以暂停执行的函数。yield语句就是暂停标志。
遍历器对象的next方法的运行逻辑如下。
(1) 遇到yield语句,就暂停执行后面的操作,并将紧跟在yield后面的那个表达式的值,作为返回的对象的value属性值。
(2) 下一次调用next方法时,再继续往下执行,直到遇到下一个yield语句。
(3) 如果没有再遇到新的yield语句,就一直运行到函数结束,直到return语句为止,并将return语句后面的表达式的值,作为返回的对象的value属性值。
(4) 如果该函数没有return语句,则返回的对象的value属性值为undefined。
需要注意的是,yield语句后面的表达式,只有当调用next方法、内部指针指向该语句时才会执行,因此等于为JavaScript提供了手动的“惰性求值”(Lazy Evaluation)的语法功能。
实例:
function* funGenerator(){
yield console.log("this is a yield function");
}
var f = funGenerator();
setTimeout(()=>{
f.next();
},2*1000);
十二、Promise对象
Promise是异步编程的一种解决方案。有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供统一的接口,使得控制异步操作更加容易。
示例:
var testPromise = function(x){
return new Promise(function(resolve,reject){
if(x>5){
resolve(x);
}else{
reject(x);
}
});
}
testPromise(1).then(function(value){
console.log(value +" 大于5");
},function(value){
console.log(value + " 小于5");
});
1、Promise.prototype.then
then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法。第一个回调函数完成以后,会将返回结果作为参数,传入第二个回调函数。
示例:
testPromise(1).then(function(value){
console.log(value +" 大于5");
return value +1;
},function(value){
console.log(value + " 小于5");
return value +1
}).then(function(){
}); //此时第二个函数是调用不到的
2、Promise.prototype.catch
Promise.prototype.catch 是 .then(null,rejection)的别名,用来指定发生错误时的回调函数。
如果Promise的状态已经变为Resolved,再抛出错误是无效的。
var promise = new Promise(function(resolve,reject){
resolve("ok");
throw new Error("err");
});
promise.then(function(value){
console.log(value);
}).catch(err){
console.log("错误信息:"+err.message);
}
Promise对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch语句捕获
catch方法返回的还是一个Promise对象,因此后面还可以接着调用then方法。
catch方法指定的回调函数,会接着运行后面那个then方法指定的回调函数。如果没有报错,则会跳过catch方法。
十三、Class
1、Javascript的传统方法是通过构造函数来定义并生成新的对象,ES6提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。
传统写法:
function Person(name,age){
this.name = name;
this.age = age;
}
Person.prototype.sayName = function(){
console.log(this.name);
}
var person = new Person();
ES6:
class Person{
constructor(name,age){
this.name = name;
this.age = age;
}
sayName(){
console.log(this.name);
}
}
var person = new Person();
console.log(typeof Person);//function
console.log(Person.prototype.constructor === Person);//true
2、类的数据类型就是函数,类本身就指向构造函数。
使用的时候,也是直接对类使用new命令,跟构造函数的用法完全一致。
事实上,实例的属性除非显式定义在其本身(即定义在this对象上),否则都是定义在原型上(即定义在class上)。可以通过打印prototype属性进行验证。
3、class不存在变量提升
var person = new Person();
class Person{
}//ReferenceError: Person is not defined
Class的继承
Class之间可以通过extends关键字实现继承。
class MalePerson extends Person{
constructor(name,age,gender){
super(name,age);
this.gender = gender;
}
sayGender(){
console.log(this.gender);
}
}
MalePerson.__proto__ =
Super关键字
super这个关键字,有两种用法,含义不同。
(1) 作为函数调用时(即super(...args)),super代表父类的构造函数。
(2) 作为对象调用时(即super.prop或super.method()),super代表父类。注意,此时super即可以引用父类实例的属性和方法,也可以引用父类的静态方法。
class Person{
constructor(name,age){
this.name = name;
this.age = age;
}
sayName(){
console.log(this.name);
}
}
class MalePerson extends Person{
constructor(name,age,gender){
super(name,age);
this.gender = gender;
}
saySuperName(){
console.log(super.name);//undefined
console.log(this.name);//nie
super.sayName();//nie
}
}
super.IdentifierName作为getter使用时,表示函数B的prototype属性对象的[[prototype]];
getter : SubClas.prototype.proto / SuperClass.prototype
super.IdentifierName作为setter使用时,super表示this;
setter: this
若通过super.IdentifierName()来调用函数,则此时的函数相当于 .call(this)来调用
IdentifierName.all(this)
Class的静态方法
类中定义的方法前面加上static关键字,即为静态方法,通过Class.FunctionName的形式调用。
父类的静态方法,可以被子类继承。可以通过super关键字调用。
class MalePerson extends Person{
constructor(name,age,gender){
super(name,age);
}
static sayHello(){
alert("Hello");
//alert(MalePerson.hello);
}
}
MalePerson.hello = "hello"; // ES6明确规定,Class内部只有静态方法,没有静态属性。只能在外部定义静态属性,ES7可能会做修改
MalePerson.sayHello();
十四、字符串模板
字符串模板相对简单易懂些。ES6中允许使用反引号 ` 来创建字符串,此种方法创建的字符串里面可以包含由美元符号加花括号包裹的变量${vraible}。
var name = "nie";
console.log(`my name is ${name}`);
参考资料:
阮一峰 ECMAScript6入门
ES6新特性概览