ES5和ES6的继承区别(class类)
-
ES5继承
-
寄生组合式继承(基本思想)
- 定义祖先
- 定义祖先可继承的变量
- 定义继承的类(构造函数),并在类中调用组件的方法
- 使用 prototyoe定义继承关系
- 重新将constructor指向自己
function (a){ this.varA = a; } //定义祖先对象的可继承属性和方法 A.prototype = { varA : null, doSomeThing: function(){ console.log(this.varA); }, } //定义继承函数 function B(a,b){ A.call(this,a); this.varB = b; } //定义继承关系 B.prototype = Object.create(A.prototype) B.prototype.doSomeThing = function(){ console.log(this.varB); } //绑定Constructor B.prototype.constructor = B; var b = new B('a','b'); var a = new A('a'); a.doSomeThing(); b.doSomeThing();
-
-
ES6继承
-
基本思想
- Class之间通过使用extends关键字,这比通过修改原型链实现继承,要方便清晰很多
class Colorpoint extends Point { constructor(x,y,color){ super(x,y); //调用父类的constructor(x,y) this.color = color } toString(){ //调用父类的方法 return this.color + ' ' + super.toString(); } }
-
注意事项
- 子类必须在constructor中调用super方法,否则新建实例时会报错,这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工,如果不调用super方法,子类就得不到this对象,因此,只有调用super之后,才可以使用this关键字
-
-
区别和不同
-
类内部定义的方法,是不可枚举的,和ES5不同
-
类不存在变量提升,这一点和ES5不同
-
类相当于实例的原型,所有在类中定义的方法,都会被实例继承,
如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称之为静态方法 -
es5的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面,es6的继承机制完全不同,实质先创造父类的实例对象this,
所以必须先调用super方法`,然后再用子类的构造函数修改this -
类的prototype属性和proto属性,大多数浏览器的ES5实现之中,每一个对象都有proto属性,指向对应的构造函数的prototype属性,Class作为构造函数的语法糖,同时有prototype属性proto属性,因此同时存在两条继承链
-
子类的proto属性,表示构造函数的继承,总是指向父类
-
子类的prototype属性的proto属性,表示方法的继承,总是指向父类的prototype属性
//类和模块的内部,默认就是严格模式,所以不需要使用use strict指定运行模式。 //只要你的代码写在类或模块之中,就只有严格模式可用。 class Point { //constructor方法,就是构造方法 //如果没有定义constructor方法,JS会自动为其添加 //constructor方法默认返回实例对象(即this),完全可以指定返回另外一个对象。 constructor(x, y) { //this代表实例对象 this.x = x; this.y = y; this.tohello = function () { console.log("hello"); } } //类的方法,不需要加上function这个关键字 //下面代码中,toString方法是Point类内部定义的方法,它是不可枚举的。 //这一点与 ES5 的行为不一致。 toString() { return '(' + this.x + ', ' + this.y + ')'; } } //完全可以看成构造函数的另外一种写法 Point === Point.prototype.constructor // true //构造函数的prototype属性,在 ES6 的“类”上面继续存在。 //事实上,类的所有方法都定义在类的prototype属性上面。 //除非显示定义在类上面 //类必须使用new调用,否则会报错。 //这是它跟普通构造函数的一个主要区别,后者不用new也可以执行。 let p = new Point('x', 'y'); p.tohello(); // p.prototype.tohello(); //false //与 ES5 一样,类的所有实例共享一个原型对象。 var p1 = new Point(2, 3); var p2 = new Point(3, 2); p1.__proto__ === p2.__proto__ //true //上面代码中,p1和p2都是Point的实例,它们的原型都是Point.prototype,所以__proto__属性是相等的。 //这也意味着,可以通过实例的__proto__属性为“类”添加方法。 //__proto__ 并不是语言本身的特性,这是各大厂商具体实现时添加的私有属性, //虽然目前很多现代浏览器的 JS 引擎中都提供了这个私有属性, //但依旧不建议在生产中使用该属性,避免对环境产生依赖。 //生产环境中,我们可以使用 Object.getPrototypeOf 方法来获取实例对象的原型,然后再来为原型添加方法/属性。 //不推荐下面的做法 p1.__proto__.printName = function () { return 'Oops' }; p1.printName() // "Oops" p2.printName() // "Oops" var p3 = new Point(4, 2); p3.printName() // "Oops" //类不存在变量提升(hoist),这一点与 ES5 完全不同。 class Foo { //静态方法,只能通过类来调用 //父类的静态方法也会被子类继承 static classMethod() { return 'hello'; } } Foo.classMethod() // 'hello' var foo = new Foo(); // foo.classMethod() // TypeError: foo.classMethod is not a function //实现继承 class ColorPoint extends Point { constructor(x,y,color){ //调用父类的构造函数,用来新建父类的this对象 //super作为函数调用时,返回的是子类B的实例,super内部的this指向B //super相当于 A.prototype.constructor.call(this) //super作为函数只能用在constructor中 super(x,y); //子类必须使用super方法,否则子类没有自己的this对象 //继承父类的this对象然后进行加工 this.color = color; } toString() { //super作为对象使用时,指向父类的原型对象。 //在静态方法中指向父类 //定义在父类实例上的方法是没办法用的 return this.color + ' ' +super.toString();//调用父类的方法 } } //可以使用getPrototypeOf方法来获取父类 Object.getPrototypeOf(ColorPoint) === Point ColorPoint.__proto__ == Point; //true ColorPoint.prototype.__proto__ == Point.prototype;//true //这里和es5不一样 //对象有属性__proto__,指向该对象的构造函数的原型对象。 //方法除了有属性__proto__,还有属性prototype,prototype指向该方法的原型对象。 var p1 = new Point(2, 3); var p2 = new ColorPoint(2, 3, 'red'); // p2.__proto__ === p1.__proto__ // false p2.__proto__.__proto__ === p1.__proto__ // true
-
-