JavaScript在设计之初只是为了在浏览器中添加一点交互,但是在js中模仿了java 万物皆对象,所以必须有一种方式能够让对象之间的数据实产生关联,设计者便设计了一种Prototype的继承方式
壹、构造函数里面的继承
一、原型链继承
- 现在这里有一个动物构造函数
function Animal() {
this.specil = "动物";
}
- 然后有一个猫的构造函数
function Cat(name, color) {
this.name = name;
this.color = color;
}
3.实例化
var cat1 = new Cat('miaomiao', 'orange');
那么那么猫咪如何继承动物这一属性呢?
- 我们知道构造函数的实例可以继承自其构造函数的prototype属性(隐式继承)
- 这个prototype属性呢是一个object类型的空对象
- 那么将动物 这一构造函数的实列绑定给 prototype则可以让cat 实现继承
// 现在这里有一个动物构造函数
function Animal() {
this.specil = "动物";
}
// 然后有一个猫的构造函数
function Cat(name, color) {
this.name = name;
this.color = color;
}
// 那么猫咪如何继承动物这一属性
var cat1= new Cat('miaomiao','orange');
Cat.prototype = new Animal();
console.log(cat1.specil);
问题一:以上代码运行为undefinded
此问题的区别只有var cat1= new Cat('miaomiao','orange'); Cat.prototype = new Animal();
这两行代码的顺序问题。(困扰一整天…)
- 先前的理解:Cat构造函数的实例要继承Animal的属性,那么
cat1=new Cat
先实例化,cat1这个对象中能继承其构造函数的原型对象。那么在下一步我们将Cat.prototype
和Animal构造函数绑定
—Cat.prototype=new Animal
,则Animal的原型对象中的属性可被Cat的原型对象继承。
也就是两部:①cat1继承Cat原型,②Cat原型继承Animal…合情合理! - 实际的方式:上面的理解大致正确,但忽略了一个重要的属性
__proto__
,将过程细分则会发现区别。
①:先实例化的后果:Cat实例对象想继承Animal的东西,直接讲Cat的原型变成Animal的实例就可以啦~
毕竟cat1能继承Cat.prototype->Animal.prototype注意是因为cat1.__proto__得以继承一旦实例这个属性地址值就已经创建,后面并没有更改它的指向;
②:所以,由于是隐式继承,我们不能先更改Cat.prototype的指向!
那么 这也是可行的 var dog1 = new Dog(‘boolding’, 1);
dog1.proto = new Animal();
- 总结:** 理解1.原型链,且明白继承关系是隐式继承。2.new操作符**
二 原型链继承的改进
由于需要不必要的new Animal 过程,既然实现继承Animal=继承Animal.prototype那么Cat.prototype=Animal.prototype
能够节约内存
同样有有优点的同时,它有又有一个很大的缺陷:当我们修改Cat.prototype 时会影响到Animal的原型.
解决方案:创建一个temp空对象作为跳转.
所谓空对象并不是直接var temp={},然后temp=Animal.prototype;这并没有任何意义temp的地址同样指向了Animal原型地址!
function Temp() {
}
Temp.prototype = Animal.prototype;
var dog1 = new Temp();
console.log(dog1.specil); //animal
Dog.prototype.color = 'red';
console.log(Animal.prototype.color); //undefined
new 一个空对象实在是太香了(内存消耗很小);
最后一步封装成一个继承函数
function extend(Father, Son) {
function Temp() {};
Temp.prototype = Father.prototype;
Son.prototype = new Temp();
Son.prototype.constructor = Son;
}
function Animal() {
}
Animal.prototype.specil = "animal";
function Cat(name) {
this.name = name;
}
extend(Animal, Cat);
var cat1 = new Cat("maomi");
console.log(cat1.specil);
贰、非构造函数的继承
1.object函数
var animal = {
specil :"动物",
}
var cat = {
name:"tom"
}
function temp(){}
temp.prototype = animal;
cat = new temp();
cat.name="tom"
2.浅拷贝
遍历对象属性一一赋值
for (var i in animal) {
cat[i] = animal[i];
}
console.log(cat);
随便想想问题都大的很.
深拷贝
循环遍历浅拷贝
function deepCopy(a, b) {
for (var i in b) {
var a = a || {};
if (typeof b[i] == "object") {
a[i] = b[i].constructor == Array ? [] : {};
deepCopy(a[i], b[i]);
} else {
a[i] = b[i]
}
}
return a;
}
二者互不影响: