这是一个翻译。原文地址http://javascriptissexy.com/javascript-prototype-in-plain-detailed-language/#

原型(prototype)是每一个JavaScript开发者必须理解的基本概念,本文的目标是通俗而又具体地解释JavaScript的原型。假设你读完这篇博文以后还是不理解JavaScript的原型,请将你的问题写在以下的评论里,我本人会回答全部的问题。

为了理解JavaScript中的原型,你必须理解JavaScript的对象。假设你对对象还不熟悉,你须要阅读我的文章JavaScript Objects in Detail译文:具体解释JavaScript对象)。

并且你要知道属性就是函数中定义的变量。

在JavaScript中有两个互相之间有关联的原型的概念:

1.首先。每个JavaScript函数有一个原型属性,当你须要实现继承的时候你就给这个原型属性附加属性和方法。注意这个原型属性是不能够枚举的:它在for/in循环中是不可获取的。可是FireFox和大多数版本号的Safari和Chrome浏览器有一个__proto__“伪”属性(一种选择方式)同意你訪问对象原型的属性。你可能从来没实用过这个_proto__伪属性,但你得知道它的存在而且它是在某些浏览器中訪问对象的原型属性的一种简单的方法。

对象原型主要用于继承:你为对象的原型属性添加方法和属性,使这些原型和属性存在于该函数的实例。

下面是一个简单的使用原型属性继承的样例(后面还有很多其它关于继承的内容):

function PrintStuff (myDocuments) {
this.documents = myDocuments;
} //我们为PrintStuff的原型属性添加方法print (),这种话其它实例(对象)能够继承这种方法
PrintStuff.prototype.print = function () {
console.log(this.documents);
} //用构造函数PrintStuff ()创建一个新的对象,由此让这个新对象继承PrintStuff 的属性和方法。
var newObj = new PrintStuff ("I am a new Object and I can print."); // newObj继承了函数PrintStuff全部的属性和方法,包含方法print。如今newObj能够直接调用print,即使我们从来没有为它定义过方法print()。 newObj.print (); //I am a new Object and I can print.

2. 第二个关于JavaScript原型的概念是原型特性。把原型特性想成该对象的一个性质;这个性质表明了该对象的“父母”。简而言之:对象的原型特性能够看成是对象的“父母”--该对象获得它属性的地方。对象特性经常被称为原型对象,而且它是在你创建对象时就自己主动建立的。对此的解释是:每个对象从某个其它的对象那里继承属性,而这里的“某个其它的对象”就是该对象的原型特性或者“父母”。(你能够把原型特性想象成血缘关系或者父母)。

在上面样例的代码中,newObj的原型是PrintStuff.prototype。

注意:全部的对象都有特性,就和对象属性有自己的特性一样。对象特性是原型、类和扩展特性。这些是我们在第二个样例中要讨论的原型特性。

另一点须要注意, “伪”属性__proto__包括一个对象的原型对象(被该对象继承方法和属性的父对象)。

重要提示
构造函数
在我们继续往下阅读之前,让我们来简单的考查一下构造函数。构造函数是一个用来初始化新对象的函数。并且使用新的keyword来调用构造函数。 比如: function Account () {
}
//这是利用构造函数Account来创建对象userAccount
var userAccount = new Account (); 并且。全部继承自还有一个对象的对象。也继承了那个对象的构造函数属性。 而这个构造函数属性就是一个保存或者指向该对象的构造函数的属性(和不论什么变量一样)。 //本例的构造函数是Object ()
var myObj = new Object ();
//而假设你之后想要知道myObj的构造函数:
console.log(myObj.constructor); // Object() // 还有一个样例: Account ()是构造函数
var userAccount = new Account ();
//查看对象userAccount的构造函数
console.log(userAccount.constructor); // Account()

用new Object()或对象式创建的对象的原型特性

全部用对象式或者构造函数Object创建的对象都继承自Object.prototype。因此Object.prototype是全部用Object()或者{}所创建的对象的原型特性(或原型对象)。Object.prototype本身没有从其它不论什么对象那里继承不论什么的方法或者属性。

// 对象userAccount 继承自Object 而且因此它的原型特性就是Object.prototype.
var userAccount = new Object (); // 这个声明用了对象式来创造对象userAccount;该对象userAccount继承自Object;因此,就和上面的对象userAccount一样。它的原型特性是Object.prototype。
var userAccount = {name: “Mike”}

用构造函数所创建的对象的原型特性

用新keyword以及不论什么一种非Object()的构造函数所创建的对象,从该构造函数中获得它们的构造函数。

比如:

function Account () {

}
var userAccount = new Account () // 用构造函数Account ()初始化userAccount而且因此它的原型特性(原型对象)就是 Account.prototype。 相似的,不论什么数组,比方var myArray = new Array (),从Array.prototype获得原型而且继承Array.prototype的属性。

所以,当对象被创建时有两种通用的方式来建立对象的原型特性:

1.假设对象是使用对象式(var newObj = {})创建的。那么它从Object.prototype继承属性,而且我们说它的原型对象(或者原型特性)是Object.prototype。

2.假设对象是使用构造函数,比方 new Object ()或者new Fruit ()或者new Array ()或者 new Anything ()创建的,那么它继承自构造函数 (Object (), Fruit (), Array (), or Anything ())。比如,用一个函数,比方Fruit ()。每次我们创建一个新的水果的实例(var aFruit = new Fruit ()),那么该新实例的原型就来自于构造函数Fruit,也就是
Fruit.prototype。

不论什么用new Array ()所创建的对象都会将Array.prototype作为它的原型。

不论什么用构造函数Object(Obj (), 比方 var anObj = new Object() )创建的对象继承自Object.prototype。

另一点你须要知道的。在ECMAScript 5中,你能够用一个同意你指定新对象的原型的方法Object.create()来创建对象。我们会在兴许的文章中学习ECMAScript 5。

原型为什么重要以及何时使用原型?

在JavaScript中原型有两种重要的用途,就像前文中提到的那样:

1.原型属性:基于原型的继承

在JavaScript中原型之所以重要是由于JavaScript没有(大多数面向对象的语言全部的)经典的基于类的继承。因此JavaScript全部的继承是通过原型属性来实现的。JavaScript有一套基于原型继承的机制。继承是一种能让对象(或者是其他语言中的类)继承其他对象(或类)的属性和方法的编程规范。在JavaScript中,通过原型来实现继承。比如,你能够创建一个Fruit函数(也就是对象。由于全部JavaScript中的函数都是对象)而且给这个Fruit的原型属性加入属性和方法,那么全部Fruit函数的实例会继承Fruit全部的属性和方法。

JavaScript中的继承演示样例:

function Plant () {
this.country = "Mexico";
this.isOrganic = true;
} //把方法showNameAndColor加入到Plant原型属性
Plant.prototype.showNameAndColor = function () {
console.log("I am a " + this.name + " and my color is " + this.color);
} // 把方法amIOrganic加入到Plant原型属性
Plant.prototype.amIOrganic = function () {
if (this.isOrganic)
console.log("I am organic, Baby!");
} function Fruit (fruitName, fruitColor) {
this.name = fruitName;
this.color = fruitColor;
} //将Fruit的原型设为Plant的构造函数,因此继承了Plant.prototype所有的方法和属性
Fruit.prototype = new Plant (); // 用构造函数Fruit创建一个新的aBanana
var aBanana = new Fruit ("Banana", "Yellow"); // 这里aBanana用了来自aBanana对象原型Fruit.prototype的name属性:
console.log(aBanana.name); // Banana //用来自Fruit对象原型Plant.prototype的方法showNameAndColor。 该aBanana对象继承了来自函数Plant和Fruit的所有属性和方法
console.log(aBanana.showNameAndColor()); // I am a Banana and my color is yellow.

注意到,虽然方法showNameAndColor是在对象Plant.prototype的原型链上定义的,可是此方法还是被对象aBanana所继承。

实际上,不论什么使用构造函数Fruit ()的对象。都将继承Fruit.prototype所有的属性和方法以及来自Fruit的原型Plant.prototype的所有的属性和方法。

这就是JavaScript中实现继承的主要方式以及原型链在这一过程中所扮演的整合角色。

很多其它深入的关于JavaScript中的面向对象编程的内容。请阅读Nicholas Zakas的 Principles of Object-Oriented Programming in JavaScript(这本书仅仅要14.99美元)

2.原型特性:获取对象的属性

原型对于获取对象的方法和属性也是非常重要的。原型特性(或原型对象)是那些可继承的属性的“父母”对象,这些可继承的属性原本就是为这些“父母”对象定义的。这就有点类似于你能够从你的父亲--他是你的“原型父母”。那里继承姓。假设我们想知道你的姓是从哪里来的,我们会先看看是否是你自己给自己取了这个姓;假设不是。我们会继续查看是否你是从你的父亲那里继承了这个姓。

假设这个姓不是你父亲的。那么我们会继续查看你父亲的父亲的姓(你父亲的原型父亲)。

与之类似的,假设你想要获取一个对象的原型。你将直接从该对象的属性開始寻找。

假设JS执行时不能再那里找到该属性。那么它会去该对象的原型--该对象得到属性的地方,去查看这个属性。

假设在对象的原型中没有发现该属性。那么对于该属性的搜寻会转移到对象的原型的原型(对象的父亲的父亲--爷爷)那里去。就这样一直持续到没有原型为止(没有很多其它的曾祖父;没有很多其它有遗传来的血缘关系)。

这事实上就是原型链:从对象的原型到对象原型的原型不断向上的一条链。而且JavaScript就用这条原型链来搜寻对象的属性和方法。

假设某个属性在它的整条原型链上的不论什么一个对象的原型中均不存在,那么这个属性就是不存在而且会返回undefined。

这样的原型链机制本质上和我们上面讨论的基于原型的继承是一样的概念,仅仅是在这里我们更注重于JavaScript怎样通过对象原型获取对象的属性和方法。

这个样例演示了对象的原型对象的原型链:

var myFriends = {name: "Pete"};

//为了找到以下的属性name。搜寻会直接从对象myFriends開始。而且会立马找到属性name。由于我们为对象myFriends定义了属性name。

这个能够被想像成有一条链接的原型链。
console.log(myFriends.name); //在这个样例中。将会从对象myFriends開始搜寻方法toString (),可是由于我们从来没有为对象myFriends创建过方法toString,编译器会接着去myFriends的原型(被myFriends继承属性的那个对象)搜寻。 //而且由于全部用对象式创建的对象都继承自Object.prototype,方法toString将在 Object.prototype中被发现--关于全部继承自Object.prototype的属性。请看以下的重要提示
myFriends.toString ();

重要提示
全部对象都会继承的Object.prototype的属性
在JavaScript中全部对象的属性和方法继承自Object.prototype。这些继承来的属性和方法有构造函数,hasOwnProperty (), isPrototypeOf (), propertyIsEnumerable (), toLocaleString (), toString (), and valueOf ()。ECMAScript 5中还新增了四种訪问Object.prototype的方法。 以下是还有一个原型链的样例:
function People () {
this.superstar = "Michael Jackson";
}
// 为People原型定义属性"athlete"以便"athlete" 能够被全部使用构造函数People () 的对象所訪问。
People.prototype.athlete = "Tiger Woods"; var famousPerson = new People ();
famousPerson.superstar = "Steve Jobs"; //对于superstar的搜寻将首先查看对象famousPerson是否有属性superstar。而由于就是在那里定义的这个属性,这就是须要用到的属性。由于我们已经为对象famousPerson反复定义链famousPerson的属性superstar。所以对于superstar的搜寻就不会在原型链上继续上升。 console.log (famousPerson.superstar); // Steve Jobs // 注意在ECMAScript 5中你能够将属性设置为仅仅读。这种话你就不能像我们刚才那样反复定义该属性。 //这里展示了来自famousPerson原型(People.prototype)的属性。由于属性athlete没有为对象famousPerson本身所定义。
console.log (famousPerson.athlete); // Tiger Woods //在这个样例中,在原型链上向上搜寻而且在Object.prototype中找到了方法toString,这种方法来自对象Fruit的继承--像我们前面提到的那样。全部的对象终于继承自Object.prototype
console.log (famousPerson.toString()); // [object Object]

全部已经建立的构造函数 (Array (), Number (), String (), etc.)都是由构造函数Object所创建的。因此它们的原型是Object.prototype。

能够回过头再做做2月7号的那篇关于JavaScript原型的測试。

附加信息

许多其他有关JavaScript内容对象。阅读David Flanagan书面 JavaScript: The Definitive Guide (第六版。2011五月) 本书的第六章。

通俗易懂的语言描述JavaScript原型的更多相关文章

  1. 1.js基础(以通俗易懂的语言解释JavaScript)

    1.JavaScript组成: ECMAScript: 解释器.翻译 -->几乎没有兼容问题 DOM: Document Object Model -->有一些操作不兼容 BOM: Bro ...

  2. 3.定时器的使用(以通俗易懂的语言解释JavaScript)

    1.定时器的作用: 开启定时器:setInterval -->间隔型 setTimeout -->延时型 区别:setInterval会一直执行,应用如微博间隔一段时间不断请求后台数据,看 ...

  3. 2.js深入(以通俗易懂的语言解释JavaScript)

    1.函数返回值: 即函数的执行结果 可以没有return 经验:一个函数应该只返回一种类型的值 2.函数传参 可变参(不定参):arguments ——>(参数的个数可变,参数数组) 例子1:求 ...

  4. 大白话通俗易懂的讲解javascript原型与原型链(__proto__、prototype、constructor的区别)

    javascript原型和原型链是js中的重点也是难点,理论上来说应该是属于面向对象编程的基础知识,那么我们今天为什么要来讲这个呢?(因为我也忘了,最近看资料才揭开面纱……  哈哈哈) 好了,直接进入 ...

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

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

  6. 从mixin到new和prototype:Javascript原型机制详解

    从mixin到new和prototype:Javascript原型机制详解   这是一篇markdown格式的文章,更好的阅读体验请访问我的github,移动端请访问我的博客 继承是为了实现方法的复用 ...

  7. 再谈javascript原型继承

    Javascript原型继承是一个被说烂掉了的话题,但是自己对于这个问题一直没有彻底理解,今天花了点时间又看了一遍<Javascript模式>中关于原型实现继承的几种方法,下面来一一说明下 ...

  8. [转]Javascript原型继承

    真正意义上来说Javascript并不是一门面向对象的语言,没有提供传统的继承方式,但是它提供了一种原型继承的方式,利用自身提供的原型属性来实现继承.Javascript原型继承是一个被说烂掉了的话题 ...

  9. JavaScript原型与继承的秘密

    在GitHub上看到的关于JavaScript原型与继承的讲解,感觉很有用,为方便以后阅读,copy到自己的随笔中. 原文地址:https://github.com/dreamapplehappy/b ...

随机推荐

  1. OpenStack路: OpenStack建筑设计指南 - 概要(摘录和翻译)

    OpenStack它是在云技术领先的黄金工艺,作为一个组织,使各类企业,具有较大的灵活性和速度被发现,向市场推出自助服务云计算和基础架构即服务(IaaS)积.然,为了能够真正享受到这些好处,云计算必须 ...

  2. Java知多少(4)J2SE、J2EE、J2ME的区别

    原文:Java知多少(4)J2SE.J2EE.J2ME的区别 1998年12月,SUN公司发布了Java 1.2,开始使用“Java 2” 这一名称,目前我们已经很少使用1.2之前的版本,所以通常所说 ...

  3. Ecshop他们主动双语版切换来推断个人的计划

    个人思路是基于浏览器的语言来推断自己主动,假设中国的浏览器,对使用中国模板.将英语模板.于.英国的模板差值称为不同的产品类别.文章分类,的模板可设置为相同的固定的文本language,所以你不会有打造 ...

  4. Spring FrameWork4(MVC + IOC)高速入门实例

    使用Maven创建project并配置依赖项 首先创建一个Maven Project: 然后选择创建Maven 的webapp实例,当然也能够通过命令行方式创建Maven webapp的项目再转化并导 ...

  5. [Cocos2d-x]在Cocos2d-x 3.x如何通过版本号WebSocket连接server数据的传输

    WebSocket 首先新建一个空的目录,通过npm安装nodejs-websocket: npm install nodejs-websocket 新建app.js文件: var ws = requ ...

  6. SDUT oj 3005 打怪升级(内存搜索)

    当比赛一直纠缠骑2如何做一个非常大的数量,数组不开啊...后来他们发现自己很傻啊,该数不超过最大10什么,这个上限就是力量100什么.. .. 其它的就是记忆化搜索啊,还有就是加一点力量的瓶子当时就要 ...

  7. CSDN帐号被盗尚未?

    总是早上登录CSDN,STIL.总是让C货币. 但是今天除了发C币,还提示我有2篇博文被删除了,打开看了看,原来不是我发的. watermark/2/text/aHR0cDovL2Jsb2cuY3Nk ...

  8. Java多播通讯框架 JGroups(转)

    JGroups是一个可靠的群组通讯Java工具包.它基于IP组播(IP multicast),但在可靠性,组成员管理上对它作了扩展. JGroups的可靠性体现在: 1,对所有接收者的消息的无丢失传输 ...

  9. HDU 1596 find the safest road (最短路)

    find the safest road Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Ot ...

  10. COC+RTS+MOR游戏开发 一(游戏特色分析,和实践)

    本场比赛的临时名称 游戏特色(-):COC风格 ,塔防养成类游戏.          一款史诗般的战斗策略游戏.玩家须要建立村庄,成千上万的网友训练玩家的军队和战斗. 游戏中玩家须要不断的提高军队的作 ...