ES5原型的几种常用继承方式 原型链继承(子类原型指向父类实例) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 function SuperType ( ) { this .colors = ['red' , 'blue' , 'green' ]; } function SubType ( ) {}SubType.prototype = new SuperType(); let instance1 = new SubType();instance1.colors.push('black' ); console .log(instance1.colors);let instance2 = new SubType();console .log(instance2.colors);
缺点: - 属于引用类型传值,某一个副本实例属性的修改会引起其他副本实例属性的变化 - 不能向父类构造函数传递参数,不够灵活
借用构造函数继承(执行子类构造函数、各得到一份父类实例副本) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 function Parent ( ) { this .colors = ['red' , 'blue' , 'green' ]; } Parent.prototype.say = function ( ) { console .log('hello' ); }; function Child ( ) { Parent.call(this ); } let instance3 = new Child();instance3.colors.push('white' ); console .log(instance3.colors);console .log(instance3.prototype);let instance4 = new Child();console .log(instance4.colors);
属于值传递,子类之间属性修改互不相干
缺点:没有父类prototype上的属性,而且instanceof操作无法判断出子类实例和父类的关系,因为子类的prototype和父类无关
组合式继承 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 function Person (name, age ) { this .name = name; this .age = age; this .action = ['speak' , 'run' , 'eat' ]; console .log('我被调用了' ); } Person.prototype.say = function ( ) { console .log(`my name is ${this .name} and I am ${this .age} years old!` ); }; function Student (name, age, score ) { Person.call(this , name, age); this .score = score; } Student.prototype = new Person(); Student.prototype.constructor = Student; Student.prototype.showScore = function ( ) { console .log(`my score is ${this .score} ` ); }; let xiaoming = new Student('xiaoming' , 23 , '88' );xiaoming.action.push('panio' ); console .log(xiaoming.action);xiaoming.say(); xiaoming.showScore(); let xiaohua = new Student('xiaohua' , 24 , '99' );console .log(xiaohua.action);xiaohua.say(); xiaohua.showScore();
Student.prototype = new Person();将子对象的prototype与父对象的实例关联,实现原型链连接
Person.call(this, name, age); 和Student.prototype.constructor = Student; 在每一次new Student时,获得一个父实例副本,更改属性不会互相影响。
原型式继承 利用一个空对象作为媒介,将某对象直接赋值给空对象的构造函数的原型
1 2 3 4 5 function object (obj ) { function F ( ) {} F.prototype = obj; return new F(); }
object()函数创建了一个临时构造函数,将传入的对象赋值给这个构造函数的原型,并返回这个临时类型的一个实例。本质上,object()是对传入的对象执行了一次浅复制。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 var person = { name: "Nicholas" , friends: ["Shelby" , "Court" , "Van" ] }; var anotherPerson = object(person);anotherPerson.name = "Greg" ; anotherPerson.friends.push("Rob" ); var yetAnotherPerson = object(person);yetAnotherPerson.name = "Linda" ; yetAnotherPerson.friends.push("Barbie" ); alert(person.friends);
person的原型既有原始值属性又有引用值属性。这也意味着,当你通过anotherPerson 或者yetAnotherPerson 改变引用值属性的值时,person的引用值属性会被改变
原文地址
ES6继承 ES6引入了class语法糖,使继承操作看起来更像面向对象语言的写法。在JS中,class的本质还是一个function。 通过extends关键字,不仅可以继承一个类,也可以继承普通的构造函数。
1 2 3 4 5 6 7 8 9 10 class A {}class B extends A { constructor ( ) { super (); } } function C ( ) {}class D extends C {}
constructor方法是类的默认构造函数,若未定义,则默认添加。在constructor中必须调用super方法,因为子类没有自己的this对象,而是继承父类的this对象,然后对其加工,super就代表了父类的构造函数,但在super内部的this指向B···
1 A.prototype.constructor.call(this , props)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class A { constructor ( ) { console .log(new .target.name); } } class B extends A { constructor ( ) { super (); } } new A(); new B();
笔者知识有限,有理解不到位的地方,欢迎指正。