javascript中的每个对象都有一个内置的属性prototype,Javascript中对象的prototype属性的解释是:返回对象类型原型的引用。意思是是prototype属性保存着对另一个JavaScript对象的引用,这个对象作为当前对象的父对象。

A.prototype = new B();

理解prototype不应把它和继承混淆。A的prototype为B的一个实例,可以理解A将B中的方法和属性全部克隆了一遍。A能使用B的方法和属性。这里强调的是克隆而不是继承。可以出现这种情况:A的prototype是B的实例,同时B的prototype也是A的实例。

继续看下面的分析:

私有变量和函数

在函数内部定义的变量和函数,如果不对外提供接口,外部是无法访问到的,也就是该函数的私有的变量和函数。


这样在函数对象Box外部无法访问变量color和fn,他们就变成私有的了:
var obj = new Box();

    alert(obj.color);//弹出 undefined

    alert(obj.fn);//同上

静态变量和函数

当定义一个函数后通过点号 “.”为其添加的属性和函数,通过对象本身仍然可以访问得到,但是其实例却访问不到,这样的变量和函数分别被称为静态变量和静态函数。

实例变量和函数

在面向对象编程中除了一些库函数我们还是希望在对象定义的时候同时定义一些属性和方法,实例化后可以访问,js也能做到这样

为实例变量和方法添加新的方法和属性

在box1中修改了a和fn,而在box2中没有改变,由于数组和函数都是对象,是引用类型,这就说明box1中的属性和方法与box2中的属性与方法虽然同名但却不是一个引用,而是对Box对象定义的属性和方法的一个复制。

这个对属性来说没有什么问题,但是对于方法来说问题就很大了,因为方法都是在做完全一样的功能,但是却又两份复制,如果一个函数对象有上千和实例方法,那么它的每个实例都要保持一份上千个方法的复制,这显然是不科学的,这可肿么办呢,prototype应运而生。

基本概念

我们创建的每个函数都有一个prototype属性,这个属性是一个指针,指向一个对象,这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。那么,prototype就是通过调用构造函数而创建的那个对象实例的原型对象。

使用原型的好处是可以让对象实例共享它所包含的属性和方法。也就是说,不必在构造函数中添加定义对象信息,而是可以直接将这些信息添加到原型中。使用构造函数的主要问题就是每个方法都要在每个实例中创建一遍。

在JavaScript中,一共有两种类型的值,原始值和对象值。每个对象都有一个内部属性 prototype ,我们通常称之为原型。原型的值可以是一个对象,也可以是null。如果它的值是一个对象,则这个对象也一定有自己的原型。这样就形成了一条线性的链,我们称之为原型链。

含义

函数可以用来作为构造函数来使用。另外只有函数才有prototype属性并且可以访问到,但是对象实例不具有该属性,只有一个内部的不可访问的__proto__属性。__proto__是对象中一个指向相关原型的神秘链接。按照标准,__proto__是不对外公开的,也就是说是个私有属性,但是Firefox的引擎将他暴露了出来成为了一个共有的属性,我们可以对外访问和设置。

当我们调用Bro.run()方法时,由于Bro中没有这个方法,所以,他就会去他的__proto__中去找,也就是Browser.prototype,所以最终执行了该run()方法。(在这里,函数首字母大写的都代表构造函数,以用来区分普通函数)

当调用构造函数创建一个实例的时候,实例内部将包含一个内部指针(__proto__)指向构造函数的prototype,这个连接存在于实例和构造函数的prototype之间,而不是实例与构造函数之间。


Person的实例person1中包含了name属性,同时自动生成一个__proto__属性,该属性指向Person的prototype,可以访问到prototype内定义的printName方法,大概就是这个样子的:

每个JavaScript函数都有prototype属性,这个属性引用了一个对象,这个对象就是原型对象。原型对象初始化的时候是空的,我们可以在里面自定义任何属性和方法,这些方法和属性都将被该构造函数所创建的对象继承。

那么,现在问题来了。构造函数、实例和原型对象三者之间有什么关系呢?

构造函数、实例和原型对象的区别

实例就是通过构造函数创建的。实例一创造出来就具有constructor属性(指向构造函数)和__proto__属性(指向原型对象),

构造函数中有一个prototype属性,这个属性是一个指针,指向它的原型对象。

原型对象内部也有一个指针(constructor属性)指向构造函数:Person.prototype.constructor = Person;

实例可以访问原型对象上定义的属性和方法。

在这里person1和person2就是实例,prototype是他们的原型对象。

再举个栗子:

可以从程序运行结果看出,构造函数的prototype上定义的方法确实可以通过对象直接调用到,而且代码是共享的。(可以试一下将Animal.prototype.behavior 中的prototype属性去掉,看看还能不能运行。)在这里,prototype属性指向Animal对象。

数组对象实例

再看个数组对象的实例。当我们创建出array1这个对象的时候,array1实际在Javascript引擎中的对象模型如下:

var array1 = [1,2,3];

array1对象具有一个length属性值为3,但是我们可以通过如下的方法来为array1增加元素:

array1.push(4);

push这个方法来自于array1的__proto__成员指向对象的一个方法(Array.prototye.push())。正是因为所有的数组对象(通过[]来创建的)都包含有一个指向同一个具有push,reverse等方法对象(Array.prototype)的__proto__成员,才使得这些数组对象可以使用push,reverse等方法。

函数对象实例

function Base() {  

    this.id = "base" 

}  

var obj = new Base();

这样代码的结果是什么,我们在Javascript引擎中看到的对象模型是:

new操作符具体干了什么呢?其实很简单,就干了三件事情。

var obj  = {};  

obj.__proto__ = Base.prototype;  

Base.call(obj);

原型链

原型链:当从一个对象那里调取属性或方法时,如果该对象自身不存在这样的属性或方法,就会去自己关联的prototype对象那里寻找,如果prototype没有,就会去prototype关联的前辈prototype那里寻找,如果再没有则继续查找Prototype.Prototype引用的对象,依次类推,直到Prototype.….Prototype为undefined(Object的Prototype就是undefined)从而形成了所谓的“原型链”。

这里,用构造器Shape()新建了一个实体,然后用它去覆盖该对象的原型。

原型继承

原型继承:在原型链的末端,就是Object构造函数prototype属性指向的那个原型对象。这个原型对象是所有对象的祖先,这个老祖宗实现了诸如toString等所有对象天生就该具有的方法。其他内置构造函数,如Function,Boolean,String,Date和RegExp等的prototype都是从这个老祖宗传承下来的,但他们各自又定义了自身的属性和方法,从而他们的子孙就表现出各自宗族的那些特征。

ECMAScript中,实现继承的方法就是依靠原型链实现的。

原型链的问题:原型链虽然很强大,可以用它来实现继承,但它也存在一些问题。其中最主要的问题来自包含引用类型的值原型。包含引用类型的原型属性会被所有实例共享;而这也正是为什么要在构造函数中,而不是在原型对象中定义属性的原因。在通过原型来实现继承时,原型实际上回变成另一个类型的实例。于是,原先的实例属性也就变成了原型的属性。

在创建子类型的实例时,不能向超类型的构造函数中传递参数。实际上,应该说是没有办法在不影响所有对象实例的情况下,给超类型的构造函数传递参数。再加上刚刚讨论的由于原型中包含引用类型值所带来的问题,实践中很少会单独使用原型链。

再举个栗子:

看下面一个原型链例子:

从上面例子中,test对象从Hi.prototype和Year.prototype中继承下来;因此他能访问Year的原型方法method,同时他能访问实例属性value

__ptoto__属性

__ptoto__属性(IE浏览器不支持)是实例指向原型对象的一个指针,它的作用就是指向构造函数的原型属性constructor,通过这两个属性,就可以访问原型里的属性和方法了。

Javascript中的对象实例本质上是由一系列的属性组成的,在这些属性中,有一个内部的不可见的特殊属性——__proto__,该属性的值指向该对象实例的原型,一个对象实例只拥有一个唯一的原型。

  

__proto__属性和prototype属性的区别

prototype是function对象中专有的属性。
__proto__是普通对象的隐式属性,在new的时候,会指向prototype所指的对象;
__ptoto__实际上是某个实体对象的属性,而prototype则是属于构造函数的属性。__ptoto__只能在学习或调试的环境下使用。

原型模式的执行流程

1.先查找构造函数实例里的属性或方法,如果有,就立即返回。
2.如果构造函数的实例没有,就去它的原型对象里找,如果有,就立即返回

原型对象的

构造函数的

综上,整理一下:

工厂模式

 function createObject(name,age){

    var obj = new Object();

    obj.name = name;

    obj.age = age;

    return obj;

}

工厂模式解决了实例化对象大量重复的问题,但还有一个问题,那就是根本无法搞清楚他们到底是哪个对象的实例。
使用构造函数的方法,既解决了重复实例化的问题,又解决了对象识别的问题。

使用构造函数的方法和工厂模式的不同之处在于:

1.构造函数方法没有显示的创建对象(new Object());
2.直接将属性和方法赋值给this对象
3.没有return 语句

当使用了构造函数,并且new 构造函数(),那么就在后台执行了new Object();
函数体内的this代表了new Object()出来的对象

1.判断属性是在构造函数的实例里,还是在原型里,可以使用`hasOwnProperty()`函数
2.字面量创建的方式使用constructor属性不会指向实例,而会指向Object,构造函数创建的方式则相反
为什么指向Object?因为Box.prototype = {};这种写法其实就是创建了一个新对象。
而每创建一个函数,就会同时创建它的prototype,这个对象也会自动获取constructor属性
3.如果是实例方法,不同的实例化,他们的方法地址是不一样的,是唯一的
4.如果是原型方法,那么他们的地址的共享的

JavaScript中原型和原型链详解的更多相关文章

  1. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  2. HTML5数字输入仅接受整数的实现代码

    这篇文章主要介绍了HTML5数字输入仅接受整数的实现代码,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  3. amaze ui 的使用详细教程

    这篇文章主要介绍了amaze ui 的使用详细教程,本文通过多种方法给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  4. html5简介_动力节点Java学院整理

    这篇文章主要介绍了html5简介,用于指定构建网页的元素,这些元素中的大多数都用于描述网页内容,有兴趣的可以了解一下

  5. ios 8 Homescreen webapp,关闭和打开iPad停止javascript

    我有一个适用于iPad的全屏HTML5网络应用程序,并且刚刚安装了IOS8来试用它,它一切正常,直到你关闭并重新启动iPad.一旦web应用程序重新启动javascript就会停止并加载新页面不会重新启动它.在iPad上的Safari中打开同一页面时,关闭和打开iPad会继续按预期工作.其他人注意到了这个或想出了一个解决方案吗?解决方法这似乎是我在iOS8.1.1更新中解决的.

  6. iOS 6 javascript与object.defineProperty的间歇性问题

    当访问使用较新的Object.defineProperty语法定义属性的对象的属性时,有没有其他人注意到新iOS6javascript引擎中的间歇性错误/问题?https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperty我正在看到javascript失败的情况,说

  7. ios – 如何使用JSExport导出内部类的方法

    解决方法似乎没有办法将内部类函数导出到javascript.我将内部类移出并创建了独立的类,它起作用了.

  8. 静音iOS推送通知与React Native应用程序在后台

    我有一个ReactNative应用程序,我试图获得一个发送到JavaScript处理程序的静默iOS推送通知.我看到的行为是AppDelegate中的didReceiveRemoteNotification函数被调用,但是我的JavaScript中的处理程序不会被调用,除非应用程序在前台,或者最近才被关闭.我很困惑的事情显然是应用程序正在被唤醒,并且它的didReceiveRemoteNotifi

  9. ios – 内存泄漏与UIWebView和Javascript

    清楚地包含一个Javascript文件到我的HTML是使UIWebView泄漏内存.当我重复使用相同的UIWebView对象时,或者每当我有内容实例化一个新的漏洞时,会出现泄漏的事实,导致我认为必须有一些JavaScript文件被loadHTMLString处理,导致泄漏.有人知道如何解决这个问题吗?

  10. iOS应用程序的UI自动化测试如何与乐器和Javascript

    从WWDC2010视频会议中了解iOS应用程序的自动化UI测试,但没有实践.从代码项目project,我们可以有一个例子.这个问题在这里听到有涉及这个的人.任何限制?解决方法我建议从AlexWollmer开始使用thisblogpost.他创建了一个非常有用的JavaScript库:tuneup_jswithtest()函数,它允许测试分离和有用的帮助者以及为自动化仪器编写测试的断言.

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部