以下内容来自《JavaScript高级程序设计》第三版

  我们创建的每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。使用原型对象的好处是可以让所有对象实例共享它所包含的属性和方法。

function Person(){
}
Person.prototype.name='lisi';
Person.prototype.age=23;
Person.prototype.job='Software engineer';
Person.prototype.sayName=function(){
alert(this.name);
}
var person1 = new Person();
alert(person1.name);//lisi
var person2 = new Person();
alert(person2.name);//lisi
alert(person1.sayName==person2.sayName);//true

  1、理解原型对象

  只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象。在默认情况下,所有原型对象都会自动获得一个constructor(构造函数)属性,这个属性包括一个指向prototype属性所在函数的指针。就像前面例子,Person.prototype.constructor指向Person。通过这个构造函数,我们还可以继续为原型对象添加其他属性和方法。

  创建了自定义的构造函数之后,其原型对象默认只会取得constructor属性;至于其他方法,则都是从Object继承而来的。当调用构造函数创建一个新实例后,该实例的内部将包含一个指针(内部属性),指向构造函数的原型对象。

  虽然在所有访问中都无法访问[[Prototype]],但可以通过isPrototypeOf()方法来确定对象之间是否存在这种关系。从本质上讲,只要[[Prototype]]指向调用isPrototypeOf()方法的对象(Person.prototype),那么这个方法就返回true。

        alert(Person.prototype.isPrototypeOf(person1));//true
alert(Person.prototype.isPrototypeOf(person2));//true

  ECMAScript5增加了一个新方法,叫Object.getPrototypeOf(),在所有支持的实现中,这个方法返回[[Prototype]]的值。

    alert(Object.getPrototypeOf(person1)==Person.prototype);//true

  每当代码读取某个对象的某个属性时,都会执行一次搜索,目标是具有给定名字的属性。搜索首先从对象实例本身开始。如果在实例中找到具有给定名字的属性,则返回该属性的值;如果没找到,则继续搜索指针执行的原型对象,在原型对象中查找具有指定名字的属性。如果在原型对象中找到了该属性,则返回该属性的值。也就是说,当我们调用person1.sayName()方法的时候,会先后执行两次搜索。首先,会搜索实例person1的sayNane方法,没有继续搜索person1原型的sayName方法。

  虽然可以通过实例访问保存在原型中的值,但却不能通过对象实例重写原型中的值。如果我们在实例中添加了一个属性,该属性与实例原型中的一个属性同名,那我们就在实例中创建该属性,该属性会屏蔽原型中的属性。

        function Person(){
}
Person.prototype.name='lisi';
Person.prototype.age=23;
Person.prototype.job='Software engineer';
Person.prototype.sayName=function(){
alert(this.name);
}
var person1 = new Person();
alert(person1.name);//lisi
var person2 = new Person();
person2.name='zhangsan';
alert(person2.name);//zhangsan

  即使将实例属性设置为null,也只会在实例中设置这个属性,而不会恢复其指向的原型的链接。不过,使用delete操作符可以完全删除实例属性,从而让我们能够重新访问原型中的属性。

        var person1 = new Person();
alert(person1.name);//lisi
var person2 = new Person();
person2.name=null;
alert(person2.name);//null
delete person2.name;
alert(person2.name);//lisi

  使用hasOwnProperty()方法可以检测一个属性是存在实例中还是原型中。这个方法(不要忘了是从Object继承来的)只在给定属性存在与对象实例中时返回true。

        function Person(){
}
Person.prototype.name='lisi';
Person.prototype.age=23;
Person.prototype.job='Software engineer';
Person.prototype.sayName=function(){
alert(this.name);
}
var person1 = new Person();
alert(person1.hasOwnProperty('name'));//false
person1.name = 'wangwu';
alert(person1.name);//wangwu
alert(person1.hasOwnProperty('name'));//true var person2 = new Person();
alert(person2.name);//lisi
alert(person2.hasOwnProperty('name'));//false
delete person1.name;
alert(person1.name);//lisi
alert(person1.hasOwnProperty('name'));//false

  2、原型与in操作符

  有两种方式使用in操作符:单独使用和在for-in中使用。在单独使用时,in操作符会在通过对象能够访问给定属性时返回true,无论该属性是存在实例中还是原型中。

        function Person(){
}
Person.prototype.name='lisi';
Person.prototype.age=23;
Person.prototype.job='Software engineer';
Person.prototype.sayName=function(){
alert(this.name);
}
var person1 = new Person();
alert(person1.hasOwnProperty('name'));//false
alert('name' in person1);//true
person1.name = 'wangwu';
alert(person1.name);//wangwu
alert(person1.hasOwnProperty('name'));//true
alert('name' in person1);//true

  同时使用hasOwnProperty()和in操作符,就可以确定该属性到底存在与实例中还是原型中。

        function hasPrototypeProperty(object,name){
return !object.hasOwnProperty(name) && (name in object);
}

  只要in操作符返回true而hasOwnProperty()返回false,就可以确定属性是原型中的属性。

  在使用for-in循环时,返回的是所有能过通过对象访问的、可枚举的属性,其中既包括存在实例中的属性,也包括存在于原型中的属性。

  要取得对象上所有的可枚举的实例属性,可以使用ECMAScript5的Object.keys()方法;

        function Person(){
}
Person.prototype.name='lisi';
Person.prototype.age=23;
Person.prototype.job='Software engineer';
Person.prototype.sayName=function(){
alert(this.name);
}
var keys = Object.keys(Person.prototype);
alert(keys);//name,age,job,sayName
var person1 = new Person();
person1.name='zhangsan';
person1.age=21;
var pkeys = Object.keys(person1);
alert(pkeys);//name,age

  如果你想要得到所有的实例属性,无论它是否可枚举,都可以使用Object.getOwnPropertyNames()方法。

        var keys = Object.getOwnPropertyNames(Person.prototype);
alert(keys);//constructor,name,age,job,sayName

  3、更简单的原型语法

  前面的例子每增加一个属性和方法都要敲一遍Person.prototype。为减少不必要的输入,从视觉上更好地封装原型的功能,常见的做法是用一个包含所有属性和方法的对象字面量来重写整个原型对象,如下:

        function Person(){
}
Person.prototype= {
name : 'lisi',
age : 23,
job : 'Software engineer',
sayName : function () {
alert(this.name);
}
}

  我们将Person.prototype设置为等于一个以对象字面量形式创建的新对象。最终结果一样,但是有一个例外:constructor属性不再指向Person啦。每创建一个函数,就会同时创建它的prototype对象,这个对象也会自动获得constructor属性。在这里,本质上完全重写了默认的prototype对象,因此constructor属性也就变成了新对象的constructor属性(指向Object构造函数),不再指向Person函数。instanceOf操作符还能返回正确的结果,但通过constructor已经无法确定对象的类型啦。

        var p = new Person();
alert(p instanceof Object);//true
alert(p instanceof Person);//true
alert(p.constructor == Object);//true
alert(p.constructor == Person);//false

  如果constructor很重要,可以向下面这样设置:

        function Person(){
}
Person.prototype= {
constructor:Person,
name : 'lisi',
age : 23,
job : 'Software engineer',
sayName : function () {
alert(this.name);
}
}

  注意:以这种方式重设constructor属性会导致它的[[Enumerable]]特性被设置为true。默认情况下,原生的constructor属性是不可枚举的,因此如果你使用兼容ECMAScript5的JavaScript引擎,可以试一试Object.defineProperty().

        //重设构造函数,只适用于ECMAScript5兼容的浏览器
Object.defineProperties(Person.prototype,"constructor",{
enumerable:false,
value:Person
});

js的原型模式的更多相关文章

  1. [js]js设计模式-原型模式

    构造函数模型- 对象的属性和方法每人一份 function createJs(name, age) { this.name = name; this.age = age; this.writeJs = ...

  2. 攻略前端面试官(三):JS的原型和原型链

    本文在个人主页同步更新~ 背就完事了 介绍:一些知识点相关的面试题和答案 使用姿势:看答案前先尝试回答,看完后把答案收起来检验成果~ 面试官:什么是构造函数 答:构造函数的本质是一个普通函数,他的特点 ...

  3. Js原型模式

    function Person(){ } Person.prototype.name = "xd"; Person.prototype.age = 26; Person.proto ...

  4. 面向对象JS基础讲解,工厂模式、构造函数模式、原型模式、混合模式、动态原型模式

    什么是面向对象?面向对象是一种思想!(废话). 面向对象可以把程序中的关键模块都视为对象,而模块拥有属性及方法.这样我们如果把一些属性及方法封装起来,日后使用将非常方便,也可以避免繁琐重复的工作.接下 ...

  5. 【JavaScript】 JS面向对象的模式与实践 (重点整治原型这个熊孩子 (/= _ =)/~┴┴ )

    参考书籍 <JavaScript高级语言程序设计>—— Nicholas C.Zakas <你不知道的JavaScript>  —— KYLE SIMPSON   在JS的面向 ...

  6. 关于js的对象创建方法(简单工厂模式,构造函数模式,原型模式,混合模式,动态模式)

    // 1.工厂方式创建对象:面向对象中的封装函数(内置对象) 简单来说就是封装后的代码,简单的工厂模式是很好理解的,关于它的作用,就是利用面向对象的方法,把一些对象封装,使一些占用空间多的,重复的代码 ...

  7. js设计模式:工厂模式、构造函数模式、原型模式、混合模式

    一.js面向对象程序 var o1 = new Object();     o1.name = "宾宾";     o1.sex = "男";     o1.a ...

  8. JS面向对象基础讲解(工厂模式、构造函数模式、原型模式、混合模式、动态原型模式)

    什么是面向对象?面向对象是一种思想. 面向对象可以把程序中的关键模块都视为对象, 而模块拥有属性及方法. 这样如果我们把一些属性及方法封装起来,日后使用将非常方便,也可以避免繁琐重复的工作.   工厂 ...

  9. JS面向对象(1)——构造函数模式和原型模式

    1.构造函数模式 构造函数用来创建特定的类型的对象.如下所示: function Person(name,age,job){ this.name=name; this.job=job; this.ag ...

随机推荐

  1. node.js环境安装,及连接mongodb测试

    1.node.js环境安装 npm config set python python2.7npm config set msvs_version 2013npm config set registry ...

  2. Linux监控实战-2

    vmstat命令 用法:vmstat 1 --->每个1s打印信息; vmstat命令是最常见的Linux/Unix监控工具,可以展现给定时间间隔的服务器的状态值,包括服务器的CPU使用率,内存 ...

  3. 基于CentOS与VmwareStation10搭建Oracle11G RAC 64集群环境:5.安装Oracle RAC FAQ-RAC安装DB软件runInstaller看不到节点

    集群安装正常: [root@kmdbrac1 ~]# crs_stat -t -v Name Type R/RA F/FT Target State Host -------------------- ...

  4. python3-day1-python简介及入门

    python简介及入门 python简介 Python的创始人为Guido van Rossum.1989年圣诞节期间,在阿姆斯特丹,Guido为了打发圣诞节的无趣,决心开发一个新的脚本解释程序,做为 ...

  5. Mybatis原理分析之二:框架整体设计

    1.引言 本文主要讲解Mybatis的整体程序设计,理清楚框架的主要脉络.后面文章我们再详细讲解各个组件. 2.整体设计 2.1 总体流程 (1)加载配置并初始化       触发条件:加载配置文件 ...

  6. 兵家必争之地——关于O2O商业模式的一点遐想

    先来说说什么是O2O(online to offline)商业模式.创新工场CEO李开复在提及O2O模式时指出,“你如果不知道O2O至少知道团购,但团购只是冰山一角,只是第一步”.O2O营销模式又称离 ...

  7. 01从c到c++

    c++的发展历史  + 80年代贝尔实验室 本贾尼 + 83年 正式命名c++ + 87年 gnu制定了c++标准 + 92年 微软和IBM分别制定了c++标准 + 98年 ansi ISO 制定了标 ...

  8. Use Visual studio 2010 build Python2.7.10

    http://p-nand-q.com/python/building-python-27-with-vs2010.html

  9. Volley网络框架的使用

    Volley的特点:   使用网络通信更快.更简单 Get/Post网络请求网络图像的高效率异步请求 可以对网络请求的优先级进行排序处理 可以进行网络请求的缓存 可以取消多级别请求 可以和Activi ...

  10. 使用compass编译sass

    1.初始化项目 compass create test(项目名称),会在当前目录下创建test子目录,test的子目录下有config.gb文件,sass和stylesheets文件夹. 2.编写sa ...