JavaScript-继承的多种的方式

有异议或者理解不对的地方欢迎指出

js继承:通过某种方式让一个对象可以访问到另一个对象中的属性和方法。

为什么使用继承:
某些对象会有函数方法,如果把这些函数方法都放置在构造函数内部,会造成浏览器内存的浪费。

首先
先定义父类:
定义父类,并在父类的原型上添加方法
在这里插入图片描述
var p1=new Person();
var p2=new Person();

p1.printNamep2.printName–.true
p1.printName
=p2.printName—true
如果比较的是对象的话,双等和三等无区别。如果是值的话,双等比较值是否一样,三等还比较两个值在是否指向对一个内存。

**结论1:**根据上面的比较内容可得知,只要在某个构造函数的prototype属性上添加属性和方法,这个构造函数的属性和方法,都可以被该构造函数的所有实例共享。

根据javascript权威指南中的解释,这里的构造函数的prototype对象称之为原型对象
Person.prototypes是p1,p2(Person构造函数实例)的原型对象
person的原型对象是function.prototype.

js的继承方式有哪些

一:原型链继承

子类实例的原型等于父类的实例,从而继承父类构造函数的属性.构造函数方法,原型方法,原型属性.
但是原型属性是子类共同使用的.如果修改了,其他子类会受到影响.另外实例无法向构造函数传参.

function PersonOne(){
}
PersonOne.prototype= new Person(“asd”,12);
var personone=new PersonOne(“sum1”);
personone.proto.proto.sex=“123”;
console.log(personone.name,personone.age);
console.log(personone.sex);
personone.setAge();
personone.printName();
console.log(personone,"&&&&");
var persontwo=new PersonOne();
console.log(persontwo.name,persontwo.age);
console.log(persontwo.sex)
persontwo.printName();
console.log(persontwo);
输出:
在这里插入图片描述
想要避免这种情况,可以使用借用构造函数实现,也可以重新new新的子类去继承父类
在这里插入图片描述
这样除了父类原型属性共享外,构造参数实现了私有化.在这里插入图片描述

二:借用构造函数实现继承

通过借助call/apply来改变this的指向,从而构造独有的作用域,每个实例继承属性私有化,相互之间不影响.
缺点:构造方法无法复用,每个实例有携带一个构造方法.
function PersonOne(){
Person.call(this,arguments);
}
PersonOne.prototype= new Person();
var personone=new PersonOne(“tom”,“123”);
var persontwo=new PersonOne(“Jack”,“456”);
console.log(personone);
console.log(persontwo);
console.log(personone.setAge === persontwo.setAge)
console.log(personone.printName === persontwo.printName)
输出:
在这里插入图片描述

三:组合继承

把方法放到父类的原型上,实现复用.例如上述的printName方法,唯一不足的是父类构造函数调用两次,子类实例上会覆盖子类原型上的.

四:原型继承

通过在中间生成对象,使用中间对象去继承父类,最后接收生成的新对象.
f
核心:
(1)function create(obj){
var F = function(){};
F.prototype = obj;
return new F();
}
用法:var person=new Person();
var proto=create(person);
不足:原型引用的属性会被实例共享,而且无法实现复用.

五:寄生组合继承

相对于来说较为完善.(Es6提供Object.create创造新对象的方法);
function Person(name,age){
this.name=name;
this.age=age;
this.setAge=function(){
console.log(this.age);
}
}
Person.prototype.printName=function(){
console.log(this.name);
}
Person.prototype.sex=“1”;
function PersonOne(){
Person.call(this,arguments);
}
//继承父类原型上的属性和方法,相比之前create去掉了多余的父类实例的属性
var proto=Object.create(Person.prototype);
//将生成的proto新对象与PersonOne进行关联,相当于PersonOne实例化的实例.
proto.constructor=PersonOne;
//关联原型,实例化后proto具有父类的构造属性,方法,原型的方法,属性
PersonOne.prototype=proto;

自己在编写的时候,发现这个问题.
function Person(){
this.name=“parent”
this.arr=[1,2];
}
Person.prototype.printName=function(){
console.log(this.name);
}

 function PersonOne(){

 }

 PersonOne.prototype=new Person();
 var person=new PersonOne();
 person.name="2";
 person.arr.push(4)

 console.log(person)

 var per2=new PersonOne();

 console.log(per2)

在这里插入图片描述
name属性在实例上实例化,但是arr却并没有实例化,原因在于arr为引用类型,在赋值的时候实例会随着原型链找到arr的位置并修改值(arr在堆上的地址是唯一的).而name是String类型,所以不能直接修改值,需要通过实例化生成对象,从而修改值.每一个实例化的对象在栈上的位置不同,具有私有化.

部分参考该文章:https://www.cnblogs.com/ayqy/p/4471638.html

  • 8
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值