### 原型链的理解
#### 概念
+ javascript每一个对象**包括原型对象**都有一个内置的`proto`属性指向创建他的函数对象的原型对象,即`prototype`属性
#### 作用
+ 实现对象的继承
### 理解
1.函数对象
+ 在javascript中,函数就是对象
2.原型对象
+ 当定义一个函数对象的时候,会包含一个预定的属性,`prototype`,这就属性称之为原型对象
3.\__proto__
+ javascript 在创建对象的时候,都会有一个\_proto\_的内置属性,用于指向创建它的函数对象的`prototype`。原型对象也有\_proto\_ 属性。因此在不断的指向中,形成了原型链。
4.new
+ 当使用new关键字去调用构造函数就相当于执行啦
5.constructor
+ 原型对象prototype上都有个预定义的constructor属性,用来引用它的函数对象。这是一种循环引用
?
### 继承
+ **构造函数绑定**
> 使用call或apply方法,将父对象的构造函数绑定在子对象上,即在子对象构造函数中加一行:
```javascript
function test(name,height) {
this.name = name
this.height= height
};
function trys(age){
this.age = age
test.apply(this,["张三","180cm"])
//apply(this,argument)第一个参数为改变this指向,第二个参数为一个伪数组每一项对应 调用apply的函数的形参。
//call(this,name,height) 第一个参数为this,后面参数为调用call的函数的形参。
}
let person = new trys;
person.age = "18"
console.log(person)
```
+ prototype模式
```javascript
function test(name,height) {
this.name = name
this.height= height
this.do=function(hobby){
console.log("我是"+this.name+"我今年"+this.age+"岁"+"身高"+this.height+"我喜欢"+hobby)
}
};
function trys(age){
this.age = age
}
trys.prototype =new test
trys.prototype.constructor = trys;
// trys.prototype =new test 将trys的constructor 属性指向了test,每一个实例对象也会有一个constructor属性默认指向prototype的constructor 属性,person.constructor==test
所以需要将trys的constructor属性重新指回trys
let person = new trys;
person.name = "张三"
person.age = 18
person.height = 180
person.do("打羽毛球")
console.log(person)
```
![](http://p0zfk1qh0.bkt.clouddn.com/markdown001.png)
+ 直接继承prototype
> 是对第二种方法的改进。由于person对象中,不变的属性都可以直接写入person.prototype。所以,我们也可以让man()跳过 person(),直接继承person.prototype。
```javascript
function person (){
}
person.prototype.skill = "开车"
function man(){
this.hobby = "泡妞"
}
man.prototype = person.prototype;
man.prototype.constructor = man;
let xiaoming = new man ;
console.log(xiaoming.skill);
```
+ 利用空对象作为中介
> 用第三种方法会改变person的constructor 的指向 所以有了这种方法 定义一个空的
> 对象作为中介
```javascript
function person (){
}
person.prototype.skill = "开车"
function man(){
this.hobby = "泡妞"
}
function F (){
}
F.prototype =person.prototype
man.prototype = new F()
man.prototype.constructor = man;
let xiaoming = new man ;
```
> 我们将上面的继承封装
```javascript
function extend(Child, Parent) {
var F = function(){};
F.prototype = Parent.prototype;
Child.prototype = new F();
Child.prototype.constructor = Child;
}
```
+ 拷贝继承
>把父对象的所有属性和方法,拷贝进子对象
``` javascript
function extend2(Child, Parent) {
var p = Parent.prototype;
var c = Child.prototype;
for (var i in p) {
c[i] = p[i];
}
c.uber = p;
}
```
+ 非构造函数继承
```javascript
let person = {
skill:"行走"
}
let xiaomming = {
age:"18"
}
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
let xiaoming = object(person)
console.log(xiaoming.skill) //行走
```
+ 浅拷贝
***这样的拷贝有一个问题。那就是,如果父对象的属性等于数组或另一个对象,那么实际上,子对象获得的只是一个内存地址,而不是真正拷贝,因此存在父对象被篡改的可能。***
```javascript
let person = {
skill:"行走"
}
let xiaomming = {
age:"18"
}
function extendCopy(p) {
var c = {};
for (var i in p) {
c[i] = p[i]; //遍历p对象,将p对象的每一个属性 都赋值给c对象的每一项
}
return c;
}
let xiaoming = extendCopy(person);
console.log(xiaoming.skill)//行走
```
+ 深拷贝
>"深拷贝",就是能够实现真正意义上的数组和对象的拷贝。只要递归调用"浅拷贝"就行了。
``` javascript
let person = {
skill:"行走"
}
let xiaomming = {
age:"18"
}
function deepCopy(p, c) {
var c = c || {};
for (var i in p) {
if (typeof p[i] === ‘object‘) {
c[i] = (p[i].constructor === Array) ? [] : {};
deepCopy(p[i], c[i]);
} else {
c[i] = p[i];
}
}
return c;
}
var xiaoming = deepCopy(person)
console.log(xiaoming.skill)
```