ES6学习总结(五)
class和class继承
为什么要引入class?
要知道,JavaScript是没有类的概念的,我们在面向对象编程的时候,通常会是编写一个构造函数。把属性写在函数里,方法放在原型上。
function constructor(a,b){
this.a = a;
this.b = b;
}
constructor.prototype.add = function (){
return this.a + this.b
}
var aa = new constructor(1,2)
aa.add() //3
这样的写法很容易让Java、python等编程人员产生疑惑,引入class,作为一个语法糖来编写,在表现形式上更靠近传统的面向对象语法。不过究其根本,本质上还是原型。下面的新写法和python的对比。
class People{ //或者 let People = MyPeople {
constructor(n,a){
this.name = n
this.age = a
}
speack() {
console.log(`${this.name}说: 我${this.age}岁了`)
}
}
let s= new People('xiaoming',10); //let s= new MyPeople('xiaoming',10);
s.speack() //xiaoming说: 我10岁了
class People:
# 定义基本属性
name = ''
age = 0
# 定义构造方法
def __init__(self, n, a):
self.name = n
self.age = a
def speack(self):
print("%s 说: 我 %d 岁了" % (self.name, self.age))
s = People('xiaoming','10')
s.speack() #xiaoming说: 我10岁了
这样对比看起来是不是就很直观了。
以下要注意几点:
1.类的所有方法定义在类的prototype属性上
2.类的内部定义方法不可枚举 Object.keys(People) // []
3.类默认使用严格模式
4.类不存在变量提升,所以一定要先声明再使用。
类的实例对象
类使用new命令生成实例对象,而不能直接像python那样调用,否则会报错。
实例的属性除非显示定义在其本身(this对象上),否则都定义在原型class上,这样其实更符合实际情况。
类的静态方法
class People{ //或者 let People = MyPeople {
constructor(n){
this.name = n
}
speack(){ //类的普通方法
//...
}
static talk(){ //类的静态方法
//...
}
}
在方法名前加static 就变成了静态方法,看下图,静态方法在类prototype.constructor上,普通方法在prototype上。
所以,实例是不能继承静态方法的。 不过子类可以继承父类的静态方法。
类的静态属性
阮一峰老师在写《ES6标准入门》的时候,类的静态方法还只是作为一个提案,不过现在已经标准化了。 同静态方法一样,静态属性需要在属性名前加 static.
static talk ="talk"
new.target
ES6为构造函数和类引入new.target属性。当通过new来生成实例时,内部的new.target会返回构造函数或类。 首先是构造函数,注意看下图的注释。
function People(){
log(new.target)
}
let myfoo1 = new People(); //返回构造函数
let myfoo2 = People(); //返回undefined
然后是类,当未使用new的时候就会报错
class People{
constructor(){
log(new.target)
}
}
let myfoo = new People(); //返回类
let myfoo = People(); //Uncaught TypeError: Class constructor People cannot be invoked without 'new'
注意
类有name属性,也有getter和setter。类的方法内部如果含有this,它将指向默认类的实例。 类的内部方法也支持Generator方法,
ES5在继承的时候,通常会让父函数使用apply或者call。绑定子函数的this去调用父函数的方法。
ES6的类继承机制不同。子类没有this,需要继承父类的this,进而对其加工。所以下面在子类中需要先super()继承父类this,然后才能使用this。
再来看看和python的对比
class People{
constructor(n,a){
this.name = n
this.age = a
}
}
class Kid extends People{
constructor(n,a,g){
super(n,a)
this.grade = g
}
speack() {
console.log(`${this.name}说: 我${this.age}岁了,${this.grade}年级`)
}
}
let s= new Kid('xiaoming',10,2);
s.speak()//xiaoming说: 我10岁了,2年级
class People:
# 定义基本属性
name = ''
age = 0
def __init__(self, n, a):
self.name = n
self.age = a
class Kid(People):
grade= ''
def __init__(self, n, a, g):
# 调用父类的构函
self.grade= g
s = Kid('xiaoming',10,2)
s.speak() #xiaoming说: 我10岁了,2年级
ES6类的写法相比之下和python2更像而不是上图的python3。
super 可作为 函数,也可作为 对象 使用。 ES6规定子类必须使用一次super()方法,来调用父类的构造函数。constructor(n,a,g){ super(n,a) this.grade = g }
注意下面是难点
作为 对象,super既能指向父类的prototype(原型方法),又能指向父类(静态方法,(注意是 方法,而不是属性) 。但不能指向父类的实例(实例方法)。。 super在普通方法中指向父类的prototype,在静态方法中指向父类。
直观来说就是。。。
let log = console.log.bind(console)
class People{
fu_lei_prototype() {
return 'fu_lei_prototype'; //可以取到父类的prototype
}
static fu_lei () {
return 'fu_lei' //可以取到父类
}
constructor(){
this.fu_lei_shili = 'fu_lei_shili'
}
}
class Kid extends People{
constructor(){
super() //作为函数使用,必须使用一次super()方法
log(super.fu_lei_shili) //undefined
log(super.fu_lei_prototype()) //fu_lei_prototype
}
static fu_lei () {
log(super.fu_lei())
}
}
log( Kid.fu_lei ) //fu_lei
这里有点稍微难理解,需要理清思路,可以先收藏回头再看。
另外提一嘴,super在普通方法中调用父类原型,会绑定到子类的this上。
class People{
people= '大汽车'
constructor(n,a){
this.name = n
this.age = a
}
speack() {
console.log(`${this.name}说: 我${this.age}岁了,我爱玩${this.people}`)
}
}
class Kid extends People{
people = '小玩具车'
constructor(n,a){
super(n,a)
}
}
let myfoo = new Kid('xiaoming',10);
myfoo.speack() // xiaoming说: 我10岁了,我爱玩小玩具车
so,这里绑定了子类的this,调用了Kid的people。所以myfoo.speack()输出是爱玩小玩具车而不是大汽车。
类的__ proto__ 和 prototype
class People{
}
class Kid extends People{
}
let man = new People()
let child = new Kid()
- 子类的__proto__总是指向父类
Kid.__proto__ === People //true
- 子类的prototype的__proto__总是指向父类的prototype
Kid.prototype.__proto__ === People.prototype //true
- 实例的__proto__的__proto__指向父类实例的__proto__
child.__proto__.__proto__ === man.__proto__ //true
好啦,就先到这里,短短一篇文章写了将近四个小时,休息去了。@_@
还有最后一篇,Module的加载实现
写的不错,点个赞鼓励下 =v =
上一篇 ES6学习总结(四)
下一篇 ES6学习总结(六)