1.原型链继承
原理: 子类原型指向父类实例对象实现原型共享,即Son.prototype = new Father()。
这里先简单介绍下原型
js中每个对象都有一个__proto__属性,这个属性指向的就是该对象的原型。js中每个函数都有一个prototype属性,这个属性指向该函数作为构造函数调用时创建的实例的原型。原型对象上有一个constructor属性,指向创建该对象的构造函数,该属性不可枚举。
var obj = {};
obj.__proto__ === Object.prototype; //true
console.log(Object.prototype.constructor) // "htmlcode">
var obj = {};
obj.toString();
obj.__proto__.toString(); //obj.__proto__和Object.prototype指向的是一个对象,自然就能访问Object.prototype上的toString方法啦
注意:原型链的终点是null,使用bind方法返回的函数没有prototype属性。
var obj = {};
function fn(){};
fn.bind(obj).prototype; // undefined
Object.prototype.__proto__; // null
原型链接继承
function Father(age){
this.age = age;
this.color = ['red','pink']
}
Father.prototype.sayHello = function(){
console.log('hello')
}
function Son(sex){
this.sex = sex
}
console.log(Son.prototype.constructor) // "htmlcode">
//写法一
Son.prototype.constructor = Son // 这种写法有点缺点,它会让constructor属性变的可以枚举。
//写法二
Object.defineProperty(Son.prototype,'constructor',{
enumerable:false, // 设置不可枚举
value:Son
})
2.构造函数继承
原理:在子类构造函数中通过apply或者call调用父类构造函数来继承属性或方法。
function Father(name){
this.color = ['red']
this.sayHello = function(){
console.log('hello')
}
}
Father.prototype.sayName = function(){
console.log('zs')
}
function Son(num,name){
Father.call(this,name) //实现继承的关键代码
this.num = num
}
var son = new Son(10,'zs')
var son2 = new Son(15,'ls')
son.color.push('pink')
console.log(son2.color) // ['red']
son.sayName() //报错 son.sayName is not a function
console.log(son.sayHello === son2.sayHello) //false
可以看出通过构造函数实现继承,解决了原型链继承不能向父类传参以及引用类型值共享的问题。但这种继承方法却不能访问父类构造函数原型上的方法和属性,而且定义在父类构造函数中的方法也不能复用。
3.组合式继承
组合继承,有时候也叫伪经典继承,它是将原型链继承和构造函数继承结合到一起的一种继承模式。实现思路是通过原型链实现对原型属性和方法的继承,通过借用构造函数实现对实例属性的继承。
function Father(name){
this.color = ['red']
}
Father.prototype.sayName = function(){
console.log('zs')
}
function Son(num,name){
Father.call(this,name) //继承实例属性
this.num = num
}
Son.prototype = new Father() //继承原型上属性
Son.prototype.constructor = Son
var son = new Son(10,'zs')
var son2 = new Son(15,'ls')
son.color.push('pink')
console.log(son.color,son2.color) //['red','pink'] ['red']
son.sayName() // zs
组合式继承避免了原型链继承和构造函数继承的缺点,融合了它们的优点,成为JavaScript中常用的一种继承模式。
4.寄生式继承
寄生式继承与工厂模式类似,一般用来继承对象。即创建一个封装继承的函数,在函数内部复制一份该对象,对复制的对象进行处理,返回复制的对象。
function createAnother(obj){
var clone = Object.create(obj)
clone.name = 'zs'
clone.sayHello = function(){
console.log('hello')
}
return clone
}
var obj = {age:15}
var newObj = createAnother(obj) // 15
console.log(newObj.name) // zs
newObj.sayHello() // hello
5.寄生组合式继承
前面说到过组合式继承是Javascript中最常用的继承模式,不过这种模式也有自己的不足,它会调用两次父类构造函数。第一次是在将子类原型指向父类实例的时候,第二次是在子类构造函数中调用的。
function Father(name){
this.name = name
}
function Son(num,name){
Father.call(this,name) // 第二次调用
}
Son.prototype = new Father('ls') // 第一次调用
var son = new Son(10,'zs')
console.log(son)
在第一次调用的时候,Son.prototype会继承name这个属性,第二次调用时,实例对象会继承name。当我们获取实例对象的name属性时因为实例对象上有该属性,所以是不会去原型上去寻找的,相当于实例对象上的name属性把原型上的name属性给屏蔽掉了,所以原型上的这个属性是多余的。
为了解决这个问题,就有了寄生组合式继承。主要思路就是创建一个函数完成原型链继承和constructor的指向问题,然后通过构造函数继承属性。
// 复制一个父类的原型指向,将子类的原型指向复制的父类原型,达到不用调用父类构造函数就能继承其原型上的方法的效果。
function inherit(Sup,Sub){
var prototype = Object.create(Sup.prototype)
Sub.prototype = prototype
prototype.constructor = Sub
}
function Father(name){
this.name = name
}
function Son(name){
Father.call(this,name)
}
inherit(Father,Son)
var son = new Son('zs')
console.log(son)
以上就是JavaScript中常用的几种继承方式啦。
免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
RTX 5090要首发 性能要翻倍!三星展示GDDR7显存
三星在GTC上展示了专为下一代游戏GPU设计的GDDR7内存。
首次推出的GDDR7内存模块密度为16GB,每个模块容量为2GB。其速度预设为32 Gbps(PAM3),但也可以降至28 Gbps,以提高产量和初始阶段的整体性能和成本效益。
据三星表示,GDDR7内存的能效将提高20%,同时工作电压仅为1.1V,低于标准的1.2V。通过采用更新的封装材料和优化的电路设计,使得在高速运行时的发热量降低,GDDR7的热阻比GDDR6降低了70%。

