Web/06-前端基础/05-原型链总结.md
2018-03-07 09:46:13 +08:00

5.0 KiB
Raw Blame History

前言

面向对象的三大特性

  • 封装

  • 继承

  • 多态

原型链的知识

原型链是面向对象的基础,是非常重要的部分。有以下几种知识:

  • 创建对象有几种方法

  • 原型、构造函数、实例、原型链

  • instanceof的原理

  • new 运算符

创建对象有几种方法

方式一:字面量

    var obj11 = {name: 'smyh'};
    var obj12 = new Object(name: `smyh`); //内置的构造函数

上面的两种写法,效果是一样的。因为,第一种写法,obj11会指向Object

  • 第一种写法是:字面量的方式。

  • 第二种写法是:内置的构造函数

方式二:通过构造函数

    var M = function (name) {
        this.name = name;
    }
    var obj3 = new M('smyhvae');

方法三Object.create

    var p = {name:'smyhvae'};
    var obj3 = Object.create(p);  //此方法创建的对象,是用原型链连接的

第三种方法很少有人能说出来。这种方式里obj3是实例p是obj3的原型name是p原型里的属性构造函数是Objecet

20180306_1633.png

原型、构造函数、实例,以及原型链

20180306_1538.png

PS任何一个函数如果在前面加了new那就是构造函数。

原型、构造函数、实例三者之间的关系

20180306_2107.png

  • 1、构造函数通过 new 生成实例

  • 2、构造函数也是函数构造函数的prototype指向原型。(所有的函数有prototype属性,但实例没有 prototype属性)

  • 3、原型对象中有 constructor指向该原型的构造函数。

上面的三行,代码演示:

    var Foo = function (name) {
        this.name = name;
    }

    var fn = new Foo('smyhvae');

上面的代码中,Foo.prototype.constructor === Foo的结果是true

20180306_2120.png

  • 4、实例的__proto__指向原型。也就是说,Foo.__proto__ === M.prototype

声明:所有的引用类型(数组、对象、函数)都有__proto__这个属性。

Foo.__proto__ === Function.prototype的结果为true说明Foo这个普通的函数是Function构造函数的一个实例。

原型链

原型链的基本原理:任何一个实例,通过原型链,找到它上面的原型,该原型对象中的方法和属性,可以被所有的原型实例共享。

Object是原型链的顶端。

原型可以起到继承的作用。原型里的方法都可以被不同的实例共享:

    //给Foo的原型添加 say 函数
    Foo.prototype.say = function () {
        console.log('');
    }

原型链的关键:在访问一个实例的时候,如果实例本身没找到此方法或属性,就往原型上找。如果还是找不到,继续往上一级的原型上找。

instanceof的原理

20180306_2209.png

instanceof作用:用于判断引用类型属于哪个构造函数

instanceof原理:判断实例对象的__proto__属性,和构造函数的prototype属性,是否为同一个引用(是否指向同一个地址)。

注意1:虽然说,实例是由构造函数 new 出来的,但是实例的__proto__属性引用的是构造函数的prototype。也就是说,实例的__proto__属性与构造函数本身无关。

注意2:在原型链上,原型的上面可能还会有原型,以此类推往上走,继续找__proto__属性。这条链上如果能找到, instanceof 的返回结果也是 true。

比如说:

  • foo instance of Foo的结果为true因为foo.__proto__ === M.prototype为true。

  • foo instance of Objecet的结果也为true,因为Foo.prototype.__proto__ === Object.prototype为true。

但我们不能轻易的说:foo 一定是 由Object创建的实例。这句话是错误的。我们来看下一个问题就明白了。

分析一个问题

**问题:**已知A继承了BB继承了C。怎么判断 a 是A直接生成的实例还是B直接生成的实例呢还是C直接生成的实例呢

分析:这就要用到原型的constructor属性了。

  • foo.__proto__.constructor === M的结果为true但是 foo.__proto__.constructor === Object的结果为false。

所以,用 consturctor判断就比用 instanceof判断更为严谨。

new 运算符

new 运算符的原理如下:

1创建一个新的空对象,此空对象继承自Foo.prototype,也就是继承自构造函数的原型。

2构造函数被执行。执行的时候传入相应的参数如果没有参数就不用传同时 this 指向这个新实例。

3如果构造函数返回的是“对象”那么这个对象会取代整个 new 出来的结果。如果构造函数没有创建对象,那么 new 出来的结果为步骤1创建的对象。

类继承和原型继承的区别