原型链的理解

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了原型链的理解相关的知识,希望对你有一定的参考价值。

### 原型链的理解

#### 概念

+ 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)
```

以上是关于原型链的理解的主要内容,如果未能解决你的问题,请参考以下文章

原型链的理解

原型和原型链的理解

前端基本知识:JS的原始链的理解

面向对象(2 )构造函数 原型 原型链的理解

JS中原型链的理解

javascript 原型及原型链的初步理解