理解原型对象

在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. python基础(8)--迭代器、生成器、装饰器

    1.迭代器 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退.另外,迭代器的一大优 ...

  2. Hive2.x 版本的安装及配置 以及要注意的事项

    博主学习Hadoop学习到Hive,一开始跟着资料去安装Hive 1.x一点问题也没有,方便快捷啊,但是看了一下官方文档,上面好像说Hive 2.0修复了很多bug,那么我想,我还是用Hive2.0好 ...

  3. vue框架muse-ui官网文档主题错误毕竟【01】

    在使用了element-ui后,总觉得不尽兴,再学一个响应式的muse-ui发现是个小众框架,但是我很喜欢. 指出官网文档里的主题使用描述错误. 首先,在vue-cli里安装raw-loader:np ...

  4. java总结(二)(运算符)

    算数和赋值运算符 1.变量类型溢出时候,会直接取反:出现x>x+1 2.知道a++和++a 3.知道a/0错误 a/0.0无穷大 字符串 1.知道栈区.堆区和方法区 2.知道new String ...

  5. shell-命令行参数(转)

    命令行参数 (转自http://c.biancheng.net/cpp/view/2739.html) 特殊变量列表 变量 含义 $0 当前脚本的文件名 $n 传递给脚本或函数的参数.n 是一个数字, ...

  6. linux 使用

    1. 请问怎样从文件里读内容到变量 var=(echo $(<aa)) ====>var=($(<aa)) $ var=($(<aa)) $ echo ${var[*]} /h ...

  7. Java反射机制Reflection

    Java反射机制 1 .class文件 2 Class类 3 Class类与反射机制 4 Java反射机制的类库支持及简介 5 反射机制的定义与应用 6 反射机制Demo Java反射机制demo(一 ...

  8. HDU 5692 Snacks

    题目链接[http://acm.hdu.edu.cn/showproblem.php?pid=5692] 题意:一棵树,每个节点有权值,有两种操作:1.修改某个点的权值,2.求以x根的子树中的节点到根 ...

  9. POJ2955【区间DP】

    题目链接[http://poj.org/problem?id=2955] 题意:[].()的匹配问题,问一个[]()串中匹配的字符数,匹配方式为[X],(X),X为一个串,问一个长度为N(N<= ...

  10. 【二项式定理】【DFS】UVALive - 7639 - Extreme XOR Sum

    题意:一个序列,q次询问,每次问你某个指定区间内的EXtreme XOR值. 一个长度为l的区间的EXtreme XOR值被定义为,从左到右,将每相邻的两个数XOR起来,产生l-1个新的值,……如此循 ...