es6学习:class简介、静态成员和继承和getter与setter

1. class简介

      传统的js中没有对象,没有类的概念。传统方法(es5)是通过构造函数,定义并生成新对象,并且将自身的属性共享给新对象。

      对于类中的方法是通过prototype属性进行添加的。注意:函数名与实例化构造名相同。(函数名首字母大写,方便区分普通函数)通过构造函数创建对象时必须使用new运算符。

    function Phone (brand, price) {
      this.brand = brand;
      this.price = price;
    }
    // 添加方法
    Phone.prototype.call = function () {
      console.log('正在呼叫***')
    }
    // 实例化对象
    let Huawei = new Phone('华为', 3999)
    Huawei.call()
    console.log(Huawei)

 

      es6中引入Class,通过class关键字定义类。es6的class可以看作只是一个语法糖,它的绝大部分功能,es5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。es6中的类中会有一个默认构造函数constructor,用来接收参数和初始化,实例化时会自动调用,且该构造函数的命名不可更改。在类中定义类的方法,定义方法时不能加上function,且方法之间不可有逗号(,)分隔。

    class Phone {
      // 构造方法 (名字不可更改, 实例化时会自动调用)
      constructor(brand, price) {
        this.brand = brand
        this.price = price
      }
      
      // 方法必须使用该语法,不能使用es5对象完整形式  不可有function
      call () {
        console.log(this.brand+' 正在呼叫***')
      }
    }
    let onePlus = new Phone('1+', 2999)
    onePlus.call()
    console.log(onePlus)

      类的数据类型就是函数,类本身就指向构造函数。

    console.log(typeof onePlus) // object 
    console.log(typeof Phone) // function
    console.log(Phone === Phone.prototype.constructor) // true

2. 静态成员

    2.1 类的静态属性

      es6中静态属性指的是Class本身的属性,即Class.propname,而不是定义在实例对象(this)上的属性。静态属性不能被实例对象调用。

      静态属性定义的方法:

       ① 方法一(目前只有这种写法可行,ES6明确规定,Class内部只有静态方法,没有静态属性,其他方法eslint-js编译不通过)(对于新写法,本人写的时候eslint-js编译没有通过)

      对于老写法,其静态属性定义在类的外部,整个类生成以后,再生成静态属性。新写法是显示声明(declarative),而不是赋值处理,语义更好。

// 老写法
class Foo {}
Foo.prop = 1;
console.log(Foo.prop) // 1

// 新写法
class Foo {
  static prop = 1
}
console.log(Foo.prop) // 1

// 以下几种定义方式失效
class Test {
  prop: 2  // 写法一 (eslint-js 编译不通过)
  static prop: 2 // 写法二 (eslint-js 编译不通过)
}
Test.prop // undefined 

      ② 方法二 (ES7 有一个静态属性的提案,目前Babel转码器支持。类的静态属性可以用等式写入类的定义中)

class Test {
  prop = 'myProp'
}

      2.2 类的静态方法

      类相当于实例的原型,在类中定义的方法会被实例化继承。如果在方法之前加上static关键字,实例化对象就不会继承到该方法,此方法为静态方法,直接通过类来调用。

    class Phone {
      static change () {
        console.log('change')
      }
    }
    let nokie = new Phone()
    Phone.change() // change
    nokie.change() // 报错:Uncaught TypeError: nokie.change is not a function

      对于ES5的静态成员的处理:

    // es5
    function Phone () {}
    Phone.name = 'phone' // 静态属性
    Phone.change = function () { // 静态方法
      console.log('change')
    }
    Phone.prototype.size = '5.5inch' // (不是静态属性)此种定义方式与this处理类同,可被继承
    // 实例化
    let nokie = new Phone()
    console.log(nokie.name) // undefined
    console.log(nokie.size) // 5.5inch
    nokie.change() // 报错

3. 继承

    3.1 ES5构造函数实现继承

      通过父级类名.call(this, 属性名, ...)进行寄生继承属性。其中this指向的是子级类。推荐一篇es5实现继承的几种方式

    // es5 构造函数实现继承 ----------------------------------------------------------
    // 父级构造函数
    function Phone (brand, price) {
      this.brand = brand;
      this.price = price;
    }
    // 添加方法
    Phone.prototype.call = function () {
      console.log('正在呼叫***')
    }
    // ------------------------------------------------------------------------------
    // 子级构造函数
    function SmartPhone (brand, price, color, size) {
      Phone.call(this, brand, price) // this指向SmartPhone    继承父级属性
      this.color = color
      this.size = size
    }
    // 设置子级构造函数的原型
    SmartPhone.prototype = new Phone;
    SmartPhone.prototype.constructor = SmartPhone; // 做矫正  加不加不影响
    // 声明子类的方法
    SmartPhone.prototype.photo = function () {
      console.log('拍照')
    }
    SmartPhone.prototype.PlayGames = function () {
      console.log('玩游戏')
    }
    // ------------------------------------------------------------------------------
    const XXX = new SmartPhone('锤子', 2499, '黑色', '5.5inch')
    console.log(XXX)

    3.2 ES6 class的类继承

      ES6,子级类定义时通过关键字extends来时间类的继承,通过super关键字实现继承父级的属性,类似于父级.call()的功能。

    class Phone {
      constructor(brand, price) {
        this.brand = brand
        this.price = price
      }
      // 父类的成员属性
      call () {
        console.log('正在呼叫***')
      }
    }
    // 子级继承 使用关键子extends
    class SmartPhone extends Phone {
      constructor(brand, price, color, size) {
        super (brand, price) // 类似于Phone.call(this, brand, price)
        this.color = color
        this.size = size
      }
      photo () {
        console.log('拍照')
      }
      playGames () {
        console.log('玩游戏')
      }
    }
    
    const xiaomi = new SmartPhone('小米', 1799, 'white', '4.7inch')
    console.log(xiaomi)
    xiaomi.call() // 正在呼叫***
    xiaomi.photo() // 拍照
    xiaomi.playGames() // 玩游戏

      super关键字既可以当作函数使用,也可以当作对象使用。这两种情况下,用法完全不同。

      ① super作为函数调用时,代表父类的构造函数。ES6要求,子类的构造函数必须执行一次super函数。super虽然代表了父类的构造函数,但返回的是子类的实例,即super内部的this指向子类,因此在这里相当于父级.prototype.constructor.call(this)。作为函数时,super()只能在子类的构造函数中,用在其他地方会报错。

      ② super作为对象时,指向的是父类的原型对象(父类.prototype)。通过super.XXX的方式调用父类的属性和方法。定义在父类实例对象的方法和属性(父类构造函数中的属性属于父类实例对象的)不能通过super调用。ES6规定,通过super调用父类方法时,super会绑定子类的this。

      注意:使用super时,必须显式指定作为函数还是作为对象使用,否则会报错。如console.log(super)会报错。

    3.3 重写

    class SmartPhone extends Phone {
      constructor(brand, price, color, size) {
        super (brand, price) // 类似于Phone.call(this, brand, price)
        this.color = color
        this.size = size
      }
      ...
      call () { // 对call方法进行重写
        console.log('视频通话')
      }
    }
    xiaomi.call() // 视频通话

4. 类的getter与setter

      ES6中,可以通过get方法获取属性值,通过set方法对属性值进行更改值。不自定义时,初始化时会自动调用set方法,读取时调用get方法,get方法只能读。

      自定义get和set方法的注意事项和实例:

    class Phone {
      constructor(price) {
        this.price = price
      }
      get price () {
        console.log('--- getter')
        return this._price
      }
      set price (newPrice) {
        console.log('--- setter')
        this._price = newPrice
      }
      sayPrice () {
        console.log(this.price)
      }
    }
    let xxx = new Phone (500) // --- setter
    // ---------------------------------
    xxx.sayPrice() // 读取price输出:1. --- getter 2. 500

     

      自定义get和set时,调用set方法内是this.price = newPrice,调用get方法内是return this.price,在初始化实例对象时会在constructor构造函数中执行this.price=price,会进行无限递归,最后导致栈溢出现象。即

      但通过在set和get中使用别名_price会解决这个问题。直接调用_price,就直接输出_price的值,不走price(),因为get price()是读取price属性值。直接调用price时,会调用price的get()。

console.log(xxx._price) // 500
console.log(xxx.price) // 1. --- getter  2. 500
console.log(xxx)

      当在类中定义_price的get和set方法时,在直接调用_price时,也会自动调用_price的get()方法,即会走自己的get()和set()。即同样的操作,只是类中多定义了_price的get()和set(),输出结果如下:

      get price()与set price(newPrice)是成对出现的。如果只有get,则会报如下错误:

 

 


下一篇.......

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值