有异议或者理解不对的地方欢迎指出
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类型,所以不能直接修改值,需要通过实例化生成对象,从而修改值.每一个实例化的对象在栈上的位置不同,具有私有化.