Prototype

2016-02-21  本文已影响551人  xiao_A

Prototype是js面向对象中实现多态的核心,或者说是区别于普通面向对象语言如java等的灵魂所在,越是这种玩意,越是坑,因为如果对这些理解不深,反而会被它的一些表面现象所迷惑,导致各种深层bug,不断入坑。
这里对自己之前所做的项目中所用到的此部分内容做一些总结

思考

开篇我想就我之前用JS的一些体会,简单说几个点

JS中的对象

通常来说,javascript中的对象就是一个指向prototype的指针和一个自身的属性列表。javascript创建对象时采用了写时复制的理念。
只有 构造器 才具有prototype属性,原型链继承就是创建一个新的指针,指向构造器的prototype属性。
prototype属性之所以特别,是因为javascript时读取属性时的遍历机制决定的。本质上它就是一个普通的指针。
构造器包括以下对象:

  1. Object
  2. Function
  3. Array
  4. Date
  5. String

Prototype

Prototype是啥

这里强烈推荐参考[关于JS中的constructor与prototype][],这应该是全网写的最直白的,帮助我们小白看懂其中的逻辑
首先,prototype我的理解是一个对象的属性,根据上文,我们知道只有构造器才有prototype属性。
prototype属性又指向了一个prototype对象,注意prototype属性与prototype对象是两个不同的东西,要注意区别。在prototype对象中又有一个constructor属性,这个constructor属性同样指向一个constructor对象,而这个constructor对象恰恰就是这个function函数本身。
看图(本文图均出自[关于JS中的constructor与prototype][]文章,下文不再说明)


prototype和构造器

Sample Code:

function Person(name)
{
   this.name=name;
   this.showMe=function() {
             alert(this.name);
   }
};
var one=new Person('js');
alert(one.prototype)//undefined
alert(typeof Person.prototype);//object
alert(Person.prototype.constructor);//function Person(name) {...};

分析:
其中one是具体的构造器弄出来的对象,所以没有prototype属性。而Function有(Function是构造器),并且prototype中有只想具体构造函数的属性

JS中对象的定义过程

按照《悟透javascript》书中说的,new形式创建对象的过程实际上可以分为三步:
第一步是建立一个新对象(叫A吧);
第二步将该对象(A)内置的原型对象设置为构造函数(就是Person)prototype 属性引用的那个原型对象;
第三步就是将该对象(A)作为this 参数调用构造函数(就是Person),完成成员设置等初始化工作。
其中第二步中出现了一个新名词就是内置的原型对象,注意这个新名词跟prototype对象不是一回事,为了区别我叫它inobj,inobj就指向了函数Person的prototype对象。在person的prototype对象中出现的任何属性或者函数都可以在one对象中直接使用,这个就是javascript中的原型继承了。


对象与Prototype

这样one对象通过内置的原型对象inobj就可以直接访问Person的prototype对象中的任何属性与方法了。这也就解释了上面的代码中为什么one可以访问form函数了。因为prototype对象中有一个constructor属性,那么one也可以直接访问constructor属性。

JS继承(原型链)

继承的实现很简单,只需要把子类的prototype设置为父类的一个对象即可。注意这里说的可是对象哦!
那么通过prototype属性实现继承的原理是什么呢?还是先看图形说明,然后编写代码进行验证。


继承(原型链)

Sample Code:

function Person(name) {
   this.name=name;
   this.showMe=function() {
       alert(this.name);
   }
};
Person.prototype.from=function() {
  alert('I come from prototype.');
}
function SubPerson() {
}
SubPerson.prototype=new Person();
var subOne=new SubPerson();
subOne.from();//I come from prototype.
alert(subOne.constructor);//function Person(name) {...};
alert(SubPerson.prototype.constructor);//function Person(name) {...};

这个所谓的原型链就是从最下方的子对象开始,往自己的原型上溯。找调用的属性或者方法,如果找不到就继续找原型的原型。一直下去。这个比较好理解,和普通的父类回溯是差不多的逻辑。

What's More

至此,prototype的大概应该有所理解了。那么还有几个非常重要的细节,并且是使用最多的特性需要再强调一下,其实已经隐藏在上面的code里了。

  1. 每一个对象(被构造器创造出来的对象)姑且成为myObj,即new+某个function弄出的对象,可以直接访问constructor属性,这玩意指向的就是构造器
    但是同时,这玩意是没有prototype属性的,因为prototype只在构造器里才有。不过我们可以这样找到他的prototype,那就是myObj. constructor. prototype
  2. 函数对象中自身声明的方法和属性与prototype声明的对象有什么差别?
    有下面几个差别:

总结下,结合上文开头所述,prototype是指针,指向的是一个prototype对象。而具体的调用在在具体使用的时候,才去根据原型链一个一个去找的。所以在你update了prototype的属性和方法后,所有继承了这个prototype的对象都能动态的自动继承这些新update的玩意。这个才是JS作为动态的面向对象语言最有价值的玩意

Javascript的方法

JS中有三类方法

a. 类方法
b. 对象方法
c. 原型方法

Sample Code:

function People(name) {
 this.name=name;
 //对象方法
 this.Introduce=function(){
   alert("My name is "+this.name);
  } 
}
//类方法
People.Run=function(){
  alert("I can run");
}
//原型方法
People.prototype.IntroduceChinese=function(){
  alert("我的名字是"+this.name);
}

参考文章
[JS中的prototype][]
[关于JS中的constructor与prototype][]
[javascript必知必会之prototype][]
[JS中的prototype]:http://www.cnblogs.com/yjf512/archive/2011/06/03/2071914.html
[关于JS中的constructor与prototype]:http://blog.csdn.net/niuyongjie/article/details/4810835
[javascript必知必会之prototype]:http://www.cnblogs.com/mindsbook/archive/2009/09/19/javascriptYouMustKnowPrototype.html

上一篇下一篇

猜你喜欢

热点阅读