理解原型对象

在Javascript中不管什么时候,仅仅要创建一个新的函数,就会依据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象(这个对象的用途是包括能够有特定类型的全部实例共享的属性和方法)。假设依照字面上的意思来理解。那么原型属性就是通过调用构造函数而创建的那个对象的实例的原型对象。

在默认的情况下,全部的原型对象都会自己主动获得一个constructor(构造函数)属性,这个属性包括一个指向prototype属性所在函数的指针。

例如以下图

function Person(){
}

上图中创建了一个构造函数Person(function Person())。Person函数中有一个prototype的属性指向Person的原型对象,在原型对象中有一个constructor的属性指向了Person函数。全部能够通过new Person()创建对象。



创建了自己定义的构造函数后。其原型对象默认仅仅会取得constructor属性,至于其它的方法。都是从Object继承而来的。

当中上图中Person.prototype .constructor指向Person.而通过这个构造函数,我们能够继续为原型对象加入其它的属性和方法。

例如以下图:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemxfamF5/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

上图的js代码就是

Person.prototype={
name:"Nicholas",
age:23,
sayName:function(){
return this.name;
}
};

当调用构造函数创建一个新实例后。该实例的内部将包括一个指针(内部属性)。指向构造函数的原型对象。

ECMA-262第5版中管这个指针叫[[Prototype]],尽管在脚本中没有标准方式訪问,我们能够借由Chrome在每一个对象上都支持一个属性_proto_(私有属性不可见),这个链接的存在于实例与构造函数的原型对象之间,而不是存在于实例与构造函数之间。

var p1=new Person();





当创建一个新的p2之后依旧会有一个_proto_属性指向Person的原型(Persion.prototype)。换句话说每一个实例与构造函数没有直接的关系。尽管这实例都不包括属性和方法,但我们却能够调用p1.name查找对象属性的个过程来实现。

此时假设通过p2.name设置属性值后会在对象自己的内存空间中存储name的值,当调用sayName()方法的时候在寻找name时,在自己空间中找到之后就不会去原型对象中查找(注意:原型中的值是不会被替换,不过在查找的时候被覆盖)

var p1=new Person();
alert(p1.name);//Nicholas
var p2=new Person();

原型的检測

在全部实现中都无法訪问到[[Prototype]],可是我们能够通过isPrototypeOf()方法来确定对象直接是否存在这样的关系。

从本质上讲,假设[[Prototype]]指向调用isPrototypeOf()方法的对象(Person.prototype)。

ECMAScript5中添加一个新的方法.叫做Object.getPrototypeOf(),这种方法返回[[Prototype]]的值

== 能够检測某个对象的constructor

检測某个属性是否是自己是自己的属性用(不是对象原型中的实现)hasOwnProperty(),能够清楚的知道什么时候訪问的自己的属性。什么时候訪问的是原型属性了。

delete能够用来删除实例属性(自己的属性)

in操作:有两种方式操作in操作符。

单独的使用for-in循环中使用。单独是用时,in

会通过对象可以訪问给的属性的返回值。不管属性存在于实例中还是原型中。

//检查某个对象是否是某个函数的原型
alert(Person.prototype.isPrototypeOf(p1));//true
ECMAScript5中添加一个新的方法.叫做Object.getPrototypeOf(),在全部支持的实现中,这种方法返回[[Prototype]]的值
alert(Object.getPrototypeOf(p1)==Person.prototype);
alert(Object.getPrototypeOf(p1).name);
//alert(p1.constructor==Person);
//alert(p2.hasOwnProperty("name"))
delete p2.name;
//alert("name" in p1)//来自原型
p1.id=12;
// alert("id" in p1);//来自实例
alert(hasPrototypeProperty(p1,"name"))
/**
检查某个属性是否在原型中存在
*/
function hasPrototypeProperty(obj,prop){
return ((!obj.hasOwnProperty(prop))&&(prop in obj));
}

在上面给原型加入的属性中存在着已问题constructor属性不指向Person了。上面写法的本质是全然重写了默认的prototype对象。因此constructor属性也变成了新的对象的constructor属性(指向Object构造函数),不在指向Person函数,虽然instanceof操作还是正确返回结果,可是通过constructor已经无法确定对象的类型了。

   为了避免这个问题但是手动指定constructor

alert(p1 instanceofPersion);alert(p1.constructor==Persion)

原型重写存在的问题

 因为在原型中查找值得过程是一次搜索。我们对原型对象所做的不论什么改动都可以马上从实例上反映出来。即使先创建实例后改动原型也是可以的

var p2=new Person();
Person.prototype.sayHi=function(){
alert(this.name);
}
p2.sayHi();//能够获取值

能够获取值是由于实例与原型之间的松散连接关系,当我们调用p2.saHi()时。首先回去实例中搜索名为sayHi的属性。在没有找到的情况下。会继续搜索原型。由于实例和原型之间仅仅只是是一个指针,而不是副本,因此能够在原型中找到新的sayHi属性并返回保存在哪里的函数。

假设是重写整个原型就不一样了。我们知道调用构造函数是会为实例加入一个指向最初原型的[[Prototype]]指针。把原型改动为另外一个对象就等于切断了构造函数和最初的原型之间的联系。切记:实例中的指针仅指向原型。

而不是构造函数。

function Person(){
} var p1=new Person(); //全部的"范围对象"都继承自这个对象 重写原型对象
Person.prototype.sayHi=function(){
alert(this.name);
}
//全部的"范围对象"都继承自这个对象 重写原型对象
Person.prototype={
constructor:Person,//显示的设置构造函数的反向引用
name:"Nicholas",
age:23,
sayName:function(){
return this.name;
}
}; p1.sayHi();//undefined
alert(p1.sayName());//报错
var p2=new Person();
alert(p2.sayName());//Nichola

重写之前与重写之后如图:

原型存在的问题

原型对象中的属性是被非常多实例共享的,这个共享对于函数是非常合适的。对于原型中基本值得属性是没有问题的可是,假设属性值包括引用类型值就会有一定的问题了。

function Person(){
} Person.prototype={
constructor:Person,//显示的设置构造函数的反向引用
name:"Nicholas",
age:23,
friends:["Shelby","Cunrt"],
sayName:function(){
return this.name;
}
};
var p1=new Person();
var p2=new Person(); p1.friends.push("Jack");
alert(p1.friends);//"Shelby","Cunrt","Jack"
alert(p2.friends);//"Shelby","Cunrt","Jack"
alert(p1.friends==p2.friends);//true

解决这个为题做好的方法例如以下:

function Person(name,age,friends){
this.name=name;
this.age=age;
this.friends=friends;
} Person.prototype={
constructor:Person,//显示的设置构造函数的反向引用
sayName:function(){
return this.name;
}
};
var p1=new Person("Tom",20,"Shelby");
var p2=new Person("Alisa",20,["Cunrt","Jack"]);
alert(p1.friends);//"Shelby"
alert(p2.friends);//"Cunrt","Jack"
alert(p1.friends==p2.friends);//false

第一篇 对Javascript中原型的深入理解的更多相关文章

  1. JavaScript中原型对象的应用!

    JavaScript中原型对象的应用! 扩展内置对象的方法 我以数组对象为例! // 原型对象的应用 扩展内置对象方法! Array.prototype.sum = function() { var ...

  2. 从问题入手,深入了解JavaScript中原型与原型链

    从问题入手,深入了解JavaScript中原型与原型链 前言 开篇之前,我想提出3个问题: 新建一个不添加任何属性的对象为何能调用toString方法? 如何让拥有相同构造函数的不同对象都具备相同的行 ...

  3. 关于JavaScript中prototype机制的理解

    最近几天一直在研究JavaScript中原型的机制,从开始的似懂非懂,到今天终于有所领悟.不敢说彻底理解,但是起码算知道怎么回事了. 为什么一开始似懂非懂 开始了解一遍原型机制后,感觉知其然但不知其所 ...

  4. javascript中原型(prototype)与原型链

    javascript是一门动态语言(动态语言Dynamic Programming Language:动态类型语言,意思就是类型的检查是在运行时做的,也就是常说的“弱类型”语言),没有类的概念,有cl ...

  5. javascript中原型链与instanceof 原理

    instanceof:用来判断实例是否是属于某个对象,这个判断依据是什么呢? 首先,了解一下javascript中的原型继承的基础知识: javascript中的对象都有一个__proto__属性,这 ...

  6. 第一篇、javascript变量和循环

    一.代码存放位置 理论上放在body和head中都可以,但是推荐放在body代码块底部,因为Html代码是从上到下执行,如果Head中的js代码耗时严重,就会导致用户长时间无法看到页面,如果放置在bo ...

  7. 第十篇:javaScript中的JSON总结

    参考网站:json中国,MDN json 一.必知基础    JSON 是JavaScript对象文字符号的一个子集,它可以自如的在JavaScript中使用.看下这个对象: var myJSONOb ...

  8. 对JavaScript中原型及原型链的理解

    什么是原型:  1,我们所创建的每一个函数,解析器都会向该函数对象添加一个属性prototype,这个属性指向一个对象,这个对象就是我们所谓的原型对象 2,如果我们将函数作为普通函数调用时,proto ...

  9. javascript中concat方法深入理解

    最近在恶补js知识的时候,总是会因为js强大的语法而感到震撼.因为以前对前端方面的疏忽,导致了一些理解的错误.因此痛改前非,下定决心,不管做什么事情,都要有专研的精神. 在介绍前,抛出一个问题:如何将 ...

随机推荐

  1. flask-login 学习(1)

    今天的目标,就是学习 flask-login.争取用1天时间,掌握个大概. 第一步:掌握flask-login的大致使用,具体参考了:https://www.centos.bz/2017/09/fla ...

  2. HTTP协议头注射漏洞实例

    HTTP 响应头文件中包含未经验证的数据会引发 cache-poisoning.cross-site scripting.cross-user defacement.page hijacking.co ...

  3. 使用php扩展mcrypt实现AES加密

    AES(Advanced Encryption Standard,高级加密标准)是美国联邦政府采用的一种区块加密标准.这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用.Rijndael是 ...

  4. LoadRunner监控Linux资源

    一.LoadRunner监控Linux资源 (一).准备工作 首先,监视Linux一定要有rstatd这个守护进程,有的Linux版本里也有可能是rpc.rstatd这里只是名字不同而已,功能是一样的 ...

  5. Java多线程编程——生产者-消费者模式(1)

    生产者-消费者模式在生活中非常常见.就拿我们去餐馆吃饭为例.我们会遇到以下两种情况: 1.厨师-客人 如下图所示,生产者.消费者直接进行交互. 生产者生产出产品后,通知消费者:消费者消费后,通知生产者 ...

  6. django配置Ueditor

    1.安装DjangoUeditor pip install DjangoUeditor 2.在Django中安装DjangoUedito app,在INSTALL_APPS里面增加DjangoUedi ...

  7. 【BZOJ 2728】 2728: [HNOI2012]与非 (线性基?)

    2728: [HNOI2012]与非 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 813  Solved: 389 Description Inpu ...

  8. Opencv学习笔记2:图像模糊作用和方法

    一.意义和作用: 图像的模糊处理就是将图片处理的更加模糊,如下图,左侧是原图,右侧是经过处理之后的图片. 从主观意愿上说,我们希望看到清晰的图像,而不是模糊的图像.所以很多时候我们听说还有一种专门进行 ...

  9. luogu 11月月赛 斐波那契数列

    本来想作为水题刷,很快就想出了做法,结果细节实现太差改了好久... 根据题意你会发现其实就是求方程 ax+by=k解的个数. 此时 a=f[i],b=f[i+1],而(x,y)就是你要求的数对. 于是 ...

  10. ARC 058

    所以为啥要写来着........... 链接 T1 直接枚举大于等于$n$的所有数,暴力分解判断即可 复杂度$O(10n \log n)$ #include <cstdio> #inclu ...