Javascript的原型总会给人产生一些困惑,无论是经验丰富的专家,还是作者自己也时常表现出对这个概念某些有限的理解,我认为这样的困惑在我们一开始接触原型时就已经产生了,它们常常和new、constructor相关,特别是函数(function)的原型(prototype)属性(property)。事实上,原型是一种非常简单的概念。为了更好的理解它,我们应该首先记住这个原则,那就是忘记我们已经学到的关于构造原型(construtor prototypes)的认识。
 
什么是原型?
 
原型是一个对象,其他对象可以通过它实现属性继承。
 
任何一个对象都可以成为原型么?
 

 
哪些对象有原型
 
所有的对象在默认的情况下都有一个原型,因为原型本身也是对象,所以每个原型自身又有一个原型(只有一种例外,默认的对象原型在原型链的顶端。更多关于原型链的将在后面介绍)
 
好吧,再绕回来,那什么又是对象呢?
 
在javascript中,一个对象就是任何无序键值对的集合,如果它不是一个主数据类型(undefined,null,boolean,number,or string),那它就是一个对象
 
你说每个对象都有一个原型,可是我当我写成({}).prototype 我得到了一个null,你说的不对吧?
 
忘记你已经学到的关于原型属性的一切,它可能就是你对原型困惑的根源所在。一个对象的真正原型是被对象内部的[[Prototype]]属性(property)所持有。ECMA引入了标准对象原型访问器Object.getPrototype(object),到目前为止只有Firefox和chrome实现了此访问器。除了IE,其他的浏览器支持非标准的访问器__proto__,如果这两者都不起作用的,我们需要从对象的构造函数中找到的它原型属性。下面的代码展示了获取对象原型的方法
var a = {};
 
  //Firefox 3.6 and Chrome 5
 
  Object.getPrototypeOf(a); //[object Object] 
 
  //Firefox 3.6, Chrome 5 and Safari 4
 
a.__proto__; //[object Object] 
 
  //all browsers
 
  a.constructor.prototype; //[object Object]
ok,一切都进行的很好,但是false明明是一个主数据类型,可是false.__proto__却返回了一个值
 
当你试图获取一个主数据类型的原型时,它被强制转化成了一个对象
 
//(works in IE too, but only by accident)
 
false .__proto__ === Boolean( false ).__proto__; //true
我想在继承中使用原型,那我该怎么做?
 
如果仅仅只是因为一个实例而使用原型是没有多大意义的,这和直接添加属性到这个实例是一样的,假如我们已经创建了一个实例对象 ,我们想要继承一个已经存在的对象的功能比如说Array,我们可以像下面这样做( 在支持__proto__ 的浏览器中)
//unusual case and does not work in IE
var a = {};
a.__proto__ = Array.prototype;
a.length; //0
———————————————————————————————————–
 译者注:上面这个例子中,首先创建了一个对象a,然后通过a的原型来达到继承Array 这个已经存在的对象的功能
———————————————————————————————————–
 
原型真正魅力体现在多个实例共用一个通用原型的时候。原型对象(注:也就是某个对象的原型所引用的对象)的属性一旦定义,就可以被多个引用它的实例所继承(注:即这些实例对象的原型所指向的就是这个原型对象),这种操作在性能和维护方面其意义是不言自明的
 
这也是构造函数的存在的原因么?
 
是的。构造函数提供了一种方便的跨浏览器机制,这种机制允许在创建实例时为实例提供一个通用的原型
 
在你能够提供一个例子之前,我需要知道constructor.prototype 属性究竟是什么?
 
首先,javascript并没有在构造函数(constructor)和其他函数之间做区分,所以说每个函数都有一个原型属性。反过来,如果不是函数,将不会有这样一个属性。请看下面的代码
 
//function will never be a constructor but it has a prototype property anyway
 
Math.max.prototype; //[object Object]
 
//function intended to be a constructor has a prototype too
 
var A = function (name) {
 
      this .name = name;
 
}
 
  A.prototype; //[object Object]  
 
  //Math is not a function so no prototype property
 
  Math.prototype; //null
现在我们可以下个定义了:函数A的原型属性(prototype property )是一个对象,当这个函数被用作构造函数来创建实例时,该函数的原型属性将被作为原型赋值给所有对象实例(注:即所有实例的原型引用的是函数的原型属性)
———————————————————————————————————-
译者注:以下的代码更详细的说明这一切
 
//创建一个函数b
var b = function(){ var one; }
//使用b创建一个对象实例c
var c = new b();
//查看b 和c的构造函数
b.constructor;   // function Function() { [native code]}
b.constructor==Function.constructor;  //true
c.constructor;  //实例c的构造函数 即b function(){ var one; }
c.constructor==b  //true
//b是一个函数,查看b的原型如下
b.constructor.prototype // function (){}
b.__proto__  //function (){}
 
//b是一个函数,由于javascript没有在构造函数constructor和函数function之间做区分,所以函数像constructor一样,
//有一个原型属性,这和函数的原型(b.__proto__ 或者b.construtor.prototype)是不一样的
b.prototype //[object Object]   函数b的原型属性
 
b.prototype==b.constructor.prototype //fasle
b.prototype==b.__proto__  //false
b.__proto__==b.constructor.prototype //true
 
//c是一个由b创建的对象实例,查看c的原型如下
c.constructor.prototype //[object Object] 这是对象的原型
c.__proto__ //[object Object] 这是对象的原型
 
c.constructor.prototype==b.constructor.prototype;   //false  c的原型和b的原型比较
c.constructor.prototype==b.prototype;   //true c的原型和b的原型属性比较
 
//为函数b的原型属性添加一个属性max
b.prototype.max = 3
//实例c也有了一个属性max
c.max   //3
上面的例子中,对象实例c的原型和函数的b的原型属性是一样的,如果改变b的原型属性,则对象实例c
的原型也会改变
———————————————————————————————————-
理解一个函数的原型属性(function’s prototype property )其实和实际的原型(prototype)没有关系对我们来说至关重要
//(example fails in IE)
 
  var A = function (name) {
 
   this .name = name;
 
}
 
A.prototype == A.__proto__; //false
 
  A.__proto__ == Function.prototype; //true - A's prototype is set to its constructor's prototype property
给个例子撒
 
你可能曾经上百次的像这样使用javascript,现在当你再次看到这样的代码的时候,你或许会有不同的理解。
 
 
 
//Constructor. <em>this</em> is returned as new object and its internal [[prototype]] property will be set to the constructor's default prototype property
var Circle = function (radius) {
     this .radius = radius;
     //next line is implicit, added for illustration only
     //this.__proto__ = Circle.prototype;
  }   
//augment Circle's default prototype property thereby augmenting the prototype of each generated instance
Circle.prototype.area = function () {
     return Math.PI* this .radius* this .radius;
  }  
  //create two instances of a circle and make each leverage the common prototype
var a = new Circle(3), b = new Circle(4);
  a.area().toFixed(2); //28.27
  b.area().toFixed(2); //50.27
棒极了。如果我更改了构造函数的原型,是否意味着已经存在的该构造函数的实例将获得构造函数的最新版本?
 
不一定。如果修改的是原型属性,那么这样的改变将会发生。因为在a实际被创建之后,a.__proto__是一个对A.prototype 的一个引用,。
 
var A = function (name) {
     this .name = name;
  }  
var a = new A( 'alpha' );
a.name; //'alpha'  
  A.prototype.x = 23;  
a.x; //23
——————————————————————————————————
译者注:这个和上例中的一样,实例对象a的原型(a.__proto__)是对函数A的原型属性(A.prototype)的引用,所以如果修改的是A的原型属性,
 
改变将影响由A创建的对象实例a 在下面的例子中,但是对函数A的原型进行了修改,但是并没有反应到A所创建的实例a中
 
var A = function(name)
{
this.name = name;
}
var a = new A(‘alpha’);
a.name; //’alpha’
 
A.__proto__.max = 19880716;
 
a.max   //undefined
 
——————————————————————————————————
 
但是如果我现在替换A的原型属性为一个新的对象,实例对象的原型a.__proto__却仍然引用着原来它被创建时A的原型属性
 
var A = function (name) {
     this .name = name;

  var a = new A( 'alpha' );
a.name; //'alpha'  
  A.prototype = {x:23};   
  a.x; //null
——————————————————————————————————————
译者注:即如果在实例被创建之后,改变了函数的原型属性所指向的对象,也就是改变了创建实例时实例原型所指向的对象
 
但是这并不会影响已经创建的实例的原型。
——————————————————————————————————————-
 
一个默认的原型是什么样子的?
 
var A = function () {};
  A.prototype.constructor == A; //true
  var a = new A();
  a.constructor == A; //true (a's constructor property inherited from it's prototype)
instance of 和原型有什么关系
 
如果a的原型属于A的原型链,表达式a instance of A 值为true。这意味着 我们可以对instance of 耍个诡计让它不在起作用
var A = function () {}  
 
  var a = new A();
 
  a.__proto__ == A.prototype; //true - so instanceof A will return true
 
  a instanceof A; //true;  
 
//mess around with a's prototype
 
  a.__proto__ = Function.prototype;
 
  //a's prototype no longer in same prototype chain as A's prototype property
 
  a instanceof A; //false
还能使用原型做些什么呢?
 
记住我曾经所提到过的每个构造函数都有一个原型属性,它用来为每一个它所创建的实例提供原型。这同样也适用原生态的构造函数Function,String等,扩展这个属性,我们可以达到扩展指定构造函数的所有实例
我曾经在之前的很多文章中使用过这个技巧来演示函数的拓展。在tracer utility 这篇文章中所有的string实例都实现了times这个方法,对字符串本身进行指定数目的复制
String.prototype.times = function (count) {
     return count < 1 ? '' : new Array(count + 1).join( this );
  }
 
"hello!" .times(3); //"hello!hello!hello!";
 
"please..." .times(6); //"please...please...please...please...please...please..."
告诉我继承是怎样通过原型来工作的。什么是原型链?
 
因为每个对象和原型都有一个原型(注:原型也是一个对象),对象的原型指向对象的父,而父的原型又指向父的父,我们把这种通过原型层层连接起来的关系撑为原型链。这条链的末端一般总是默认的对象原型。
 
a.__proto__ = b;
 
  b.__proto__ = c;
 
  c.__proto__ = {}; //default object
 
{}.__proto__.__proto__; //null
原型的继承机制是发生在内部且是隐式的.当想要获得一个对象a的属性foo的值,javascript会在原型链中查找foo的存在,如果找到则返回foo的值,否则undefined被返回。
 
赋值呢?
 
原型的继承is not a player 当属性值被设置成a.foo=’bar’是直接给a的属性foo设置了一个值bar。为了把一个属性添加到原型中,你需要直接指定该原型。
 
以上就是这篇文章所要讲述的。我个人感觉自己对原型概念的理解还是比较深刻的,但我的观点并不能代表一切。如有纰漏和异议,敬请告知。

如何理解JavaScript原型相关推荐

  1. 深入理解javascript原型和闭包(16)——完结

    之前一共用15篇文章,把javascript的原型和闭包. 首先,javascript本来就"不容易学".不是说它有多难,而是学习它的人,往往都是在学会了其他语言之后,又学java ...

  2. 深入理解javascript原型和闭包(17)——补this

    本文对<深入理解javascript原型和闭包(10)--this>一篇进行补充,原文链接:http://www.cnblogs.com/wangfupeng1988/p/3988422. ...

  3. 深入理解javascript原型和闭包(3)——prototype原型

    既typeof之后的另一位老朋友! prototype也是我们的老朋友,即使不了解的人,也应该都听过它的大名.如果它还是您的新朋友,我估计您也是javascript的新朋友. 在咱们的第一节(深入理解 ...

  4. 深入理解javascript原型和闭包(2)——函数和对象的关系

    上文(理解javascript原型和作用域系列(1)--一切都是对象)已经提到,函数就是对象的一种,因为通过instanceof函数可以判断. var fn = function () { }; co ...

  5. 如何理解JavaScript原型链

    如何理解JavaScript原型链 实例对象与原型对象的关系 构造函数.原型对象和实例对象之间的关系 原型链结构图 函数在原型链中的结构 原型链的理解和总结 实例对象与原型对象的关系 构造函数.原型对 ...

  6. 深入理解 JavaScript 原型

    前言 原型,作为前端开发者,或多或少都有听说.你可能一直想了解它,但是由于各种原因还没有了解,现在就跟随我来一起探索它吧.本文将由浅入深,一点一点揭开 JavaScript 原型的神秘面纱.(需要了解 ...

  7. 深入理解javascript原型链

    在javascript中原型和原型链是一个很神奇的东西,对于大多数人也是最难理解的一部分,掌握原型和原型链的本质是javascript进阶的重要一环.今天我分享一下我对javascript原型和原型链 ...

  8. 理解JavaScript原型

    2019独角兽企业重金招聘Python工程师标准>>> Javascript的原型总会给人产生一些困惑,无论是经验丰富的专家,还是作者自己也时常表现出对这个概念某些有限的理解,我认为 ...

  9. 真丶深入理解 JavaScript 原型和原型链(二):原型和原型链

    原文地址: https://www.jeremyjone.com/745/,转载请注明. 上一篇文章已经总结了关于原型的两个属性,那么接下来所有原型和原型链,乃至后面的继承,都与这两个属性有关系. 原 ...

最新文章

  1. ExtJS中xtype 概览
  2. 哈利波特 pdf_干货!哈利波特英文原版pdf免费领,(含音频)词汇量大于新概念!...
  3. aac蓝牙编解码协议_最新的真无线蓝牙耳机选购指南
  4. JavaScript中this指向
  5. Deepin系统手动安装oracle jdk8详细教程
  6. GitLab 小组中的项目访问权限赋予给用户
  7. apache 编译php mysql_apache静/动态编译在apache+php+mysql应用
  8. 树莓派研发笔记三——搭建服务器和实践任务
  9. 梅森旋转产生随机数c语言实现,C++生成随机数的实现代码
  10. 不差钱!华为,给学生开百万年薪
  11. 关于手机系统。。。。
  12. 基于Linux、QT、C++的“别踩白块儿”小游戏
  13. 如何使用纯Servlet做一个单表的CRUD操作
  14. Enhanced ShockBurst (ESB)原文翻译
  15. LeetCode数据库题目1-123
  16. C语言之联合体通用变量类型之妙用
  17. 硅步携手Allegro.ai,搭建强大的深度学习平台
  18. 身高测量仪红外传感测距模块应用方案 WTU201F2 B004 低功耗
  19. hibernate的官方网站
  20. 雷达系统 学习笔记(七)——相控阵雷达2

热门文章

  1. Could not find the main class: org.apache.catalina.startup.Boostrap. Program will exit.
  2. python(十七)
  3. 有关Nodejs的一些插件介绍
  4. 动态规划 4、基础背包问题总结(多重背包与多重背包的转化)
  5. JS的Document属性和方法
  6. java的异常机制面试题(转)
  7. 公有云运维安全常见四大难题及解决方案
  8. 服务器流量异常排查步骤(查看进程的流量)
  9. TextView设置文字包含中英文时自动换行问题的终极解决方案
  10. Hive Error : Java heap space 解决方案