理解javascript中的原型模式
一、为什么要用原型模式。
早期采用工厂模式或构造函数模式的缺点:
1.工厂模式:函数creatPerson根据接受的参数来构建一个包含所有必要信息的person对象,这个函数可以被无数次的调用,工厂模式尽管解决了创建多个相似对象的问题,却没有解决对象识别的问题(返回的是自定义的一个对象o,不明确对象o的类型)。
2. 构造函数模式:构造函数的调用和其他oo语言一样,用new操作符来构建一个Person的实例;javascript中的构造函数也是函数(所以也可以直接像普通函数那样直接调用方法名)只不过可以用来创建对象,这是和其他oo语言不一样的地方(其他oo语言的构造函数不是函数,不能直接调用方法名,必须用new操作符来创建对象才可以),相同点是构造函数首字母都要大写,非构造函数首字母都是小写。
构造函数模式解决了创建多个相似对象的问题和对象识别的问题,但是不足的地方是,采用这种模式会创建多个完成同样任务的Function实例。
拿上面的例子来分析内存:
此时person1.isName===person2.isName 是为false的
不同实例上的同名函数是不相等的,我们希望有一种方法,即可以解决创建多个相似对象的问题和对象识别的问题,还能让每个实例共享相同的方法。
上面的例子可以做改进将方法提到构造函数的外面,单独写成一个全局函数,this.isName指向一个指针:
不同的实例是共享了方法,但是如果有很多个方法,有几个我们就要定义几个全局函数,这样我们自定义的引用类型就失去了封装性,为了解决这一系列的问题,所以才有了原型模式。
二、理解原型模式。
1.理解原型模式先理解原型对象:
我们创建的每一个函数(javascript中函数也是一个对象)都有一个原型属性(prototype),原型属性实质上是一个指针,它指向一个对象,这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法(通俗的说就是这个特定类型的所有实例都可以共享原型对象包含的属性和方法)。
2.原型对象的两种赋值方法:
第一种:
此时实例对象person1和person2的属性和方法都是用的原型对象共享的,所以上面的例子输出的结果为:
(可以看到person1和person2共享一个sayName方法,它们的方法是相同的)
第二种:
和创建一个引用对象一样,也可以采用字面量的形式给原型对象赋值。最终结果和上面的结果相同,但是一个例外就是constructor属性不再指向Person了,因为字面量的方式重写了原型对象,此时的contructor指向的是Object对象(这里不懂看后面的内存分析了解原理)。
但是我们可以指明constructor指向Person:
3.原型对象的内存分析:
引用了一下《javascript高级程序第三版》中的内存分析图。
Person构造函数、Person原型对象、Person现有的两个实例之间的关系:
每一个函树都会有一个原型属性(prototype),它是一个指针,指向原型对象;默认情况下,原型对象会包含一个constructor(构造函数)属性(原型最初只包含constructor属性),这个属性包含一个指向prototype属性的指针;拿上面的图做例子,Person.prototype.constructor指向Person,通过这个构造函数就可以继续为原型对象添加其他的属性和方法。
当调用构造函数创建一个新实例后,该实例内部会包含一个内部属性(指针),它指向构造函数的原型对象;这个连接存在于实例与构造函数的原型对象之间,而不是存在于实例与构造函数之间;也就是说这个内部属性和构造函数没有直接的关系。
4.原型对象中的值不能被对象实例重写:
实例:
测试结果:
可以看到原型对象中的name没有被改变,person1.name来自实例,person2.name来自原型。
在原型模式中当通过person1.name读取属性值时,首先会去实例上查找有没有名称为name的属性,有的话就不会再去原型对象上查找;如果实例上没有,则就会去原型上搜索。
也就是说当我们给实例上添加了一个属性,这个属性就会阻止我们去原型上访问这个同名属性,但是不会修改那个属性。
内存分析,图中省略了与Person构造函数之间的关系:
通过delete操作符可以直接删除实例中的属性:delete person1.name。
5.原型的动态性:
第4点说了不能通过对象实例来修改(重写)原型对象中的值,不是说原型对象中的值不能被修改,通过如下方式仍然可以修改:
测试结果如下:
由于在原型中查找值的过程是一次搜索,因此在对原型对象做的任何修改都会立即从实例上反映出来,即使是先创建实例后修改原型也如此。
实例:
测试结果:
内存分析:
( friend改为person5,function中省略了内容)
但是如果在先创建实例后修改原型的情况下,用字面量赋值的方式来重写原型对象,这就会切断现有原型与任何之前存在的对象实例之间的联系(不是先创建实例后修改原型的情况下仍然可以用这种方式重写原型对象)。
实例:
测试结果:
内存分析:
(图引用《JavaScript高级程序设计第3版》,图中值未改,原理一样)
6.原生对象的模型:
所有原生引用类型(Object、Array、String等)都在其构造函数的原型上定义了方法。例如:Array.prototype.sort(),String.prototype.substring等,通过原生对象的模型不仅可以读取到所有的默认方法的引用,还可以像修改自定义对象的原型一样修改原生对象的原型,所以也可以给原生对象添加方法,但是在实际运用中我们不要这样去修改原生对象的模型(命名冲突,重写原生方法等等问题都是我们在实际开发中所不希望遇到的)。
7.关于原型对象的几种操作:
1) isPrototypeOf检测实例对象是否包含指向某个原型对象的指针,包含则返回true,否则false。
2) Object.getPrototypeOf(实例对象) ,返回的就是这个对象的原型,下面的结果为true。
Object.getPrototypeOf(person1).name通过这种方式可以访问到原型对象中的name值。
3)hasOwnProperty(从object中继承而来)检测一个属性是否存在于实例中,是则返回true,否则返回false。
用in也可以检测属性值,只不过用这种方式检测的无论属性是在实例中还是原型中都会返回true。关于检测属性我的另一篇文章中有:Javascript之数据检测
4)Object.keys(原型对象)返回一个包含所有可枚举属性的字符串数组:
测试结果:
8.原型对象的缺点:
原型对象的好处是原型中的所有属性和方法可以被很多实例共享,缺点是当原型中包含引用类型的值的属性时,一个实例对象对这个引用类型的属性做了修改,在其他实例对象中也可以体现出来。
9.好的实践:
1)组合使用构造函数模式和原型模式:
2)动态原型模式:
除了上面两种模式以外还有寄生构造函数模式和稳妥构造函数模式这里就不总结了,没有用到过没有什么体会,以上只是我看《JavaScript高级程序第三版》的学习笔记,用自己的理解的方式归纳整理了一下。
理解javascript中的原型模式的更多相关文章
- 理解javascript中的策略模式
理解javascript中的策略模式 策略模式的定义是:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换. 使用策略模式的优点如下: 优点:1. 策略模式利用组合,委托等技术和思想,有效 ...
- 理解JavaScript中的原型继承(2)
两年前在我学习JavaScript的时候我就写过两篇关于原型继承的博客: 理解JavaScript中原型继承 JavaScript中的原型继承 这两篇博客讲的都是原型的使用,其中一篇还有我学习时的错误 ...
- 浅谈JavaScript中的原型模式
在JavaScript中创建对象由很多种方式,如工厂模式.构造函数模式.原型模式等: <pre name="code" class="html">/ ...
- 简单理解javascript中的原型对象,实现对之间共享属性和行为
javascript中提供了构造函数.可以方便的创建对象. 典型的构造函数例如以下: function Person(name, age) { this.name = name; this.age = ...
- 如何理解JavaScript中的原型和原型链
首先是一张关系图,避免抽象化理解时产生的困难 Function对象 函数对象是JavaScript学习中不可避免的一部分,而且这一部分相对重要且抽象 函数的创建方式有2种: 字面量创建 var foo ...
- 一句话简单理解javascript中的原型对象
通过构造函数F创建的对象实例p 这个对象p的原型对象是 构造函数中prototype属性指向的对象s,这个对象p中也有个非标准的__proto__属性指向构造函数prototype属性所指向的对象s, ...
- JavaScript中的原型模式
我们创建的每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法.使用原型对象的好处是可以让所有对象实例共享它 ...
- 深入理解JavaScript中创建对象模式的演变(原型)
深入理解JavaScript中创建对象模式的演变(原型) 创建对象的模式多种多样,但是各种模式又有怎样的利弊呢?有没有一种最为完美的模式呢?下面我将就以下几个方面来分析创建对象的几种模式: Objec ...
- 前端知识体系:JavaScript基础-原型和原型链-理解原型设计模式以及 JavaScript中的原型规则
理解原型设计模式以及 JavaScript中的原型规则(原文地址) 1.原型对象:我们创建的每一个函数(JavaScript中函数也是一个对象)都有一个原型属性 prototype,原型属性实质上是一 ...
随机推荐
- ucsc工具集合
wget http://hgdownload.cse.ucsc.edu/admin/jksrc.zip 解压后所有工具在kent目录里 发现个更方便的.... http://hgdownload.cs ...
- iOS学习笔记---oc语言第四天
字符串 数组 一.使用苹果帮助文档 学会使⽤用苹果帮助⽂文档是开发者的⼀一项技能 Inherits from 继承⾃自 Conforms to 遵循什么协议 Framework 属于哪个框架 Avai ...
- Android EditText内容监听
监听 EditText的内容变化,作出对应的处理. MainActivity.class package com.example.edittextdemo; import android.app.Ac ...
- 弹出层是iframe引入的页面,如果用js进行隐藏呢?
<script> $(document).ready(function(){ $('.bjfh').click(function(){ parent.document.getElement ...
- hdu 2795 线段树(二维问题一维化)
Billboard Time Limit: 20000/8000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
- HDU-5781 ATM Mechine(概率DP)
题目大意:某个未知整数x等概率的分布在[0,k]中.每次你都可以从这个整数中减去一个任意整数y,如果x>=y,那么x=x-y,操作次数累计加1:否则,将会受到一次错误提示.当错误提示超过w次,将 ...
- HDU-1542 Atlantis(离散化+扫描线)
题目大意:给n个矩形,可能重叠,求面积. 题目分析:线段树维护扫描线. 代码如下: # include<bits/stdc++.h> using namespace std; # defi ...
- 越狱Season 1-Episode 2: Allen
Season 1, Episode 2: Allen [Previously, on Prison Break] previously: 以前(预先) 前情回顾 -Judge: I find it i ...
- min-height for IE6
1. className{ min-height:500px; height:auto !important; height:500px; } 2. 在做页面布局时遇到了i ...
- GOOGLE的专业使用方法(转)
搜索引擎命令大全! 1.双引号 把搜索词放在双引号中,代表完全匹配搜索,也就是说搜索结果返回的页面包含双引号中出现的所有的词,连顺序也必须完全匹配.bd和Google 都支持这个指令.例如搜索: “s ...