Class的基本用法----ES6重刷20

在这里我会根据阮老师ES6书中的介绍走。

一、类的由来。

// ES5做法【在原型链上直接操控,没有很明显的语义化,不便于可读性和操作性及可维护性】
const Person = function () {
  this.mouse = 'mouse',
  this.eyes = 'eyes'
}
Object.assign(Person.prototype, {
  getEyes() {
    return 'this amout is two'
  }
})

const person = new Person()
console.log(person, person.getEyes())
// Person {mouse: "mouse", eyes: "eyes"} "this amout is two"

// ES6做法【利用class,只需要语义化命令就可以操作原型链,具有可读性和操作性及可维护性】
class ManKind {
  constructor() {
    this.mouse = 'mouse',
    this.eyes = 'eyes'
  }

  getEyes() {
    return 'this amout is two'
  }
}

const manKind = new ManKind()
console.log(manKind, manKind.getEyes())
// ManKind {mouse: "mouse", eyes: "eyes"} "this amout is two"

我们都知道,js中实例的构造函数及实例上的方法本质上都是通过操作原型链达到目的,比如我们知晓实例的方法其实本质上都是其构造函数的prototype属性对象中的属性方法。

ES5:当我们编写了一个构造函数时,都是另外重新编写对其prototype属性对象的修改,从而实现实例方法的添加,这样主要有三个弊端。
1、语义化不明确
contructorName.prototype.wayName = function () { code... }【但我们只需添加一种实例方法时,我们可以直接添加;当有多个时,我们可以利用Object.assgin()添加,如上述代码】,这样很明显,语义极度不明确化。

2、操作性较差
当添加的实例方法数量不同时我们还要分而待之,这是我们一般不想做的,我们一般想的是一种方法就ok,并且还有较良好的扩展性。

3、维护性较差
当我想修改/增加/删除一个实例构造函数上的某个属性和实例方法中的某个方法,那样我得先找到实例对象的构造函数,然后再去找到设置构造函数prototype属性对象内容的地方【这是因为构造函数和构造函数实例方法分而编写所造成的】

ES6:当我们想编写一个构造函数时,我们只需要将构造函数的属性值写在constructor方法中,当我们想添加实例方法时,我们只需要在contructor方法其下编写你想要添加的方法,这样做的优点有三点。
1、清晰的语义
使语义更加接近于传统语言的写法,比如Java和C++,即便是新手也可以很好的从表面理解其作用。

2、较好的操作性和扩展性
我们就不需要对构造函数的属性和实例方法分开两个地方编写,并且还不需要考虑根据实例方法数量的多少而做不同的处理操作。

3、较好的维护性
当我们想做上述雷同的修改时,我们只需要找到实例对象的构造类就ok了。

所以class的由来是为了更好的实现构造函数及关于原型链上的继承。

二、constructor方法
constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加,返回值为实例对象(即this)。

class Point {
}

// 等同于
class Point {
  constructor() {}
}

三、实例方法命名可遵循对象属性表达式命名

const method = 'getEyes'
class ManKind {
  constructor() {
    this.mouse = 'mouse',
    this.eyes = 'eyes'
  }

  [method]() {
    return 'this amout is two'
  }
}

const manKind = new ManKind()
console.log(manKind, manKind.getEyes())
// ManKind {mouse: "mouse", eyes: "eyes"} "this amout is two"

四、注意点
1、严格模式
类和模块的内部,默认就是严格模式,所以不需要使用use strict指定运行模式。

2、不存在变量提升

new Foo(); // ReferenceError
class Foo {}

3、name属性
由于本质上,ES6 的类只是 ES5 的构造函数的一层包装,所以函数的许多特性都被Class继承,包括name属性。

class Point {}
Point.name // "Point"

4、Generator方法
如果某个方法之前加上星号(*),就表示该方法是一个 Generator 函数。比如为class添加Interator接口。

class Foo {
  constructor(...args) {
    this.args = args;
  }
  * [Symbol.iterator]() {
    for (let arg of this.args) {
      yield arg;
    }
  }
}

for (let x of new Foo('hello', 'world')) {
  console.log(x); // hello, world
}

5、this指向问题
我们先看代码对比示例

const method = 'getEyes'
class ManKind {
  constructor() {
    this.mouse = 'mouse',
    this.eyes = 'eyes'
  }

  [method]() {
    console.log(this)
    return `this ${this.eyes} is two`
  }
}

const manKind = new ManKind()
const { getEyes } = manKind
console.log(manKind.getEyes()) //ManKind {mouse: "mouse", eyes: "eyes"}, this eyes is two
console.log(getEyes)
// ƒ [method]() {
//    console.log(this)
//    return `this ${this.eyes} is two`
//  }
console.log(getEyes()) // undefined, Uncaught TypeError: Cannot read property 'eyes' of undefined

我们可以看到当打印manKind.getEyes()时,this指向的是ManKind创建的一个实例对象【注意:变量manKind只是一个用于储存指向实例对象new ManKind()的地址的变量】;当我们使用manKind.getEyes()调用方法时,则便是隐式的在实例对象new ManKind()环境中调用内部的getEyes()方法,这也就是为什么getEyes()方法内部的this是指向实例对象new ManKind()

然而我们可以看到当打印单独的getEyes()时,this指向的是undefined,这是因为我们将指向calss ManKindgetEyes方法的地址赋值给了class外部的一个变量getEyes,并且是在外部执行【我们知道一个函数内部的this指向不是看它是在哪里定义,而是看它是在哪个环境下运行】,然而getEyes方法中本身的this是处于严格模式中【因为class默认严格模式,而getEyes方法本身是定义在class中】,在严格模式中为了安全考滤,禁止this指向全局变量,这就是为什么单独打印单独的getEyes()时,this指向的是undefined,同时也可以解释后面的找不到属性报错。

解决方法【利用bind强制绑定this

const method = 'getEyes'
class ManKind {
  constructor() {
    this.mouse = 'mouse',
    this.eyes = 'eyes',
    this[method] = this[method].bind(this)
  }

  [method]() {
    console.log(this)
    return `this ${this.eyes} is two`
  }
}

const manKind = new ManKind()
const { getEyes } = manKind
console.log(manKind.getEyes()) // ManKind {mouse: "mouse", eyes: "eyes", getEyes: ƒ}, this eyes is two
console.log(getEyes)
// ƒ [method]() {
//    console.log(this)
//    return `this ${this.eyes} is two`
//  }
console.log(getEyes()) // ManKind {mouse: "mouse", eyes: "eyes", getEyes: ƒ}, this eyes is two

五、静态方法
在此我们得谈谈静态方法和实例方法【非静态方法】的各自特点和适用场景了
1、特点
静态方法
1.1、方法内部存在的this指向的是class本身
1.2、不会被calss所创建的实例对象继承
1.3、可以使用类名直接调用比如className.wayName()
1.4、可以被子类继承,利用super关键字调用
1.5、在class定义完毕之时就被储存在堆内存中,如果存在多个静态方法,则是并列储存
1.6、静态方法名和实例方法名可以重名

实例方法
1.1、方法内部存在的this指向的是实例对象本身
1.2、会被calss所创建的实例对象继承
1.3、可以使用实例名直接调用比如objName.wayName()
1.4、可以被子类继承,利用super关键字调用
1.5、在每次创建实例对象时,都会储存到内存中;在每次销毁对象时,就会释放所销毁实例对象的实例方法所占的内存空间

2、适用场景
静态方法
没有和实例对象有强烈逻辑关联且会频繁操作的某些业务逻辑,此时我们就可以写成静态方法。【切记:因为除非销毁class,不然其内部的静态方法所占空间不会被释放,所以不要造成静态方法泛滥】

实例方法
和实例对象有强烈逻辑关联的某些业务逻辑,此时我们就可以写成实例方法。

3、在静态方法中使用实例对象及constructor内部属性值
我们可以在外部调用静态方法时,传入实例对象所属的实例指针

const method = 'config'
class ManKind {
  constructor() {
    this.mouse = 'mouse',
    this.eyes = 'eyes'
  }

  static [method](...args) {
    const [obj] = args
    console.log(obj.mouse) // mouse
    return obj.getEyes()
  }

  getEyes() {
    return `this manKind has two ${this.eyes}`
  } 
}

const manKind = new ManKind()
console.log(ManKind.config(manKind)) // this manKind has two eyes

六、实例属性新写法
可以忽略constructor方法

const method = 'config'
class ManKind {
  mouse = 'mouse'
  eyes = 'eyes'

  static [method](...args) {
    const [obj] = args
    console.log(obj.mouse) // mouse
    return obj.getEyes()
  }

  getEyes() {
    return `this manKind has two ${this.eyes}`
  }
}

const manKind = new ManKind()
console.log(ManKind.config(manKind)) // this manKind has two eyes

七、new.target属性
返回实例对象对对应得calss或则构造函数,一般用于判断实例对象是否由此calss或构造函数构建而成

const method = 'config'
class ManKind {
  mouse = 'mouse'
  eyes = 'eyes'

  constructor() {
    console.log(new.target === ManKind) // true
  }

  static [method](...args) {
    const [obj] = args
    console.log(obj.mouse) // mouse
    return obj.getEyes()
  }

  getEyes() {
    return `this manKind has two ${this.eyes}`
  }
}

const manKind = new ManKind()
console.log(ManKind.config(manKind)) // this manKind has two eyes
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值