es6 class的继承
基本的继承
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
getposition () {
console.log("x:" + this.x, "y:" + this.y)
}
}
class ColorPoint extends Point {
constructor(x, y, color) {
super(x, y); //子类调用父类的构造函数 继承父类的属性
this.color = color; //子类自己的属性必须写在super函数之后,不然找不到this
}
}
var colorpoint = new ColorPoint(1, 2, "red");
colorpoint.getposition() // x:1 y:2
console.log(colorpoint.color) //red
静态方法和静态属性
(1)静态方法和静态属性不能被实例访问,只能被类访问,同时类也不能访问实例方法和实例方法。
(2)静态方法和静态属性的写法:
class Point {
constructor(x, y) {
this.x = x; // 实例属性
this.y = y;
}
z = 10; //实例属性
getposition () { //实例方法 保存在prototype中
console.log("x:" + this.x, "y:" + this.y)
}
static pointname = "biubiu" //静态属性
static getname () { //静态方法 之能访问静态属性
console.log(this.pointname)
console.log(this.otherpointname)
}
}
Point.otherpointname = "piupiu"; //也是静态属性,是另一种写法,但是没有封装在类里面
class ColorPoint extends Point {
constructor(x, y, color) {
super(x, y); //子类调用父类的构造函数 继承父类的属性
this.color = color; //子类自己的属性
}
}
var colorpoint = new ColorPoint(1, 2, "red");
colorpoint.getposition() // x:1 y:2
console.log(colorpoint.color)
Point.getname() // biubiu piupiu
ColorPoint.getname()// biubiu piupiu 子类继承了父类的静态属性和方法
colorpoint.getname() //typeerror 子类的实例不能调用父类的静态方法
es5和es6继承的区别
es5继承是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.call(this));
es6继承是先创造父类的实例对象this(所以必须先调用super方法),然后在子类的构造函数修改this。
这一区别使es5不能继承原生构造函数。因为原生构造函数的内部属性是不能获取的,通过apply()或者分配给原型对象都不行。
原生构造函数包括:Number(),String(),Array(),Boolean(),Date(),Function(),RegExp(),Error(),Object()9个。
-
super关键字
super关键字可以当做函数使用,也可以当作对象使用。
第一种情况,super作为函数调用时代表父类的构造函数。而且只能用在子类的构造函数中,在普通函 数中不能调用。虽然是调用了父类的构造函数,但是返回的是子类的实例,即super内部的this指向的 是子类。
第二种情况,super作为对象时在普通方法中指向父类的原型对象,在静态方法中指向父类。即在子类的普通实例方法中指向普通实例方法,在静态方法中指向静态方法。
父类的实例方法和属性调用不到,只能调用原型的方法和属性。
super调用父类的方法时会绑定this,即this跟随上下文。
类的prototype属性和_proto_属性
class作为作为构造函数的语法糖,同时有以上两个属性:
(1)子类的_proto_属性表示构造函数的继承,指向父类;
(2)子类的prototype属性的_proto_属性表示方法的继承,指向父类的protype属性。
JS高级程序设计里面的继承
寄生组合式继承 最合理和常用
function Person (name) {
this.name = name;
}
Person.prototype.sayName = function () {
console.log(this.name)
}
function Student (name, age) {
Person.call(this, name) //调用父类的构造函数 这样子类也有一个name实例属性了
this.age = age;
}
Student.prototype = Object.create(Person.prototype) //子类的原型指向父类的原型,不用调用两次构造函数
Student.prototype.constructor = Student;
Student.prototype.sayAge = function () {
console.log(this.age)
}
var son = new Student("bibi", 12)
son.sayName()
son.sayAge()
寄生组合式继承和组合式继承的区别
组合继承 Students.prototype = new Person() 这样调用一次构造函数,Person的实例方法出现在Students的原型中,var student = new Student()时又调用一次Person的构造函数,这个时候Person的实例属性变成Students的实例属性,覆盖了原型中的属性,浪费了空间,没必要。
原型链继承 子类的原型等于父类的实例
function Person (name) {
this.name = "bibi";
this.friend = ["biubiu", "piupiu"]
}
Person.prototype.sayName = function () {
console.log(this.name)
}
function Student (name, age) {
this.age = age;
}
Student.prototype.sayAge = function () {
console.log(this.age)
}
// 原型链继承
//问题:(1)Person的实例属性成为student的原型属性,那么所有实例对象会共享引用类型的原型属性
// (2)没办法在不影响所有实例对象的情况下向父类传参
Student.prototype = new Person()
var son = new Student()
var son2 = new Student()
son.friend.push("Anny");
console.log(son2.friend) //[ 'biubiu', 'piupiu', 'Anny' ]
借用构造函数 子类的构造函数调用父类的构造函数
function Person () {
this.name = "bibi";
this.friend = ["biubiu", "piupiu"]
}
Person.prototype.sayName = function () {
console.log(this.name)
}
function Student (age) {
Person.call(this) //借用构造函数方法,问题:不能调用父类的原型方法
this.age = age;
}
Student.prototype.sayAge = function () {
console.log(this.age)
}
var son = new Student()
var son2 = new Student()
son.friend.push("Anny");
console.log(son2.friend)
son.sayName() //报错sayName不是一个方法
原型式继承
var person = {
name: "gred",
friend: ["bob", "alice"]
}
var student = Object.create(person) //让子类的原型等于已有对象的实例,缺点也是原型属性共享
student.age = 12
寄生式继承
function creatOtherPerson () {
var clone = Object.create(Person)
clone.sayHi = function () {
console.log("Hi")
}
return clone
}
var anotherperson = creatOtherPerson()
anotherperson.sayHi() // Hi