共计 3460 个字符,预计需要花费 9 分钟才能阅读完成。
JavaScript
继承
原型链继承
function Parent() {this.name = '父亲'; // 实例基本属性 (该属性,强调私有,不共享)
this.arr = [1]; // (该属性,强调私有)
}
Parent.prototype.say = function() { // -- 将需要复用、共享的方法定义在父类原型上
console.log('hello')
}
function Child(like) {this.like = like;}
Child.prototype = new Parent() // 核心
let boy1 = new Child()
let boy2 = new Child()
// 优点:共享了父类构造函数的 say 方法
console.log(boy1.say(), boy2.say(), boy1.say === boy2.say); // hello , hello , true
// 缺点 1:不能传参数
// 缺点 2:console.log(boy1.name, boy2.name, boy1.name===boy2.name); // 父亲,父亲,true
boy1.arr.push(2); // 修改了 boy1 的 arr 属性,boy2 的 arr 属性,也会变化,因为两个实例的原型上 (Child.prototype) 有了父类构造函数的实例属性 arr;所以只要修改了 boy1.arr,boy2.arr 的属性也会变化。---- 原型上的 arr 属性是共享的。console.log(boy2.arr); // [1,2]
注意:修改 boy1 的 name 属性,是不会影响到 boy2.name。因为 name 是基本属性,不是引用属性。
构造函数继承
function Parent(name) {this.name = name; // 实例基本属性 (该属性,强调私有,不共享)
this.arr = [1]; // (该属性,强调私有)
this.say = function() { // 实例引用属性 (该属性,强调复用,需要共享)
console.log('hello')
}
}
function Child(name,like) {Parent.call(this,name); // 核心
this.like = like;
}
let boy1 = new Child('小红','apple');
let boy2 = new Child('小明', 'orange');
// 优点 1:可传参
console.log(boy1.name, boy2.name); // 小红,小明
// 优点 2:不共享父类构造函数的引用属性
boy1.arr.push(2);
console.log(boy1.arr,boy2.arr);// [1,2] [1]
// 缺点 1:方法不能复用
console.log(boy1.say === boy2.say) // false (说明,boy1 和 boy2
的 say 方法是独立,不是共享的)
// 缺点 2:不能继承父类原型上的方法
Parent.prototype.walk = function () { // 在父类的原型对象上定义一个 walk 方法。console.log('我会走路')
}
boy1.walk; // undefined (说明实例,不能获得父类原型上的方法)
组合继承
function Parent(name) {this.name = name; // 实例基本属性 (该属性,强调私有,不共享)
this.arr = [1]; // (该属性,强调私有)
}
Parent.prototype.say = function() { // --- 将需要复用、共享的方法定义在父类原型上
console.log('hello')
}
function Child(name,like) {Parent.call(this,name,like) // 核心 第二次
this.like = like;
}
Child.prototype = new Parent() // 核心 第一次
<!-- 这里是修复构造函数指向的代码 -->
let boy1 = new Child('小红','apple')
let boy2 = new Child('小明','orange')
// 优点 1:可以传参数
console.log(boy1.name,boy1.like); // 小红,apple
// 优点 2:可复用父类原型上的方法
console.log(boy1.say === boy2.say) // true
原型式继承
// 两种方法
// Object.create
// function object
function object(o){function F(){ }
F.pototype=o;
return new F()}
let parent = {
name: 'parent',
share: [1, 2, 3], // 父类的引用属性全部被子类所共享
log: function() { // 父类方法可以复用
return this.name
}
}
let child = Object.create(parent) // 子类不能向父类传递参数
寄生继承
function createAnother(original){var clone = object(original)
clone.sayHi = function(){alert('hi');
}
return clone;
}
var person = {
name:"hello",
friends:['z',"x","p"]
}
var anotherPerson = createAnother(person);
anotherPerson.sayHi() //'hi'
寄生组合继承
function Parent(name, friends) {
this.name = name
this.friends = friends
}
Parent.prototype = {
constructor: Parent, // 需要手动绑定 constructor
share: [1, 2, 3],
log: function() {return this.name}
}
function Child(name, friends, gender) {Parent.call(this, name, friends) // 这里只需要调用一次 Parent
this.gender = gender
}
// 上半部分和组合继承一样
let F = function() {} // 创建一个中介函数
F.prototype = Parent.prototype // 这个中介的原型指向 Parent 的原型
Child.prototype = new F() // 注意这里没有使用 new 操作符调用 Parent
Child.prototype.constructor = Child
// 封装
function Parent(name, friends) {
this.name = name // 可以定义私有属性
this.friends = friends // 可以定义公有引用属性不会被共享
}
Parent.prototype = {
constructor: Parent, // 需要手动绑定 constructor
share: [1, 2, 3], // 这里定义的公有属性会被共享
log: function() { // 方法被共享了
return this.name
}
}
function Child(name, friends, gender) {Parent.call(this, name, friends) // 可以向父类传递参数 这里又调用了一次 Parent
this.gender = gender
}
function proto(child, parent) {let clonePrototype = Object.create(parent.prototype)
// 核心 通过创建中间对象,子类原型和父类原型,就会隔离开
child.prototype = clonePrototype
child.prototype.constructor = child
}
proto(Child, Parent)
ES2015 class extends
继承
lass Parent {constructor(name, friends) { // 该属性在构造函数上,不共享
this.name = name
this.friends = friends
}
log() { // 该方法在原型上,共享
return this
}
}
Parent.prototype.share = [1, 2, 3] // 原型上的属性,共享
class Child extends Parent {constructor(name, friends, gender) {super(name, friends)
this.gender = gender
}
}
正文完
发表至: javascript
2019-11-19