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函数,并且执行如下操作:
- 在内存中创建一个对象
- 将类的原型prototype赋值给创建出来的对象
- 将对象赋值给函数的this
- 执行函数体中的代码
- 自动返回创建出来的对象
虽然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")