ES6 中的 Class 类

ES6 中的新引入的 class 具有正式定义类的能力,我们可以使用 class 关键字来定义类,和函数类型相似,类的定义的主要方式是 类声明 和 类表达式

1.类的定义

类的两种定义的方式都需要使用到 class 关键字

  // 类声明
  class Person {}
  // 类表达式
  let Person = class {};

需要注意的是,类表达式和函数表达式类似,使用 var 关键字声明,在求值前引用,拿到的是undefined,如果是使用 let 关键字声明,则会报错,原因是使用 let 关键字声明的变量不会自动提升,并且不允许在变量声明之前使用,

  console.log(person, personC);  //undefined undefined
  var person = function () {};
  var personC = class {};
  
  console.log(person, personC); 
   //Uncaught ReferenceError: Cannot access 'person' before initialization
  let person = function () {};
  let personC = class {};

我们知道,函数声明可以提升,我们可以在函数声明之前调用函数,但是类声明不能;

  console.log(personFn);  // ƒ personFn() {}
  function personFn() {}
  console.log(Person); 
  //Uncaught ReferenceError: Cannot access 'Person' before initialization   不能在 "Person"初始化之前访问
  class Person {}

我们声明的类受块级作用域的影响,但是函数声明却不受块级作用域的影响

  {
    function personFn() {}
    class Person {}
  }
  console.log(personFn);  // ƒ personFn() {}
  console.log(Person); // Uncaught ReferenceError: Person is not defined

补充一下作用域的知识,块级作用域是ES6 提供的,在此之前只有 全局作用域 和 函数作用域.在 ES6 中带有{}的就是块级作用域, 例如 if{}else{} 在块级作用域中我们使用 let 和 const 来声明变量,不会出现变量提升,但是对使用 var 声明的变量没有影响,还是会存在变量提升,在块级作用域中, var 声明和function 和在window中的表现一样,如果没有使用 let 和 const 进行声明的变量,我们就可以不考虑块级作用域,function(){}会形成函数作用域,在函数内部形成的作用域,如果在函数A内部定义函数B,则函数B可以访问到函数A内部定义的变量,但是函数A无法访问函数B内部定义的变量,接下来用代码来简单的复习一下函数作用域

  function wrap() {
    var wrapText = "wrap";
    function inner() {
      var innerText = "inner";
      console.log(wrapText);  // wrap
    }
    inner();
    console.log(innerText);  // Uncaught ReferenceError: innerText is not defined
  }
  wrap();

2.类的构成

声明的类可以包含 构造函数方法, 实例方法, 设置函数, 获取函数, 静态类方法, 但是这些都不是必须的,即使是定义一个空的类也是有效的.和构造函数一样,建议类名的首字母要大写,可以区别通过它创建的实例

// 这个是一个空类定义,但是它是有效的
class Person{}
// 在此依然可以使用定义的空类创建实例 'xiaoming'
let xiaoming=new Person;
// 通过对比可以发现 xiaoming 的原型和定义的类 Person 的构造函数式相等的
console.log(xiaoming.prototype==Person.constorctor);   // true

// 非空类的定义, 构造函数方法, 实例方法, 设置函数, 获取函数, 静态方法 这些都是非必须的,根据需要定义
class Person{
//  constructor  构造函数
constructor(){}
// 设置函数
set name{}
// 获取函数
get name{}
// 静态方法
static mySecret(){}
}

3.构造函数

在类中使用关键字 constructor 定义块内部创建类的构造函数,在使用 new 关键字创建类的新的实例是,会调用 constructor 这个方法.构造函数在类的定义中不是必须的,例如上面我们定义了一个空类,也是可以的;

3.1 实例化

使用 new 操作符实例化定义的类等于使用 new 调用了其构造函数,在使用 class 和 new 时,JavaScript 解释器知道需要使用 constructor 函数进行实例化;

在使用 new 关键字调用类的构造函数执行了如下操作
1.在内存中创建一个新的对象
2.这个新对象的 [[prototype]] 指针被赋值为构造函数的 prototype 属性
3.constructor 中的 this 指向新创建的对象
4. 执行 constructor 中的代码,给新的对象添加属性
5. 如果 constructor return 非空对象,则会返回该对象,否则,返回刚创建的新对象

注意: 调用类构造函数必须使用 new 关键词

// 内部执行简单的方法
class Person{
    constructor(){
        console.log('constructor 执行了');
    }
}
// constructor 如果不需要传参, 类后面的括号是可选的
let xiaoming=new Person;  //  constructor 执行了

// constructor 内部有属性
class Person{
    constructor(){
        this.uerName="李煜"
    }
}
let liyu=new Person;
console.log(liyu.uerName);   // 李煜

// 类实例化传入参数,会用 constructor 函数的参数,需要在方法里面接收参数
class Person{
    constructor(name){
        this.uerName=name
    }
}
let luyou=new Person('陆游');
console.log(luyou.uerName);
let baijuyi=new Person;
console.log(baijuyi.uerName);  // undefined

// 这种写法,类立即实例化了,类名是可选的,不写页面有关系
  let zhangjiuling = new class {
    constructor(name) {
      this.uerName = name;
    }
  }("张九龄");
  console.log(zhangjiuling.uerName); //  张九龄

在默认的情况下,类构造函数会在执行后返回 this 对象,构造函数返回的对象会被用作实例化的对象,如果新创建的 this 对象没有被引用,那么这个对象会被销毁.如果返回的不是 this 对象,那么这个对象不能通过 instanceof 操作符检测出和类之间有关联,因为这个对象的原型指针没有被修改;

  class Person {
    constructor(flag) {
      this.name = "陶渊明";
      if (flag) {
        return {
          userName: "杜子美",
        };
      }
    }
  }
  let taoyuanming=new Person;
  let duzimei = new Person(true)

  console.log(taoyuanming instanceof Person);  // true
  console.log(duzimei instanceof Person)   // false

在使用 new 关键字创建类构造函数的实例后, 类构造函数会成为普通的实例方法(但作为构造函数,仍然可以被 new 调用),因此可以在实例上面引用他;

class Person{}

let  litaibai=new Person;
let  liboqin=new litaibai.constructor()
litaibai.constructor();  
//  Class constructor Person cannot be invoked without 'new' 
//  在没有“new”的情况下无法调用类构造函数

如果使用对类进行类型检测,会发现他其实是 function 类型;

class Person{}
console.log(typeof Person);  // function
console.log(Object.prototype.toString.call(Person)); // [object Function]

声明的类是有 prototype 属性,并且这个原型的 constructor 属性指向类本身;

class Person{}
console.log(Person.prototype);

ES6 中的 Class 类_第1张图片

根据上面打印的结果我们可以看到, Person.prototype 对象里面有一个 constructor属性,是指向我们声明的 Person 类的.

和普通的构造函数一样,可以使用 instanceof 操作符检测构造函数原型是否存在于实例的原型链中,这样我们就可以判断这个对象是不是类的实例

class Person{}
let xinqiji=new Person;
console.log(xinqiji instanceof Person);  // true

类是 JavaScript 中的一等公民,可以想其他的对象或者是函数引用一样作为参数传递

let classList=[
    class{
        constructor(name){
            this.name=name;
            console.log('大家好! 我的名字是: '+this.name);
        }
    }
]
function createPerson(classfn,name){
    return  new classfn(name)
}
let person = createPerson(classList[0],'孟浩然,帅孟孟')  // 大家好! 我的名字是: 孟浩然,帅孟孟
console.log(person.name);   //  孟浩然,帅孟孟

你可能感兴趣的:(javascript,class,javascript)