js之继承
js继承有许多继承,我们在这里就简述几个常用、实用、易理解的ES5继承。
JS中的类和实例是基于原型和原型链机制来处理的.
1.原型链继承
特点:
- JS继承也不像其他语言中的继承一样(其他语言:子类继承父类,就是拷贝一份父类的属性和方法),js中他是把父类的实例放到子类的原型链上,子类实例想要去调用这些属性和方法的时候,实际上是基于__proto__原型链查找的形式去完成的。
- 子类实例可以直接修改父类上的方法(这样就会导致其他父类实例都会收到影响)。
- 父类中私有的属性和方法,在实现原型链继承之后都会变成子类公有的属性和方法。
Child.prototype = new Parent();//让子类的原型指向父类的实例;
Child.prototype.constructor = Child;//为了保证原型链的完整性
具体实例:
//父类实例:
function A(x) {
this.x = x//父类私有属性
}
A.prototype.getX = function () { //父类公有属性
console.log(this.x);
}
//子类实例:
function B(y) { //子类私有属性
this.y = y
}
B.prototype = new A(100);//使子类的原型指向父类的实例;
B.prototype.constructor = B;//保证原型链完整
B.prototype.getY = function () {//子类公有属性
console.log(this.y);
}
let b = new B(200);
b.x //==> undefined
b.getX(); //==> b.getX is not a function
console.log(a);//{x:100} ==> __proto__.getX =fn
console.log(b);//{y:200} ==> __proto__.getY =fn
原型链继承
2.构造函数(使用call方法实现继承)
特点:
1.只能继承父类私有的属性和方法(因为只是把父类构造函数当作普通函数执行了一次,跟父类的原型上的方法和属性没有任何关系)。
2.父类的私有的属性和方法 都会变成子类私有的属性和方法。
// /call继承(借用构造函数继承)
// //在子类构造函数中把父类构造函数当作普通的函数执行,
// 并且通过call方法把父类构造函数中的this替换成子类的实例(this),
// 这样相当于给子类实例设置了私有的属性和方法
// 父类实例
function A(x) {
this.x = '哈哈哈'
}
A.prototype.get = function () {
return 'abcd'
}
let a=new A(666)
console.log(a);
// 子类实例
function B(x,y) {
this.y = '嘻嘻嘻'
A.call(this,y)
}
B.prototype.geta = function () {
return 'EFGH'
}
let b=new B(666)
console.log(b);
console.log(b.x);
console.log(b.get);//call继承子类只能拿到父类私有属性,父类公有属性拿不到
3.组合继承(结合原型链继承和借用构造函数继承的方法)
特点:
1.子类实例可以使用父类的私有属性和方法。
2.父类私有的属性和方法也会变成子类实例私有的属性和方法。
3.子类实例继承父类公有的属性和方法。
4.子类的原型链上会存在一份多余的父类私有属性。
函数可以复用不存在引用属性问题。
//父类构造函数
function Parent(x){
this.x = x;
this.sayHello = function (){
console.log("sayHello")
}
}
//父类原型
Parent.prototype.getX = function (){
console.log("getX",this.x)
}
//子类构造函数
function Child(y,x){
Parent.call(this,666)
this.y = y;
}
Child.prototype = new Parent(100);
Child.prototype.constructor = Child;
Child.prototype.getY = function (){
console.log("getY",this.y)
}
//子类实例
let c1 = new Child(200,666);
4.寄生组合继承(object.create)
结合原型链继承和借用构造函数继承的方法,同时需要自己创建prototype,实现寄生组合式继承
特点:
1.最完美的JS继承解决方案。
2.父类私有的属性和方法,子类实例私有的属性和方法。
3.父类公有的属性和方法,子类实例公有的属性和方法。
4.子类实例修改公有的属性和方法不会影响父类的实例。
//父类构造函数
function Parent(x){
this.x = x;
this.sayHello = function (){
console.log("sayHello")
}
}
//父类原型
Parent.prototype.getX = function (){//父类共有属性
console.log("getX",this.x)
}
let p1 = new Parent(100);
//子类构造函数
function Child(y,x){
Parent.call(this,666)
this.y = y;
}
// Child.prototype = new Parent(100);//子类共有属性
// Child.prototype = {};
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
Child.prototype.getY = function (){
console.log("getY",this.y)
}
//子类实例
let c1 = new Child(200,666);
// Object.create(arg) 创建一个空的对象,并且让这个空对象的__proto__指向传递的第一个参数
Object.create = function(obj){
//IE浏览器不支持用户在JS代码中直接的修改或者使用__proto__
// let newObj = {};
// newObj.__proto__ = obj;
// return newObj
function NewObj(){}
NewObj.prototype = obj;
return new NewObj()
}
ES6中的类之继承
class 相当于es5中构造函数,定义方法时,前后不能加function,全部定义在class的protopyte属性中
class和方法内默认都是严格模式,class中定义的所有方法是不可枚举的,只能定义方法,不能定义对象,变量等
es5中constructor为隐式属性
// ES5中的类(class) => 构造函数(constructor)
function Parent(x){
this.x = x;
this.sayHello = function (){
console.log("sayHello")
}
}
Parent.prototype.sx= "属性";
Parent.prototype.getX= function (){
console.log("getX==>",this.x)
}
let p1 = new Parent(100);
{//ES6中的类
class Parent {
constructor(x) {
this.x = x;
this.sayHello = function () {
console.log("sayHello")
}
}
// sx: "属性",
getX() {
console.log("getX==>", this.x)
}
}
//公有属性
Parent.prototype.name = "Parent";
//公有方法
Parent.prototype.getX= function (){
console.log("getX==>",this.x)
}
let p1 = new Parent(100)
}
//ES6中的继承
class Parent {
constructor(x) {
this.x = x;
this.sayHello = function () {
console.log("sayHello")
}
}
getX() {
console.log("getX==>", this.x)
}
}
class Child {
constructor(y) {
//在ES6的class没有办法直接当作一个普通函数执行
// Child(123) //Uncaught TypeError: Class constructor Child cannot be invoked without 'new' //必须使用new关键字来创建实例,不能当作一个普通函数执行
// Parent.call(this,100)
this.y = y;
}
getY(){
console.log("getY==>", this.y)
}
}
//在使用ES6的继承的时候,没有办法直接重定向子类的原型
Child.prototype = Object.create(Parent.prototype);
let c1 = new Child(200);
//ES6中的继承
//通过extends来实现的继承
//ES6继承 ==>class 子类构造函数 extends 父类构造函数{}
//Child.prototype.__proto__ = Parent.prototype;
/*
* 1. 父类的私有属性和方法,会成为子类的私有属性和方法
* 2.
* */
class Parent {
constructor(x) {
this.x = x;
this.sayHello = function () {
console.log("sayHello")
}
}
getX() {
console.log("getX==>", this.x)
}
}
class Child extends Parent {
//如果不写constructor,不会报错,继承会正常继承
//如果不写constructor浏览器会自动的帮我们去创建以下代码
// constructor(...args){
// super(...args)
// }
constructor(y) {
super(100);// Parent.call(this,100)
//Uncaught ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
//如果是通过继承的形式写了constructor,那么就必须使用super来继承父类的私有属性和方法,不然就会报错
this.y = y;
}
getY(){
console.log("getY==>", this.y)
}
}
let c1 = new Child(200)
谢谢各位大佬的光临,请多多指教