1. 构造函数继承
问题:原型上的方法或者属性,无法继承
function Fn() {
this.name = "zhangsan",
this.age = 12
this.eat = function () {
console.log("eat")
}
}
Fn.prototype.sleep = function () {
console.log("sleep")
} // 无法继承
function F() {
// console.log(this)
// Array.prototype.join.call(obj,'-') / Array.prototype.join.apply(obj,['-'])
Fn.call(this)
}
var fn = new Fn()
console.log(fn)
var f = new F()
console.log(f.sleep())
重点:用.call()和.apply()将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复制))
特点:1、只继承了父类构造函数的属性,没有继承父类原型的属性。
2、解决了原型链继承缺点1、2、3。
3、可以继承多个构造函数属性(call多个)。
4、在子实例中可向父实例传参。
缺点:1、只能继承父类构造函数的属性。
2、无法实现构造函数的复用。(每次用每次都要重新调用)
3、每个新实例都有父类构造函数的副本,臃肿。
2、 原型继承
问题: 共用一个原型对象,导致谁修改原型对象的值,其余对象都会被更改
function Fn() {
this.name = "zhangsan"
this.age = 12
this.color = ["yellow", "pink"]
this.eat = function () {
console.log("eat")
}
}
Fn.prototype.sleep = function () {
console.log("sleep")
}
function F() {
}
F.prototype = new Fn()
var f = new F()
var f1 = new F()
f.color.push("black")
console.log(f1.color)
重点:让新实例的原型等于父类的实例。
特点:1、实例可继承的属性有:实例的构造函数的属性,父类构造函数属性,父类原型的属性。(新实例不会继承父类实例的属性!)
缺点:1、新实例无法向父类构造函数传参。
2、继承单一。
3、所有新实例都会共享父类实例的属性。(原型上的属性是共享的,一个实例修改了原型属性,另一个实例的原型属性也会被修改!)
3、组合方式继承:
function Fn() {
this.name = "zhangsan"
this.age = 12
this.color = ["yellow", "pink"]
this.eat = function () {
console.log("eat")
}
}
function F() {
Fn.call(this)
}
F.prototype = Object.create(Fn.prototype)
// F.prototype = Fn.prototype.constructor === Fn
F.prototype.constructor = F
var f = new F()
var f1 = new F()
f.color.push("black")
console.log(f1.color)
function FCC() { }
//instanceof 用来
console.log(f instanceof FCC) //true
console.log(f instanceof Fn) //true
console.log(typeof 1) //numeber
重点:结合了两种模式的优点,传参和复用
特点:1、可以继承父类原型上的属性,可以传参,可复用。
2、每个新实例引入的构造函数属性是私有的。
缺点:调用了两次父类构造函数(耗内存),子类的构造函数会代替原型上的那个父类构造函数。
- instanceof运算符的左边是实例对象,右边是构造函数。它会检查右边构建函数的原型对象(prototype),是否在左边对象的原型链上。因此,上面两种写法是等价的。
- instanceof运算符只能用于对象,不适用原始类型的值。