继承
原型链继承
在 es5 中,为了实现方法的共享和复用,使用原型链作为实现继承的主要方法。每一个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,实例都包含一个指向原型对象的内部指针。
一个例子:
function Test() {
console.log("1111");
}
Test.prototype.foo = function() {
console.log("foo");
};
var oo = new Test();
console.log(oo.__proto__ === Test.prototype); // true
console.log(oo.constructor === Test); // true
console.log(Test.prototype.constructor === Test); // true
console.log(Test.prototype === Test.prototype); //true
构造函数(Test) 有 原型对象(Test.prototype)
原型对象(Test.prototype) 包含 指向构造函数的指针(Test.prototype.constructor)
实例(oo) 包含 指向原型对象的内部指针(oo.__proto__)
- 使用原型链继承
当我们需要共享一些方法,并且,方法能够
function Parent(name, age) {
this.name = name;
this.age = age;
}
Parent.prototype.message = function() {
console.log("个人信息:" + this.name + this.age);
};
var Parent = new Parent("张三", 24);
function Child(name, age) {
this.name = name;
this.age = age;
}
Child.prototype = new Parent();
var child = new Child("李四的儿子:", 1);
child.message();
- 使用 call、apply 实现继承
function Parent(name, age) {
this.name = name;
this.age = age;
this.message = function() {
console.log("个人信息:" + this.name + this.age);
};
}
function Child() {
Parent.apply(this, arguments);
// function Child(name, age) {
// Parent.call(this,name,age)
}
var child = new Child("张三的儿子", 1);
child.message();
使用 call/apply,在 Child 构造函数内调用 Parent 函数,初始化 Parent 中定义的对象,Child 的每个实例就拥有来自 Parent 的副本对象了。当对 Parent 的对象进行修改,Child 继承的属性不会被修改。例如:
function Parent(name, age) {
this.name = name;
this.age = age;
this.test = "aaaaa";
this.message = function() {
console.log("个人信息:" + this.name + this.age);
};
}
var parent = new Parent();
parent.test = "bbbb";
parent.name = "oooo";
console.log(parent.test); // bbbb
console.log(parent.name); // oooo
function Child(name, age) {
Parent.call(this, name, age);
}
var child = new Child("张三的儿子", 1);
console.log(child.test); // aaaaa
console.log(child.name); // 张三的儿子
- 原型链 prototype 和 call/apply 一起使用
function Parent(name, age) {
this.name = name;
this.age = age;
}
Parent.prototype.message = function() {
console.log("个人信息:" + this.name + this.age);
};
function Child() {
Parent.apply(this, arguments);
}
Child.prototype = new Parent();
var child = new Child("张三的儿子", 1);
使用 apply/call 继承的是 Parent 构造函数中的属性,使用原型链继承的是 Parent 原型链上的属性。
class 继承
es6 中可以使用 class 关键字定义一个类
class Parent {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
typeof Parent; // 'function'
Parent === Parent.prototype.constructor; // true
Parent 类的数据类型为函数,Parent 指向构造函数(constructor)。构造函数的 prototype 属性在 ES6 的"类"上依然存在,类的所有方法(除 constructor)都定义在类的 prototype 属性上。
class Parent {
constructor(name, age) {
this.name = name;
this.age = age;
}
message() {
console.log("个人信息:" + this.name + this.age);
}
}
//可以等同于
Parent.prototype.message = function() {
// ...
};
class Parent {
constructor(name, age) {
this.name = name;
this.age = age;
console.log("ppppooo");
}
message() {
console.log("个人信息:" + this.name + this.age);
}
}
let parent = new Parent("张三", 24); // ppppooo
parent.message(); // 个人信息:张三24
console.log(parent.hasOwnProperty("constructor")); // false
console.log(parent.hasOwnProperty("message")); // false
console.log(parent.hasOwnProperty("name")); // true
从上例可以看出,constructor 在构建实例的时候就已经调用,hasOwnProperty 返回实例对象自身的属性,而 message 是原型对象所以打印出 false。
实现继承:
class Parent {
constructor(name, age) {
this.name = name;
this.age = age;
console.log("ppppooo");
}
message() {
console.log("个人信息:" + this.name + this.age);
}
}
class Child extends Parent {
constructor(name, age, home) {
super(name, age);
this.home = home;
}
getMess() {
console.log("extends:" + this.name);
}
}
let child = new Child("lisi", 55, 10086);
child.getMess(); // extends:lisi
child.message(); // 个人信息:lisi55
Child 类通过extends
super
继承了 Parent 的属性和方法。