对原型与原型链的理解

这部分是我长久以来习惯于直接忽略的部分,可是后面在面试和实习的过程当中发现这部分知识是很是有用的!因此我花了很久时间看书、参考博客、敲代码,结合本身的理解将这些内容总结以下~javascript

最开始想要直观的理解请直接参考阮一峰老师博客关于继承的讲解:http://www.ruanyifeng.com/blog/2011/06/designing_ideas_of_inheritance_mechanism_in_javascript.htmlhtml

 

原型对象

javascript语言是一种面向对象的语言,它没有"子类"和"父类"的概念,里面全部的数据类型都是对象,如何将这些对象联系起来呢?java

Brendan Eich在考虑设计继承机制的时候,参考了C++和JAVA使用new命令,经过调用类的构造函数生成实例的方式,将new命令引入javascript。面试

C++的写法是:闭包

  ClassName *object = new ClassName(param);ide

Java的写法是:函数

  Person person = new Person();this

可是,javascript里面没有“类”这个概念,那么,Brendan Eich决定直接在new后面跟一个构造函数,来生成实例。idea

构造函数是什么?构造函数与其余函数惟一的区别在于调用方式不一样。任何函数只要经过new来调用就能够做为构造函数,它是用来建立特定类型的对象。spa

下面定义一个构造函数Female:

1 function Female(name){
2     this.name = name;
3     this.sex = 'female';  
4 }

经过new命令来生成一个person实例:

var person1 = new Female("Summer")

这里,构造函数Female就是实例对象person1的原型!!!Female里的this关键字就指的是person1这个对象!

 

new出来的person1对象此时已经和Female再无联系了!也就是说每个new出来的实例都有本身的属性和方法的副本,是独立的的!修改其中一个不会影响另外一个!

var person1 = new Female("Summer");
var person2 = new Female("Lily");

person2.sex = 'male';

console.log(person1.sex)      // female
console.log(person2.sex)      // male

可是,咱们但愿构造函数中的sex属性是一个共有属性,那么此时用这样的方法,每一个实例中都有一个相同的sex属性,会形成资源极大的浪费!

 那么原型对象就即将登场了!Brendan Eich决定给每个构造函数都设置一个prototype属性,这个属性就指向原型对象。其实原型对象就只是个普通对象,里面存放着全部实例对象须要共享的属性和方法!因此,咱们把须要共享的放到原型对象里,把那些不须要共享的属性和方法存在在构造函数里!

那么上面的代码可改写以下:

        function Person(name,age){
            this.name = name;
        }
        Person.prototype.sex = 'female';

        var person1 = new Person("Summer");
        var person2 = new Person("Lily");
        
        console.log(person1.sex)      // female
        console.log(person2.sex)      // female

        Person.prototype.sex = 'male';

        console.log(person1.sex)      // male
        console.log(person2.sex)      // male

能够看出,修改prototype属性会影响它的全部实例的sex的值!!

实例一旦建立出来就会自动引用prototype对象的属性和方法!因此实例对象的属性和方法通常分为两种:一种是自身的,一种是引用自prototype的。

具体实现是这样的:

      每当代码读取某个对象的某个属性的时候,都会执行一次搜索。首先从对象实例自己开始,若是在实例中找到了该属性,则返回该属性的值,若是没有找到,则顺着原型链指针向上,到原型对象中去找,若是若是找到就返回该属性值。

这里要提一点,若是为对象实例添加了一个属性与原型中同名,则该属性会屏蔽掉原型中的同名属性,不会去修改它!使用delete能够删除实例中的属性~(提到delete那要插一句~delete只能删除对象下的属性,不能删除变量和参数!)

 原型链

事实上,js里彻底依靠"原型链"(prototype chain)模式来实现继承。

上面说完原型对象。下面要扒一扒__proto__、prototype、constructor

__proto__:事实上就是原型链指针!!

prototype:上面说到这个是指向原型对象的

constructor:每个原型对象都包含一个指向构造函数的指针,就是constructor

继承实现方式:

 为了实现继承,__proto__会指向上一层的原型对象,而上一层的结构依然相似,那么就利用__proto__一直指向Object的原型对象上!Object.prototype.__proto__ = null;表示到达最顶端。如此造成了原型链继承。

下面有个图解很是经典,我本身也手画了一遍去理解,真的很是有效~

大体总结一下就是:

Object是做为众多new出来的实例的基类   function Object(){ [ native code ] }

Function是做为众多function出来的函数的基类    function Function(){ [ native code ] }

 

构造函数的__proto__(包括Function.prototype和Object.prototype)都指向Function.prototype

原型对象的__proto__都指向Object.prototype

Object.prototype.__proto__指向null

 

 

 

今儿老爹生日~下午给老爹作cake~晚上继续总结js相关的面试题和闭包~

相关文章
相关标签/搜索