转自:http://www.cnblogs.com/starof/p/4190404.html

在javaScript创建对象一文中提到过:用构造函数创建对象存在一个问题即同一构造函数的不同实例的相同方法是不一样的,所以我们用原型把构造函数中公共的属性和方法提取出来进行封装,达到让所有实例共享的目的。

接下来进一步介绍javaScript原型。

一、javaScript原型机制

1、函数与原型的关系

js中创建一个函数,就会自动创建一个prototype属性,这个属性指向函数的原型对象,并且原型对象会自动获得一个constructor(构造函数)属性,指向该函数。

举例:以前面的原型模式创建对象为例说明

<script type="text/javascript">
function Person(){

}
Person.prototype.name="lxy";
Person.prototype.age=22;
Person.prototype.job="Software Engineer";
Person.prototype.sayName=function(){
alert(this.name);
}

var lxy=new Person();
lxy.sayName();
var personA=new Person();
personA.sayName();
alert(lxy.sayName()==personA.sayName());//true
</script>

  1. <script type="text/javascript">
  2. function Person(){
  3.  
  4. }
  5. Person.prototype.name="lxy";
  6. Person.prototype.age=22;
  7. Person.prototype.job="Software Engineer";
  8. Person.prototype.sayName=function(){
  9. alert(this.name);
  10. }
  11.  
  12. var lxy=new Person();
  13. lxy.sayName();
  14. var personA=new Person();
  15. personA.sayName();
  16. alert(lxy.sayName()==personA.sayName());//true
  17. </script>

Person对象和Person对象的原型之间的关系如下图1。简单一句话就是:Person.prototype.constructor指向Person。

图1函数、实例与原型的关系(图来着JS高程)

2、实例与原型的关系

通过构造函数创建一个实例,该实例内部将包含一个属性(指针),指向构造函数的原型对象。

举例:Person构造函数的实例Person1和Person2的[[Prototype]]属性都指向Person的原型。如图1所示。

Note:[[Prototype]]连接是存在于实例和构造函数的原型之间,而不是存在实例与构造函数之间。

关于这个指针,ECMA-262中叫[[Prototype]],没有标准的方式访问[[Prototype]],但Firefox、Safari和Chrome在每个对象上都支持一个属性__protp__,而在其他实现中,这个属性对脚本不可见。

3、原型链

实例有自己的属性和方法,而原型封装了所有实例共享的属性和方法,那这种共享是通过什么方式实现的呢?答案是原型链。

当要访问实例的属性时,解析器会执行一次搜索。首先从实例对象开始,如果在实例中找到了这个属性,则返回该属性的值;重点是如果没有找到的话,则继续搜索[[Prototype]]指针指向的原型对象,在原型对象中查找该属性,如果找到,则返回该属性的值。所以通过这种方式多个实例就能共享保存在原型中的属性和方法。这也是js的原型链。

Note:理解了原型链,很自然就能明白几个问题。

a、给实例添加一个与原型中同名的属性,就会将其屏蔽。因为搜索原型链时在实例中就能找到然后就返回了,根本到不了原型。

b、可以通过实例爬原型链访问原型中的值,但却不能通过实例重写原型中的值。同理。

c、原型的动态性,在原型上新增属性或方法能立即从实例反应出来。

二、原型相关的方法介绍

1、isPrototypeOf()方法

虽然实例的[[Prototype]]属性无法访问的,我们可以通过isPrototypeOf()方法来确认原型和实例之间的关系。这个方法呢是站在原型的角度来检测原型是不是某个实例的原型。A.isPrototypeOf(B),如果A的B的原型返回true,否则返回false。

举例:因为Person的两个实例lxy和personA内部都有一个[[Prototype]]属性指向Person.prototype。所以isPrototypeOf方法会返回true。

  1. <script type="text/javascript">
  2. function Person(){
  3.  
  4. }
  5. Person.prototype.name="lxy";
  6. Person.prototype.age=22;
  7. Person.prototype.job="Software Engineer";
  8. Person.prototype.sayName=function(){
  9. alert(this.name);
  10. }
  11.  
  12. var lxy=new Person();
  13. var personA=new Person();
  14. console.log(Person.prototype.isPrototypeOf(lxy)); //true
  15. console.log(Person.prototype.isPrototypeOf(personA)); //true
  16. </script>

2、Object.getPrototypeOf()方法

这个方法是ECMAScript 5中新增的,返回实例的[[Prototype]]值。

这个方法是非常有用的,因为它是在Object上实现的。所以把任何实例扔给Object,它都能获得实例的原型。

举例

  1. <script type="text/javascript">
  2. function Person(){
  3.  
  4. }
  5. Person.prototype.name="lxy";
  6. Person.prototype.age=22;
  7. Person.prototype.job="Software Engineer";
  8. Person.prototype.sayName=function(){
  9. alert(this.name);
  10. }
  11.  
  12. var lxy=new Person();
  13. console.log(Object.getPrototypeOf(lxy));
  14. console.log(Object.getPrototypeOf(lxy)==Person.prototype); //true
  15. console.log(Object.getPrototypeOf(lxy).age);//22
  16. </script>

结果:

3、hasOwnPrototype()方法

这个方法用于检测某个属性是否真正存在于实例中。是返回ture,否则返回false。

就像我们自己有一些资源和技能,但是也可以从爹妈那里得到一些资源和技能,比如看起来你有套别墅,但是你要知道哪些是你真正属于你自己的,哪些是爹妈给你的。

举例:比如我一出生父母就给我个名字lxy,这时候我用hasOwnPrototype()方法检测这个"name"属性是不真是我的,就会返回false。

后来我自己改了个名字starof,再用hasOwnPrototype()方法检测,这时就会返回true。

再后来我不想用这个名字了,我就把它delete掉了,用回了我父母给的名字。这时候再用hasOwnPrototype()方法检测这个"name"属性是不是我自己的,就会返回false。

这个一波三折的故事代码如下:

  1. <script type="text/javascript">
  2. function Person(){
  3.  
  4. }
  5. Person.prototype.name="lxy";
  6.  
  7. var lxy=new Person();
  8. console.log(lxy.name);
  9. console.log(lxy.hasOwnProperty("name")); //false
  10. lxy.name="starof";//通过重写屏蔽原型属性name,所以这个name就变成了实例属性
  11. console.log(lxy.name);
  12. console.log(lxy.hasOwnProperty("name")); //true
  13. delete lxy.name;
  14. console.log(lxy.name);
  15. console.log(lxy.hasOwnProperty("name")); //false
  16. </script>

4、in操作符,for-in循环,Object的keys()和getOwnPrototypeNames()

in操作符在通过对象能够访问属性时返回true,无论该属性是实例属性还是原型属性。

for-in循环,返回所有能够通过对象访问的,可枚举的属性。即包括实例属性也包括原型属性。

屏蔽了原型中不可枚举的属性的实例属性也会在for-in循环中返回,因为根据规定,所有开发人员定义的属性都是可枚举的——只有在IE8及更早版本中例外。

Object.keys()方法,取得对象上所有可枚举的实例属性。该方法接收一个实例作为参数,返回一个包含所有可枚举属性的字符串数组。

Object.getOwnPrototypeNames()方法,获得所有实例属性,无论它是否可枚举。

<script type="text/javascript">
function Person(){

}
Person.prototype.name="lxy";
Person.prototype.age=22;
Person.prototype.job="Software Engineer";
Person.prototype.sayName=function(){
alert(this.name);
}

var lxy=new Person();
//in
console.log("name" in lxy);//in实例可访问的属性
//for-in
for(var prop in lxy){
console.log(prop);
}//for-in列出所有可访问的,可枚举的属性
//Object.keys
var keys=Object.keys(Person.prototype);
console.log(keys);//Person的原型的所有可枚举属性
var keys=Object.keys(lxy);
console.log(keys);//lxy现在没有实例属性,所以keys为空
lxy.name="lxy";
var keys=Object.keys(lxy);
console.log(keys);
//Object.getOwnPrototypeNames
console.log(Object.getOwnPropertyNames(lxy));//得到所有实例属性
</script>

三、原型语法

第一种:每添加一个属性和方法,都直接在原型上加。

  1. <script type="text/javascript">
  2. function Person(){
  3. }
  4. Person.prototype.name="lxy";
  5. Person.prototype.age=22;
  6. Person.prototype.job="Software Engineer";
  7. Person.prototype.sayName=function(){
  8. alert(this.name);
  9. }
  10.  
  11. var lxy=new Person();
  12. </script>

第二种:对象字面量的方法

  1. <script>
  2. function Person(){
  3. }
  4. Person.prototype={
  5. name:"lxy",
  6. age: 22,
  7. job:"Software Engineer",
  8. sayName:function(){
  9. alert(this.name);
  10. }
  11. };
  12. var lxy=new Person();
  13. </script>

第二种语法比较简单,少写几行代码,但是有一点要注意,字面量形式,完全重写了prototype属性,所以constructor不再指向Person,而是Object了。

<script>
function Person(){
}
Person.prototype={
name:"lxy",
age: 22,
job:"Software Engineer",
sayName:function(){
alert(this.name);
}
};
var lxy=new Person();

console.log(lxy.constructor==Person);//false
console.log(lxy.constructor==Object);//true

</script>

  1. <script>
  2. function Person(){
  3. }
  4. Person.prototype={
  5. name:"lxy",
  6. age: 22,
  7. job:"Software Engineer",
  8. sayName:function(){
  9. alert(this.name);
  10. }
  11. };
  12. var lxy=new Person();
  13.  
  14. console.log(lxy.constructor==Person);//false
  15. console.log(lxy.constructor==Object);//true
  16.  
  17. </script>

如果constructor很重要,可手动设置为Person,如下。

  1. <script>
  2. function Person(){
  3. }
  4. Person.prototype={
  5. constructor:Person,
  6. name:"lxy",
  7. age: 22,
  8. job:"Software Engineer",
  9. sayName:function(){
  10. alert(this.name);
  11. }
  12. };
  13. var lxy=new Person();
  14.  
  15. console.log(lxy.constructor==Person);//true
  16. console.log(lxy.constructor==Object);//false
  17. </script>

但是这样写会导致constructor的[[Enumerable]]特性被置为true。因为开发人员定义的属性都是可枚举的。

如果是兼容ECMAScript5的JS引擎可使用Object.definePrototype。

<script>
function Person(){
}
Person.prototype={
name:"lxy",
age: 22,
job:"Software Engineer",
sayName:function(){
alert(this.name);
}
};
//重设构造函数,只适用于ECMAScript5兼容的浏览器
Object.defineProperty(Person.prototype,"constructor",{
enumerable:false,
value:Person
})

var lxy=new Person();

console.log(lxy.constructor==Person);//true
console.log(lxy.constructor==Object);//false
</script>

  1. <script>
  2. function Person(){
  3. }
  4. Person.prototype={
  5. name:"lxy",
  6. age: 22,
  7. job:"Software Engineer",
  8. sayName:function(){
  9. alert(this.name);
  10. }
  11. };
  12. //重设构造函数,只适用于ECMAScript5兼容的浏览器
  13. Object.defineProperty(Person.prototype,"constructor",{
  14. enumerable:false,
  15. value:Person
  16. })
  17.  
  18. var lxy=new Person();
  19.  
  20. console.log(lxy.constructor==Person);//true
  21. console.log(lxy.constructor==Object);//false
  22. </script>

javascript原型Prototype【转】的更多相关文章

  1. javascript原型Prototype

    在javaScript创建对象一文中提到过:用构造函数创建对象存在一个问题即同一构造函数的不同实例的相同方法是不一样的,所以我们用原型把构造函数中公共的属性和方法提取出来进行封装,达到让所有实例共享的 ...

  2. javascript原型prototype浅识

    C++,java是基于类的语言,主要通过类来实现继承. javascript是基于原型的语言,通过原型来实现继承. 什么是原型?每种物质,都可以追根溯源,原型就是对象的根源.继承就是追根溯源. jav ...

  3. javascript原型prototype的一个你不一定知道的理解

    原型和原型链的故事 相关文章: 为什么原型继承很重要 先来看看一段小代码用以引入要讲的小故事. function Foo() {}; var f1 = new Foo(); Foo.prototype ...

  4. javascript 原型(prototype 、__proto__、函数、对象)

    一.类型 1.JavaScript中分为值类型(string/boolean/null/number/undefind).引用类型(数组.对象.函数): 2.数组.函数.对象都是对象: 对象是由函数创 ...

  5. JavaScript 原型 prototype 使用经验

    初始化一个父类,并添加方法 1function Foo(){}2Foo.prototype.sayName = function(){3    return '初始原型';4}56var foo1 = ...

  6. 深入理解javascript原型和闭包(3)——prototype原型

    既typeof之后的另一位老朋友! prototype也是我们的老朋友,即使不了解的人,也应该都听过它的大名.如果它还是您的新朋友,我估计您也是javascript的新朋友. 在咱们的第一节(深入理解 ...

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

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

  8. javascript进阶-原型prototype

    一.javascript原型认识 很多编程语言都有类的概念,我们可以拿原型和类进行比较,看看它们之间的区别以及相同点在哪里. 1.类:类是一个具体事物的抽象所以类是一个抽象的东西,在面向对象中类可以用 ...

  9. 悟透Javascript之 原型prototype

    构造函数的Prototype上定义的方法确实可以通过对象直接调用,而且代码是共享的.我表示我不懂.太难理解了,艹.在Javascript中,prototype不但能让对象共享自己的财富,而且proto ...

随机推荐

  1. Android三种播放视频的方式

    在Android中,我们有三种方式来实现视频的播放: 1.使用其自带的播放器.指定Action为ACTION_VIEW,Data为Uri,Type为其MIME类型. 2.使用VideoView来播放. ...

  2. 无法安装 DotNetCore.1.0.0-VS2015Tools.Preview2解决方法

    安装 DotNetCore.1.0.0-VS2015Tools.Preview2,已经安装vs2015update3,还是提示检测到 Visual Studio 2015 Update 3没有完全安装 ...

  3. S2总结笔记

    第一章:深入.NET框架 1..NET FrameWork两大组件是什么? 解析:.NET 框架类库(FCL:FrameWork Class Library)和公共语言运行时(CLR:common l ...

  4. 配置Tomcat使用Redis作为session管理

    1. 在 tomcat/lib 中增加以下jar包 commons-pool2-.jar jedis-.jar tomcat-redis-session-manager-.jar 2. 修改tomca ...

  5. 通用权限管理系统多语言开发接口 - java,php 调用接口程序,多业务子系统集成

    1:公司里有多个业务系统,需要进行统一重构,有PHP的.有Java的.有.NET的,甚至还有delphi的. 2:公司里有多个数据库系统,有mysql的.有sqlserver的.还有oracel的,甚 ...

  6. 想请问下PDF双面打印时(打印机自动双面打印)为什么反面那页的内容是倒过来的,应该怎么设置?

    用foxit reader 打印pdf 直接设置为双面打印并且一张2页打印,发现正反面刚好倒着来的,其实说的正反面倒着是从左右翻的角度来讲的,如果上下翻会发现刚好是这个顺序的,这个是要在双面打印设置里 ...

  7. express:webpack dev-server中如何将对后端的http请求转到https的后端服务器中?

    在上一篇文章(Webpack系列:在Webpack+Vue开发中如何调用tomcat的后端服务器的接口?)我们介绍了如何将对于webpack-dev-server的数据请求转发到后端服务器上,这在大部 ...

  8. SQL基础之数据库

    1.基础概念 首先要强调一点,就是我们的数据库是由数据库系统来管理的,我们登入数据库并在其上进行操作时最终均要通过数据库系统来完成.可以理解成在数据库上进行操作的是客户端,数据库系统是服务端.一个数据 ...

  9. WPF 让子元素动起来!

    在没有接触Blend之前,自己整出了一个MultiTouchHelper,这东西是做什么的呢?就是利用附加属性让元素可以多点触控. 然后某一天发现Blend里面有一个Behavior的东西,我去,原来 ...

  10. UTF-8和Unicode

    What's the difference between unicode and utf8? up vote 103 down vote favorite 49 Is it true that un ...