ES6学习总结(五)

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方法,


  • 2.class继承

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学习总结(六)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值