了解继承前最好先看一下原型那一篇文章
属性查找:1.先自身查找
2.再沿原型向上查找
3.直到原型链出口结束 Object.prototype.__ proto__
面向对象的三大特点:封装,继承,多态。
继承 :从其他对象上获得属性或方法 叫做继承
编程所说的继承来自面向对象编程语言
类
类别有继承关系 (子类 和 父类)
JS中没有类 class 它的本质是 function,它只是一个语法糖
class a {};
console.log(typeof a);打印结果为function
JS中的构造函数 可以被看作是类 JS也可以看作是面向对象的编程语言
JS中的构造函数的行为 非常接近 类
由浅入深的演示下继承,重点看面向对象开发的两种继承方式
1.1子类继承父类的私有属性:修改父类的执行环境 ,让父类在子类中执行
function Father(name, age, sex) {
// 所有绑定在this关键字上的 属性 都是 '私有属性'(对象自身的属性)
this.name = name;
this.age = age;
this.sex = sex;
}
// 子类应该继承父类 私有属性
// 修改父类的执行环境
// 让父类在子类中执行
function Son(name, age, sex) {
this.f = Father;
this.f(name, age, sex);
delete this.f;
}
var s = new Son('zhangming', 18, 'nan');
console.log(s);
1.2从别的对象获得属性或方法:
让B的实例 获得 A的属性和方法;
通过原型来继承;
将A的实例赋值给B的原型;
function A() {
this.a = 'aaaaa';
this.fn = function() {
console.log(this.a);
}
}
function B() {
this.a = 'bbbbbbb';
}
// 从别的对象获得属性或方法
// 让B的实例 获得 A的属性和方法
// 通过原型来继承
// 将A的实例赋值给B的原型
B.prototype = new A();
var b = new B();
console.log(b);
b.fn();//打印结果bbbbbbb
B的原型是A;
A中的属性和方法在B的原型里,还是通过属性查找的方式来访问属性和方法。
如果B对象中没有a属性,打印的结果就为aaaaa
1.3这也是一种继承
var obj = {
x: 1,
fn: function() {
console.log(this.x);
}
};
var obj2 = {
x: 2
}
obj.fn.call(obj2); //打印结果为2 我们让obj2 借用了 obj的函数 fn
(重点:它来了,它来了)面向对象开发的两种方式,对应两种继承方式:
1.混合开发(构造函数继承+原型)–混合继承
案例:
function Father(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
Father.prototype.play = function() {
console.log('play');
}
function Son(name, age, sex) {
// 属性继承(构造函数的继承)---从父类继承属性 在子类中执行父类
Father.call(this, name, age, sex);
}
// 方法继承(原型继承)---通过 原型 继承 公有属性
Son.prototype = new Father();//第一种方法:将父类的实例化对象赋值给子类的原型,同时修改了子类的构造函数体。
Son.prototype = Father.prototype;//第二种方法:将父类的原型赋值给子类的原型
Son.prototype.constructor=Son;//重新设置子类的构造函数体。
var s = new Son('zhangming', 20, 'nan');
console.log(s);
s.play();
2.ES6class开发
class是构造函数的语法糖
extends关键字:
class 可以通过extends关键字实现继承,这比 ES5 的通过修改原型链实现继承,要清晰和方便很多。
super关键字:
子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。如果不调用super方法,子类就得不到this对象。
super关键字既可以当作函数使用,也可以当作对象使用。
第一种情况,super作为函数调用时,代表父类的构造函数。
第二种情况,super作为对象时,在普通方法中,指向父类的原型对象;
案例:
class Person {
constructor(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
showinfo() {
return `我的姓名是${this.name},我今年${this.age}岁,我是${this.sex}的`;
}
info() {
return '我是父类的方法';
}
}
let p1 = new Person('zhangsan', 100, '男');
console.log(p1.name);
console.log(p1.showinfo());
class Student extends Person {
constructor(name, age, sex, pro) {
//super作为函数调用时的情况
super(name, age, sex); //要得到与父类同样的实例属性和方法,必须先调用super方法,子类才能得到this对象
this.pro = pro;
}
showinfo() {
return super.showinfo() + ',我的专业是' + this.pro; //super当对象使用的情况
}
}
let s1 = new Student('lisi', 2500, '女', 'web');
console.log(s1.name);
console.log(s1.showinfo());
console.log(typeof Person); //function 构造函数的语法糖