理解原型对象

在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. Caffe学习系列(8):solver,train_val.prototxt,deploy.prototxt及其配置

    solver是caffe的核心. net: "examples/mnist/lenet_train_test.prototxt" test_iter: 100 test_inter ...

  2. Mysql锁的类型与简析

    数据库锁设计的初衷是处理并发问题.作为多用户共享的资源,当出现并发访问的时候,数据库需要合理地控制资源的访问规则.而锁就是用来实现这些访问规则的重要数据结构. 根据加锁的范围,MySQL 里面的锁大致 ...

  3. PHP 标准AES加密算法类

    分享一个标准PHP的AES加密算法类,其中mcrypt_get_block_size('rijndael-128', 'ecb');,如果在不明白原理的情况下比较容易搞错,可以通过mcrypt_lis ...

  4. ArrayList to Array Conversion in Java

    ArrayList to Array Conversion in Java Following methods can be used for converting ArrayList to Arra ...

  5. SQL Join简单介绍

    前沿 Join是关系型数据库系统的重要操作之一,SQL Server中包含的常用Join:内联接.外联接和交叉联接等. 如果我们想在两个或以上的表获取其中从一个表中的行与另一个表中的行匹配的数据,这时 ...

  6. linux 把ls -R格式化成树状结构

    谁能写脚本把linux中的ls -R命令的结果格式化成树状结构? 最好是shell脚本!欢迎讨论! 参与讨论有可能意外获取iPhone6哦~~

  7. 洛谷P3273 [SCOI2011] 棘手的操作 [左偏树]

    题目传送门 棘手的操作 题目描述 有N个节点,标号从1到N,这N个节点一开始相互不连通.第i个节点的初始权值为a[i],接下来有如下一些操作: U x y: 加一条边,连接第x个节点和第y个节点 A1 ...

  8. Python数据类型-集合(set)

    1.创建集合 集合的创建不同于前两种数据结构. 集合通过set(iterable)方法创建,参数iterable为可迭代对象. 示例代码: s1 = set('好好学习天天想上') # 将字符串分解为 ...

  9. oracle date 看时间

    SELECT to_char(DATE_TIME,'yyyy-MM-dd HH24:mi:ss') FROM AUDIT_EVENT;

  10. 【BZOJ 2460】线性基

    2460: [BeiJing2011]元素 Description 相传,在远古时期,位于西方大陆的 Magic Land 上,人们已经掌握了用魔法矿石炼制法杖的技术.那时人们就认识到,一个法杖的法力 ...