0
点赞
收藏
分享

微信扫一扫

ES6 class类

ES6中的类

js中生成实例对象的传统方法是通过构造函数。而ES6提供了更接近传统语言的写法,引入了class类这个概念,作为对象的模板,通过class类关键字,可以定义类。

ES6的class可以看做一个语法糖而已,它的绝大部分功能,ES5都可以做到,只不过写法让对象原型的写法更加清晰。更像面向对象的语法而已:

ES5与ES6对比:

对比两者的写法:还是ES6看起来更加清晰、明了,里边有一个constructor方法,这就是构造方法,this关键字代表实例对象。height方法前面不需要加function,而且方法之间不可以加逗号。加了会报错!!!

//ES5
function Test(name,age){
this.name = name;
this.age = age;
}
Test.prototype.height = function(){
console.log("170cm");
}
var test = new Test("lxc",20);

//ES6
class Test{
constructor(name,age){
// 类中的属性
this.name = name;
this.age = age;
}
// 原型上的方法
height(){
console.log("170cm");
}
}
var test = new Test("lxc",20);

 

 es6中类的原型prototype还在:

class Test{
name(){
console.log("lxc")
}
age(){
console.log("20")
}
height(){
console.log("170cm");
}
}
var test = new Test();
console.log(Test.prototype)
// 打印结果:
// > {constructor: ƒ, name: ƒ, age: ƒ, height: ƒ}
// > age: ƒ age()
// > constructor: class Test
// > height: ƒ height()
// > name: ƒ name()
// > __proto__: Object

上边代码,类里边所有的方法都是在原型上了。。。在类的实例上边调用方法,就是调用原型上的方法。

class Test{}
var test = new Test();
console.log(test.constructor === Test.prototype.constructor) //true

上边代码,test是Test的实例,它的constructor方法就是Test类原型上的constructor的方法!!!

通过Object.assign( ) 向类的原型添加多个方法:

class Test{}
var test = new Test();
Object.assign(Test.prototype,{
name(){},
age(){},
height(){}
})
console.log(Test.prototype)

打印结果:

ES6  class类_父类

是否可枚举:

ES6类中的方法都是不可枚举的 ( 也就是原型上的方法 ) ,与ES5中不同:

class Test{
constructor(){
this.a = "a"
}
name(){}
age(){}
height(){}
}
var test = new Test();
console.log(Object.keys(Test.prototype)) // []
//取原型对象上边的方法
console.log(Object.getOwnPropertyNames(Test.prototype))// ["constructor", "name", "age", "height"]

constructor方法:

创建一个类的时候,类里边必须有constructor方法,如果没有显式定义,js引擎会自动为它添加一个空的constructor方法。

class Test{}
// 等于
class Test{
constructor(){
}
}

constructor方法默认返回实例对象(即this),但也是完全可以指定返回另外一个对象。

class Test{
constructor(){
return Object.create(null)
}
}
var test = new Test();
console.log(test instanceof Test) //false

上边代码,constructor函数返回一个全新的对象,结果导致实例对象不是Test类的实例。。。

注意点:

只要你写代码写在类或模块中,就只有严格模式下可用,因为ES6把整个语言升级到了严格模式。。。

 

类中的getter、setter

类中的getter与setter和Object.defineProperty()对一个属性的读取和赋值进行控制一样:它们都是对一个属性进行控制而出现的。

下边使用get和set相当于给age属性加上了getter和setter,这样就可以对age属性进行校验了,既可以设置初始化的值( 10 ), 你也可以为age赋值。

tips:

1、在属性前边加上get、set,该属性并不是在原型上的;

2、下边例子中,当我们给a赋值时,a.age = 100 相当于 a调用set方法;当获取a.age 时,相当于调用类中get方法;

3、在类中,我们通过使用get和set,可以非常方便的实现对属性进行控制,而传统对对象属性进行控制需要使用 Object.defineProperty()。

class Person{
constructor(data) {
this.age = data
}
set age(data) {
if(typeof(data) !== 'number') throw new Error('number property must be a number')
this._age = data
}
get age() {
return this._age
}
}
const a = new Person(10)
console.log( a.age ) // 10
a.age = 100
console.log(a.age) // 100

静态成员:

所为静态成员,就是通过类直接添加的属性或者在类型直接定义的属性或方法。(与python中的类中的类变量和实例变量类似)

类相当于实例的原型,所有在类中定义的方法,都会被实例所继承,(啰嗦一句前这段话的意思是:类上边的属性和方法都可以被实例调用)。如果在一个方法前面加上static关键字,表示该方法不会被实例继承(也就是实例不能调用),而是直接通过类来调用,这就是"静态成员"。

    静态方法几个重要点:

       1、里边的this指向类,而不是实例;

        eg:下边代码:静态方法和非静态方法同名,静态方法this指向类,所以打印:" 我叫吕星辰:) "

class Son{
static name(){
this.name();
}
static name(){
console.log("我叫吕星辰:)")
}
name(){
console.log("我是谁?")
}
}
let son = new Son();
Son.name()//我叫吕星辰:)

     2、在类中,静态方法可以与非静态方法重名;

     3、静态方法,可以被子类继承;

     eg:下边代码,子继承父类的静态方法,可以掉用age方法

class Father{
static age(){
return "20"
}
}
class Son extends Father{
constructor(){
super();
}
}
var son = new Son();
console.log(Son.age())//20

      4、class类种没有静态属性

  字段初始化器(ES7):

字段初始化器,就是类中实例初始化的简写,如下:

(某些属性在初始化时,是固定的,此时会用字段初始化器来初始化属性,实际上初始化的属性还是在实例中的!!!)

class Person{
constructor() {
this.age = 20
this.name = 'lxc'
this.height = 180
}
}
const a = new Person()
console.dir(a)
// 相当于(下边就是字段初始化器)
class Person{
age = 20
name = 'lxc'
height = 180
}
const a1 = new Person()
console.dir(a1)

ES6  class类_初始化_02

tips:

1、添加在static上的字段初始化器,是静态方法(属性)

2、没有添加在static上的字段初始化器,属于实例对象上边的属性(方法)

3、字段初始化器是一个箭头函数时,里边的this指向类本身,比如:

class Person{
age = 20
name = () => {
alert('lxc,age为:' + this.age) // lxc,age为:20
}
height = 180
}
const a = new Person()
console.dir(a.name())

/*
上边相当于
*/
class Person{
constructor() {
this.age = 20
this.name = () => {
alert('lxc,age为:' + this.age) // lxc,age为:20
}
this.height = 180
}
}
const a = new Person()

 

 

class中的继承:

class继承是通过extends关键字实现继承,这比ES5的通过修改原型继承要清晰、方便。

eg:我们分别写下ES5和ES6构造函数继承:

// +++++++++++ES5继承
function Father(name,age){
this.name=name;
this.age = age;
}
Father.prototype.say = function(){
alert("hello world");
}
var father = new Father();
function Son(){
Father.apply(this,["lxc",20]);
}
Son.prototype = Object.create(Father.prototype);
Son.prototype.constructor = Son;
var son = new Son();
console.log(son.say())//hello world
console.log(son.age,son.name)//20,lxc

// +++++++++++++ES6继承
class Father{
constructor(name,age){
this.name = name;
this.age = age;
}
say(){
alert("hello world");
}
}
var father = new Father();
class Son extends Father{
constructor(){
super("lxc",20); //相当于Father.call(this,···)
}
}
var son = new Son();
son.say()//hello world
console.log(son.name)//lxc
console.log(son.age)//20

上边代码:在constructor中出现super关键字,在这里表示父类构造函数,用来创建父类的this对象的。子类在继承父类时,constructor方法中,第一行必须运行super(),调用父类实例,否则会报错。。。这也不难理解,让子类的this指向父类构造函数,才能完成子类继承父类。

补充:

1、下边是三个类,A类被B类继承,B类被C类继承,要求封装一个方法,返回所有类中以alias开头的属性,以及所有类原型上的以validator开头的方法:

如:

class A {
constructor() {
this.aliasA = 'a'
}
validatorA() {
console.log('a')
}
}

class B extends A {
constructor() {
super()
this.aliasB = 'b'
}
validatorB() {
console.log('b')
}
}

class C extends B {
constructor() {
super()
this.aliasC = 'c'
}
validatorC() {
console.log('c')
}
}
const c = new C()
// 传入参数:
filter(c, 'alias', 'validator')

输出:

ES6  class类_初始化_03

实现大致思路:

所有类中的的属性很好实现,由于继承关系,所以实例c中可拿到所有类中实例属性,遍历,以name开头的属性,push到数组即可;

所有类原型上的方法,需要递归遍历,通过Object.getPropertyOf()获取一个对象的原型,使用Object.getOwnPropertyNames,输出所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性),判断 属性中有'alias' 的属性,push到数组中去,最后需要递归遍历,第一个参数,刚开始是实例c,递归第二次时,参数一为实例c的原型的原型,说白了就是通过递归在原型链上不断地查找;

开始,我是通过实例的__proto__方法(原型链)寻找类原型上的属性的,由于__proto__是一个内置方法,不建议使用,后来改用: Object.getPropertyOf() 来获取类的原型。

let arr = []
function test(instance, alias, validator) {
if(instance){
Object.keys(instance).forEach(ele => {
(ele.indexOf(name) !== -1) ? arr.push(ele) : ''
})
}
const isValidator = Object.getOwnPropertyNames(Object.getPrototypeOf(instance))
if(isValidator) {
isValidator.forEach(item => {
if(item.indexOf(validator) !== -1) {
arr.push(item)
test(Object.getPrototypeOf(instance), 'alias', validator)
}
})
}
}
test(c,'alias', 'validator')
console.log(arr)

 


举报

相关推荐

0 条评论