本文以 JavaScript 语言为例,介绍了无类面向对象语言中实现各种面向对象概念的方法。值得注意的是,下面所说的并非“奇技淫巧”,其中的大部分都是计算机科学家们在设计无类语言时就已经确立了的模式,少部分是我借鉴其它语言的经验已经对前辈们思想的理解给出了完备化技术。
阅读本文至少需要对 JavaScript 语言“特别”的对象机制以及函数的运行上下文有所了解。如果您还对 JavaScript 对象知之甚少,可以查看附件中我翻译的 ECMA262 v3 中 4.2.1 Object 这一节;如果对 Lambda 演算不了解,建议去看 SICP
一. 基础:
建立类。只需声明一个函数作为类的构造函数即可。
function Light (light) {
//填充对象属性
this.light = light ? light : 0
this.state = false
//对象方法。
//放心,JavaScript 没傻到给每个对象都真去分配一个函数的地步
this.turnOn = function () {
this.state = true
}
}
创建实例。通过下面的代码创建一个新的电灯:
new Light(100) instanceof Light
js> true
这个新的电灯现在是匿名的,接下来可以在任何表达式中使用它。当然,最常用的做法是把一个名字绑定上这个对象。
访问实例属性。
//访问属性
new Light(100).light
js> 100
anOnLight = new Light()
//调整属性
anOnLight.state = true
匿名类。顾名思义,这个类没有名字(精确的说是构造函数没有名字)。就像这样:
aLight = new (function (light){
this.light = light ? light : 0
this.state = false
)(90)
类属性;类函数。顾名思义,一个类自身绑定的属性、函数,被所有类的实例可见,但不可直接使用。
//类属性
Light.SIZE = 5
//类函数
Light.newInstence = function (arg) {
//这么简单的 Factory 模式
//this 指向函数运行所在名字空间的上级
return new this(arg)
}
想利用实例使用类的属性用下面的办法。函数调用类似:
anOnLight.constructor.SIZE
js> 5
类方法。真正意义上的“方法”
Light.prototype.turnOff = function () {
this.state = false
}
anOnLight.turnOff()
anOnLight.state
js> false
二. 进阶
单继承。一个类扩展另一个类的所有能力。
function PhilipLight (price) {
this.price = price
}
//事实上是建立了一个匿名的 Light 实例,然后将其能力反映给 PhilipLight
//飞利浦灯泡的亮度默认为100。这种继承模式很有意思。
PhilipLight.prototype = new Light(100)
myLight = new PhilipLight(12)
myLight.price
js> 12
//类方法照用。对象方法也照用。
myLight.turnOn()
myLight.state
js> true
可以把单继承作为一个 Object 类的能力保留下来,如果不强求默认值的话:
//把那些垃圾的库抛在脑后,让它们见识见识什么叫优雅。
Object.prototype.extend = function (aClass) {
this.prototype = new aClass
}
PhilipLight.extend(Light) //No problem
多继承。我可以很明白的说,JavaScript 办不到。因为想在单继承链上实现多继承是不可能的。不过,这并不是说 JavaScript 面向对象机制不能达到多继承那样的表现力:装饰模式、Mixin 这些更强大的机制都是能办到的。
Mixin。漂亮地实现 Mixin 的前提是访问拦截器(getter 和 setter)。JavaScript 1.6 之前没有这种东西,需要修改编程习惯——这不是我们想要的。JavaScript 1.7 中加入的只是对特定消息的访问拦截器(现已在出现在 1.5 C 实现中)支持所以我们只能稍微改变一下编程风格。先说明一下如何对某个对象应用其它类的函数。
泛型。JavaScript 1.5 中,我们可以用函数对象的 call() 方法或 apply() 方法对该对象应用来自其它类的函数:
//Light 也是一种商品
function Product (price) {
this.price = price
//买 num 件商品需要的钱
}
Product.prototype.buySetOf = function (num) {
return this.price * num
}
//那么对于同样有 price 属性的飞利浦灯泡,我们可以这样计算买10个灯泡要多少钱:
Product.prototype.buySetOf.call(myLight, 10)
js> 120
//apply 的第二个参数是被 call 的参数列表
Product.prototype.buySetOf.apply(myLight, [10])
js> 120
类的半自动混合。
Object.prototype.mixin = function (aClass) {
//这里用到的技术下文中讲解
this.prototype.app = function (func, args) {
//func 是消息字符串
if (this[func] != undefined)
return (this[func].apply(this, args))
return (aClass.prototype[func].apply(this, args))
}
}
PhilipLight.mixin(Product)
myLight = new PhilipLight(12)
myLight.app('buySetOf', [10])
js> 120
对象的半自动混合。对象当成另一个对象使用,类似的方法:
Object.prototype.able = function (anObject) {
this.app = function (func, args) {
//func 是消息字符串
if (this[func] != undefined)
return (this[func].apply(this, args))
return (anObject[func].apply(this, args))
}
}
//这个用法弱智了点,但确实能说明问题
myLight.able(new Product)
myLight.app('buySetOf', [10])
js> 120
三. 补完
这一章讲解 4P 的实现。
包(package)没什么好说的,通读一遍 Prototype.js,看看作者是如何使用 JavaScript 对象描述程序结构的,就什么都知道了。这可比什么 interface 强多了。
公有(public)权限。Pass.
受保护的(protected)权限。如果你使用了 JavaScript 对象来描述程序结构,那么,其中每个类中的函数会自然获得 protected 权限——因为,使用它们都需要包名或者 with 语句。
私有(private)权限。不像 Python 等等语言,它们事实上是不存在的私有权限;JavaScript 使用 Lambda 演算中的逃逸变量原理实现私有权限。换个例子:
function Desk (height) {
//对于一个符合标准的实现,这里的 var 关键字可以省略
var height = height ? height : 0
var weight = 0
//下面的东西对于 Java 程序员来说很熟悉 :)
this.getHeight = function () {
return height
}
this.setHeight = function (num) {
height = num
}
}
deak = new Desk(34)
deak.getHeight()
34
deak.setHeight(45)
deak.getHeight()
45
desk.height
ReferenceError line 1:desk.height is not defined
此时的 height 就是逃逸变量,从 Desk 函数中以作为对象上绑定的函数的环境上绑定的变量“逃”了出来(这句话有些拗口,不过的确如此)。对于直接由构造函数参数引入的变量,也可以作为私有属性。类似的,还可以有私有函数——直接将函数定义写入构造函数即可。
四. 小结
以 Self、JavaScript 为代表的无类语言在用函数式风格解释面向对象思想方面作出了巨大进步,无论是灵活性还是强大程度都不是那些关键字一大堆的语言可与之相媲美的。如果我有空,可能还会来介绍一点 E 语言方面的思想,那才是真正无敌的无类语言啊。
分享到:
相关推荐
rulesets/java/ali-exception.xml,rulesets/java/ali-flowcontrol.xml,rulesets/java/ali-naming.xml,rulesets/java/ali-oop.xml,rulesets/java/ali-other.xml,rulesets/java/ali-set.xml -f text
2. **面向对象编程(OOP)**:介绍类与对象的概念,如何设计类和实现继承、封装、多态等特性。 3. **数据库操作**:教授如何通过PHP连接MySQL等数据库,并执行增删改查等基本操作。 4. **Web开发框架**:如Laravel、...
- 编码 (OOP):按照编码规范编写代码,编写策略文档和标准文档,利用对象库。 - 测试 (OOT):包括单元测试、集成测试和系统测试,确保软件质量。 - 软件维护 (OOSM):修复bug,进行软件升级和数据库扩展。 2. **...
根据提供的信息,我们可以总结出以下有关C++编程语言学习资源的知识点: ### 一、C++教程电子书籍URL概述 C++是一种广泛使用的通用编程语言,适用于多种应用场景,包括系统软件开发、游戏引擎构建以及高性能服务器...
当从本地上传文件到HDFS中时报错 fs.FSInputChecker: Found checksum error: b[0, 69]=6d6f77656968616861686168616868616686168616861686861680a org.apache.hadoop.fs.ChecksumException: Checksum error: file:/...
### 使用Yii构建博客系统知识点详解 #### 一、前言 在《Yii Blog Book.pdf》这份资料中,作者通过一个实战项目——使用Yii框架搭建博客系统的过程,详细介绍了Yii的基本用法及其在实际项目开发中的应用技巧。对于...
3. **面向对象编程(OOP)**: - 类与对象的概念。 - 继承与多态性。 - 封装、抽象类、接口。 4. **异常处理**: - try...except...finally语句。 - 自定义异常。 5. **模块与包**: - 模块导入:import语句。...
- **OOP基础**:面向对象编程的基本概念,如类、对象、继承、封装等。 - **数据库编程**:SQL语言的基础,如数据表的创建、查询、更新等操作。 - **Yii文档阅读**:深入理解Yii框架的官方文档和API手册,以便更好地...
# OOP(机试) 本程序总结文章:http://blog.qiji.tech/?p=10344 - - - ## 程序基本要求 一、项目名称: Air Infomation Programming 基于控制台的航班信息程序,简称AIP 二、具体要求如下: (1)显示航班...
从程序员的角度来看,这个例子说明了如何使用: - OOP( https://www.mathworks.com/help/pdf_doc/matlab/matlab_oop.pdf); - 预先使用绘图属性( http://it.mathworks.com/help/matlab/ref/plot.html); 。: ...
第4章 核心库类 第5章 可视控件 第6章 建立用户界面 第7章 使用窗体 第二部分 Delphi面向对象的体系结构 第8章 Delphi应用程序的结构 第9章 编写Delphi组件 第10章 库与组件包 第11章 建模和OOP编程 第12章 从COM到...
写完那篇“写给懂C语言的人的PHP基本语法入门”后一直在学习PHP5的OOP,目的很简单,就是想研究MVC的PHP实现,所以,兴趣很快转移到MVC上面,网上有很多长篇大论,但是看完了我还是不能写出一个最简单的MVC程序,我...
OOP-VGC项目 OOP项目“虚拟全球学院”的存储库。 目标:设计和实现一个应用程序,以注册和管理分支机构中的课程,学生和教职员工。 安装 将文件“谢谢”下载到github页面。 或使用git链接克隆项目: git clone ...
1. **JavaScript Tools**: 提供了更加强大的JavaScript支持,包括JSDT集成、JavaScript闭包/OOP支持等。 2. **编辑增强**: 改进了代码编辑器的功能,提高了编程效率。 3. **代码浏览**: 增强了代码导航功能,便于...
CSDN(China Software Developer Network)是中国最大的开发者技术社区之一,提供了大量的技术文档、博客、课程等资源。对于Java学习者来说,CSDN是一个不可或缺的平台。下面是一些具体的资源介绍: - **链接一:**...
4. **面向对象编程**:涉及类(class)、对象(object)、继承(inheritance)、多态(polymorphism)等OOP概念。 5. **标准库**:详细列出了Python内置的众多模块,如os用于操作系统接口,sys用于系统相关功能,re...
有一段时间没用sqoop了,今天打开进行测试的时候,发现命令行总是出现下面这样的警示信息: Warning: /opt/module/sqoop/bin/…/…/hcatalog does not exist! HCatalog jobs will fail. Please set $HCAT_HOME to ...
格式化namenode时 报错 No Route to Host from node1/192.168.3.101 to hadoop05:8485 failed on socket timeout exception: java.net.NoRouteToHostException: No route to host解决方案 一、报错信息概要: ...