class类的增加

定义“类”

之前使用new function来定义一个函数的类型,现在在es6中可以使用class关键字来定义一个函数类

先来看普通函数定义的类

    function People(name,age,sex){
  this.name = name;
  this.age = age;
  this.sex = sex;
}

People.prototype.say = function(){
  console.log(`我是${this.name},今年${this.age}岁了`)
}
var xiaoming = new People("小明",18,"")
console.log(xiaoming)

 

 

 在看class定义的类

 class People{
constructor(name,age,sex){
this.name = name; this.age = age; this.sex = sex; } say(){ console.log(`我是${this.name},今年${this.age}岁了`) } } var xiaoming= new People("小明",20,"") console.log(xiaoming)

每个类都有一个自己的构造函数constructor,当我们通过new操作符,操作一个类的时候就会调用这个类的构造函数。

当我们通过new关键字操作类的时候,会调用这个constructor函数,并且执行如下操作:

  1. 在内存中创建一个对象
  2. 将类的原型prototype赋值给创建出来的对象
  3. 将对象赋值给函数的this
  4. 执行函数体中的代码
  5. 自动返回创建出来的对象

虽然es6增加了class关键字,但是JavaScript中还是没有类的概念!依然是基于面向对象,而不是真正的面向对象,基于原型链来模型实现class,机理和普通函数定义的类是一样的

console.log(xiaoming.say === People.prototype.say) // true
console.log(xiaoming.hasOwnProperty("say")) // false
console.log(xiaoming.hasOwnProperty("name")) // true

 继承

 普通函数的继承

function People(name,age,sex){
  this.name = name;
  this.age = age;
  this.sex = sex;
}

People.prototype.say = function(){
  console.log(`我是${this.name},今年${this.age}岁了`)
}

function Student(name,age,sex){
  this.name = name;
  this.age = age;
  this.sex = sex;
}
Student.prototype = new People()
Student.prototype.test = function(){
  console.log(`${this.name}在学习`)
}

var xiaohong = new Student("小明",18,"")
xiaohong.test()
xiaohong.say()

 

继承的原理

 

 

 

 

ES6是如何实现继承的 

class People{
  constructor(name,age,sex){
    this.name = name;
    this.age = age;
    this.sex = sex;
  }
  say(){
    console.log(`我是${this.name},今年${this.age}岁了`)
  }
}

class Student extends People{
  constructor(name,age,sex) {
    super(name,age,sex) //调用的是超类的构造器
  }
  test(){
    console.log(`${this.name}在考试`)
  }
}
var xiaohong = new Student("小红",20,"")
xiaohong.test()
xiaohong.say()

 

 

 es6利用extends来实现继承

constructor方法

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

class定义的构造函数,必须使用new关键字调用,否则会报错

class Foo {
  constructor() {
    return Object.create(null);
  }
}

Foo()

 

 

 

  class类定义的构造函数没有变量声明的提升

普通函数可以先使用后声明

var xiaoming = new People("小明",19,"")
console.log(xiaoming);

function People(name,age,sex){
  this.name = name;
  this.age = age;
  this.sex = sex;
}

 

 

 class定义的构造函数

var xiaoming = new People("小明",17,"")
console.log(xiaoming);

class People{
  constructor(name,age,sex){
    this.name = name;
    this.age = age;
    this.sex = sex;
  }
}

 

 

 

 继承的构造函数必须要在constructor中调用super否则会报错

class Point { 

}
class ColorPoint extends Point {
  constructor() {
   //内部没有调用super
  }
}
let cp = new ColorPoint();

 

 

 继承的子类可以不用写constructor,但是不代表没有定义,系统会自动悄悄的给你加上下面的代码

constructor(...args) {
  super(...args);
}

继承的子类使用this之前必须要先调用super后再定义

class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
}

class ColorPoint extends Point {
  constructor(x, y, color,name) {
    this.name = name; // ReferenceError
  }
}  
var a = new ColorPoint();
console.log(a)

 

 

 

 Object.getPrototypeOf方法

Object.getPrototypeOf()方法用来查询当前的子类的父亲

class People{
  constructor(name,age,sex){
    this.name = name;
    this.age = age;
    this.sex = sex;
  }
  say(){
    console.log(`我是${this.name},今年${this.age}岁了`)
  }

}
class Student extends People{
  constructor(name,age,sex) {
    super(name,age,sex)
  }
  test(){
    console.log(`${this.name}在考试`)
  }
}
var xiaoming = new Student("小明",22,"")
xiaoming.test()
xiaoming.say()
console.log(Object.getPrototypeOf(Student) == People); 
console.log(Object.getPrototypeOf(Student));

 

 

super关键字 

super这个关键字,既可以当作函数使用,也可以当作对象使用

当函数使用

class A {
  constructor() {
    console.log("我是A的constructor")
  }
}
class B extends A {
  constructor() {
    super();
  }
}
var b = new B()

 

 

 super当做函数调用的时候,调用的是父函数的constructor构造器,但是上下文还是子类的自己的上下文

new.target的使用

class A {
  constructor() {
console.log(new.target);
console.log(new.target.name) 
  }
}
new A() 

 

 

 

class A {
  constructor() {
    console.log(new.target.name);
  }
}
class B extends A {
  constructor() {
    super();
  }
}
new A() 
new B() 

 

 

 super作为函数使用的时候只能子类的constructor构造器中,在其他的函数中会报错

class A {}

class B extends A {
  m() {
    super(); 
  }
}

 

 

 super方法作为对象的时候,指向父类的原型对象。

class A {
  a() {
    return 2;
  }
}

class B extends A {
  constructor() {
    super();
    console.log(super.a());
  }
}
let b = new B();

 

 

 

 函数的get和set关键字

class内部可以使用get和set关键字,对某个属性设置存值函数和取值函数,拦截该属性的存取行为

class One {
  constructor() {

  }
  get prop() {
    return 'getter';
  }
  set prop(value) {
    console.log('setter: '+value);
  }
}

let inst = new One();
inst.prop = 123;
console.log(inst.prop)

 

 

 

静态方法

类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。

先看一下静态化之前的构造函数

class Foo {
  fun() {
    console.log("静态函数");
    
    return 'hello';
  }
}
console.log(Foo.fun) //undefined

 

 

 此时加了static关键字后

class Foo {
  static fun() {
    return 'hello';
  }
}
console.log(Foo.fun) // 返回classMethod函数体
Foo.fun() // 'hello'

 

 

 此时如果使用new产生实例后

var fun2 = new Foo();
foo.fun()

 

 

new.target属性

ES6为new命令引入了一个new.target属性,(在构造函数中)返回new命令作用于的那个构造函数。如果构造函数不是通过new命令调用的,new.target会返回undefined,因此这个属性可以用来确定构造函数是怎么调用的

function Person(name) {
  if (new.target !== undefined) {
    this.name = name;
  } else {
    throw new Error('必须使用new生成实例');
  }
}
var xiaoming =  new Person("小明")
console.log(xiaoming); 
Person("xiaoming")

 

posted @ 2021-10-24 18:29  keyeking  阅读(54)  评论(0编辑  收藏  举报