`

《王者归来》读书笔记 ── JavaScript 面向对象编程(2)

阅读更多

I. 什么是 prototype

JS 中对象的 prototype 属性可以返回对象类型原型的引用(确实拗口),让我们分开来理解。对象的类(Class)和对象实例(Instance)之间是一种“创建”关系,所以类(Class)是对象的一个类型(Type)。在面向对象领域里,实例和类型不是唯一的一对可描述的抽象关系。在 JS 里还有另外一个更高层次的抽象关系:类型(Type)与原型(prototype),它恰好和类型与实例的抽象关系构成了一个三层的链。

在生活中有个习语“照猫画虎”,这里的猫就是原型,而虎就是类型,用 JS 的 prototype 表示为:“虎.prototype = 某只猫”或“虎.prototype = new 猫()”。当然这只是个比喻。

要注意的是,原型模式要求一个类型在一个时刻只能有一个原型,这里有两层含义:

1. 每个具体的 JS 类型有且仅有一个原型(prototype),在默认情况下该原型是一个 Object 对象(不是 Object 类型);

2. 这个类型的实例的所有类型,必须是满足原型关系的类型联。看个例子:

function ClassA(){...}
ClassA.prototype = new Object();  //默认值,可以省略

function ClassB(){...}
ClassB.prototype = new ClassA();

function ClassC(){...}
ClassC.prototype = new ClassB();

var obj = new ClassC();

alert(obj instanceof ClassC);  //ture;
alert(obj instanceof ClassB);  //ture;
alert(obj instanceof ClassA);  //ture;
alert(obj instanceof Object);  //ture;

简单描述一下原型关系的类型链:

object <─ ClassA <- objectA <─ ClassB <- objectB <─ ClassC <- objectC

有意思的是,JS 并没有规定一个类型的原型的类型,因此可以是任何类型,但通常是某种对象,这样,对象 - 类型 - 原型(对象)就可能构成一个环形结构,或其他有意思的拓扑结构。


II. prototype 使用技巧

JS 的对象是动态的,prototype 也不例外,给 prototype 增减属性会改变这个类型的原型,以及由这个原型所创建的对象上。

function Point(x, y){
    if(x) this.x = x;
    if(y) this.y = y;
}

//设定 Point 对象的 x, y 默认值并动态的添加一个属性 z
Point.prototype.x = 0;
Point.prototype.y = 0;
Point.prototype.z = 0;

var p1 = new Point;
var p2 = new Point(1, 2);

alert(p1.x + ', ' + p1.y + ', ' + p1.z);
//0, 0, 0   p1 为默认(0, 0)的对象,加上 z 的值也为 0,所以是 0, 0, 0

alert(p2.x + ', ' + p2.y + ', ' + p2.z); 
//1, 2, 0   原型属性与对象属性重名,对象属性会覆盖原型属性,所以为1, 2

如果我们用 delete 运算符删除 p2 的 x 属性,那么 p2.x 会恢复 prototype.x 的默认值 0:

delete p2.x;
alert(p2.x)  //0

关于用 delete 操作还原默认值还有一个例子:

function ClassA(){
    this.x = 10;
    this.y = 20;
    this.z = 30;
}

ClassA.prototype = new ClassA;  //将 x, y, z 同时设为 ClassA 的默认值

//下面这个方法会将自身的非原型属性删除,达到 reset 的效果
ClassA.prototype.reset = function(){
    for(var each in this){
        delete this[each];
    }
}

var a = new ClassA();

a.x *= 2;
a.y *= 2;
a.x *= 2;

alert(a.x + ', ' + a.y + ', ' + a.z)  //20, 40, 60

//调用 reset 方法回复对象的默认值
a.reset();

alert(a.x + ', ' + a.y + ', ' + a.z)  //10, 20, 30

我们还可以利用 prototype 为对象属性设置一个可读的 getter,如果忘记了 getter,可以再回顾下笔记(1)。实际上,将一个对象设置为一个类型的原型,相当于通过实例化这个类型,为对象创建只读副本:


//定义一个多边形类型
function Polygon(){

    //存放多个多边形的定点
    var m_points = [];
    m_points = Array.apply(m_points, arguments);
    
    //利用上面提到的方法为第一个顶点创建只读副本
    function GETTER(){};
    GETTER.prototype = m_points[0];
    this.firstPoint = new GETTER();
    
    //公有属性
    this.length = {
        valueOf : function(){return m_points.length},
        toString : function(){return m_points.length}
    }

    //添加一个或多个顶点    
    this.add = function(){
        m_points.push.apply(m_points, arguments);
    }
    
    //取得序号为 idx 的顶点
    this.getPoint = function(idx){
        return m_points[idx];
    }
    
    //设置一个特定位置的顶点
    this.setPoint = function(idx, point){
        if(m_points[idx] == null){
            m_points[idx] == point;
        }
        else{
            m_points[idx].x = point.x;
            m_points[idx].y = point.y;
        }
    }
}

//构建一个三角形 p
var p = new Polygon{(x:0, y:1), (x:3, y:1), (x:0, y:4))}

p.firstPoint.x = 100;  //假如我们为第一个定点重新设定 x 值
alert(p.getPoint(0).x)  // 0,私有成员的值并未受到影响
delete p.firstPoint.x  //恢复默认值
alert(p.firstPoint.x);  //0

p.setPoint(0, {x:3, y:4});  //通过 setter 改写了私有成员
alert(p.firstPoint.x);  //3,getter 的值发生了改变

上面的例子还说明了,用 prototype 可以快速创建对象的一个或多个副本,以一个对象为原型来创建大量的新对象,这正是 prototype pattern 的本质:

var p1 = new Point(1, 2);
var points = [];
var PointPrototype = function(){};
PointPrototype.prototype = p1;
for(var i = 0, i < 10000, i++){
    points[i] = new PointPrototype();  //由于 PointPrototype 是个空函数,所以它的构造要比直接构造 //p1 快得多
}

除了以上作用,prototype 更常见的用处是声明对象的方法,这样避免了在构造函数中每次对方法进行重新赋值,节省了时间和空间。所以应尽量采用 prototype 定义对象方法,除非该方法要访问对象的私有成员或者返回某些引用了构造函数上下文的闭包。

习惯上,我们把采用 prototype 定义的属性和方法称为静态属性和静态方法,或者原型属性原型方法,把用 this 定义的属性和方法称为公有属性和公有方法。


III. prototype 的实质、价值和局限性

上面已经说了 prototype 的作用,现在来透过规律揭示 prototype 的实质。prototype 的行为类似于 C++ 中的静态域,将一个属性添加为 prototype 的属性,这个属性将被该类型所创建的所有实例所共享,但这种共享是只读的。在任何一个实例中只能够用自己的同名属性覆盖这个属性,而不能够改变它。看个例子:

function Point2D(x, y){
    this.x = x;
    this.y = y;
}

Point2D.prototype.x = 0;
Point2D.prototype.y = 0;

function ColorPoint2D(x, y, c){
    this.x = x;
    this.y = y;
}

ColorPoint2D.prototype = new Point2D();
ColorPoint2D.prototype.x = 1;
ColorPoint2D.prototype.y = 1;

var cp = new ColorPoint2D(10, 20, red);
alert(cp.x)  //10,先查找 cp 自身属性
delete cp.x;
alert(cp.x)  //1,被删除后查找上层原型属性
delete ColorPoint2D.prototype.x;
alert(cp.x)  //0,删除后继续查找更上层原型链上的属性

以一个对象为实例,安全地创建大量的实例,这就是 prototype 的真正含义,也是它的价值所在。

但由于 prototype 仅仅是以对象为原型给类型构建副本,因此也具有很大局限性,比如改变某个原型上引用类型的属性的属性值,将会彻底影响到这个类型创建的每一个实例。

总之,prototype 是一种面向对象的机制,它通过原型来管理类型与对象之间的关系,prototype 的特点是能够以某个类型为原型构造大量的对象。

分享到:
评论

相关推荐

    王者归来之Thinking in java读书笔记

    通过阅读《王者归来之Thinking in Java读书笔记》,你可以系统地掌握Java编程的核心知识,理解编程思想,提高解决问题的能力。无论是初学者还是经验丰富的开发者,都能从中受益匪浅。这本书不仅提供了理论知识,还有...

    javascrip王者归来源码.zip

    《JavaScript王者归来》是针对JavaScript编程的一套深入学习资源,包含源码分析,旨在帮助开发者提升在JavaScript领域的技能。此压缩包中包含了三部分主要内容:《JavaScript王者归来》的教材内容、JavaScript高级...

    《JavaScript王者归来》

    《JavaScript王者归来》是一部深入探讨JavaScript编程语言的著作,旨在揭示其内在的神秘特性,并逐步引领读者从基础知识迈向高级主题。这部作品分为五个部分,全面覆盖了JavaScript的各个方面,不仅传授技术,更传递...

    王者归来源代码

    2. **对象**:JavaScript的对象是一种键值对的集合,它可以模拟传统面向对象编程中的类和实例。源代码中会展示如何创建和操作对象,包括使用对象字面量、构造函数、原型以及Object.create方法等。 3. **闭包**:...

    Java Web整合开发王者归来

    6. Spring框架篇:Spring框架是Java企业级应用的核心,涵盖依赖注入、AOP(面向切面编程)、Spring MVC、Spring Boot等内容,为构建复杂的企业级应用提供强有力的支持。 7. EJB与Web服务篇:探讨Enterprise ...

    王者归来-HTML5與CSS3权威指南书范例

    【标题】"王者归来-HTML5與CSS3权威指南书范例" 提供了一套全面的HTML5和CSS3的学习资源,旨在帮助开发者深入理解这两种技术的核心概念与实践应用。HTML5是现代网页开发的标准,它引入了许多新的元素、属性和API,极...

    Linux C程序设计王者归来 [吴岳等编著][清华大学出版社]

    《Linux C程序设计王者归来》是一本面向不同层次Linux学习者的权威指南,由吴岳等专家编著,并由清华大学出版社出版。这本书旨在帮助读者深入理解Linux操作系统下的C语言编程技术,无论你是初学者还是已有一定基础的...

    Java王者归来源码

    Java王者归来源码 百度云 baidu 源码 提供下载链接密码

    Java.Web整合开发王者归来 源码

    1. **Java基础**:Java作为Web开发的基石,基础部分会涉及Java语言的语法、面向对象编程概念、异常处理、集合框架(如ArrayList、LinkedList、HashMap等)以及IO流和多线程。这些是构建任何Java Web应用的必备知识。...

    Java.web整合开发王者归来整本书内容及光盘源码

    由于上传大小限制50M,因此分享的是我的百度网盘链接,下载后文本文件里有链接,包括Java Web整合开发王者归来整本书326.5M 的PDF文档以及54.7M的光盘源代码 本书简介: 资深Java程序员耗时一年时间写作,十年开发...

    王者归来通达信指标公式源码.doc

    在测试中,“王者归来”指标设定了5天内价格上涨2个点的成功率作为参考标准,但实际操作应结合更多的分析手段,如基本面分析、其他技术面的指标等,以全面考量投资决策。此外,成功率测试未考虑止损策略和交易时机的...

    王者归来_论坛系统

    Spring框架负责管理应用程序的业务对象和事务控制,通过依赖注入(DI)和面向切面编程(AOP)来简化开发。Struts作为MVC设计模式的实现,主要处理HTTP请求和视图展示,它协调控制器、模型和视图,使得各个部分职责...

    Evony: The Kings Return 伊芙妮:王者归来 Unity无尽射击游戏项目源码C#

    – 无尽游戏 64 位支持 IL2CPP AAB (ARMv64) 显示易于自定义的图表 易于编辑和重新设计 专为移动设备优化 ADMOB 集成 EASY(横幅、间质) 通用(手机和平板电脑) 完整文档 如何玩 – 在这款《Evony:王者归来》游戏...

    王者归来之经典篇—ThinkInJava4Th中文版课后习题答案

    2. **面向对象编程**:类、对象、封装、继承、多态,以及接口与抽象类的区别。 3. **集合框架**:Array、ArrayList、LinkedList、HashSet、HashMap等数据结构的使用和理解,以及泛型的应用。 4. **异常处理**:...

    王者归来的j2me源码

    【王者归来】是一款基于J2ME(Java Micro Edition)平台开发的手机游戏源码,它展示了如何在有限的资源和性能限制下,构建一个具有趣味性的过关类游戏。J2ME是Java的一种轻量级应用平台,主要用于移动设备、嵌入式...

    Java.Web整合开发王者归来.zip

    其面向对象的特性、强大的内存管理以及丰富的类库,使得Java成为Web开发的首选语言之一。本书将深入讲解如何利用Java技术进行Web应用的设计、开发与优化。 Web开发涵盖了前端界面设计、后端服务器处理以及数据库...

    java web开发王者归来源码1

    java web开发王者归来源码,由于压缩好后是72.8M,这是第1部分的源码。

    Java Web整合开发王者归来 (共两部分) part2 pdf + 源码

    Java Web整合开发王者归来 (共两部分) part2 pdf + 源码

    java web王者归来41章论坛系统源码

    【Java Web王者归来41章论坛系统源码详解】 Java Web技术是开发Web应用程序的核心工具,尤其在企业级应用中占据重要地位。本资源“Java Web王者归来41章论坛系统源码”提供了完整的论坛系统实现,对于学习和理解...

    C#面向对象入门实战-通讯录01

    在本课程"**C#面向对象入门实战-通讯录01**"中,我们将深入学习C#编程语言的基础以及如何运用面向对象编程(OOP)原则来构建实际应用。面向对象编程是一种强大的软件开发方法,它允许我们通过模拟现实世界中的对象和...

Global site tag (gtag.js) - Google Analytics