`
Lich_Ray
  • 浏览: 164216 次
  • 性别: Icon_minigender_1
  • 来自: 南京
文章分类
社区版块
存档分类
最新评论

无类语言的OOP(JavaScript描述)

阅读更多
本文以 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 语言方面的思想,那才是真正无敌的无类语言啊。
  • 4.2.1.zip (9.9 KB)
  • 描述: ECMA-262 翻译片段。
  • 下载次数: 614
分享到:
评论
6 楼 charon 2007-06-13  
dogstar 写道

为什么非要写的那么复杂呢?我在写javascript的时候,顶多就用到一些对象之类的,什么继承之类的考虑都不考虑。写java不也是一个接口,一个实现。连继承都很少有。(不要告诉我,我写的应用太小,哈哈)。所以,语言本身探讨可以,但不要过多吹毛求疵了。


只能说你所做的应用或者说用来抽象和解决问题的方法需要的只是封装,比如说继承或者多态之类的OO特性本身就有点多余。
我看到过很多人用java写程序,只是因为项目组要求用java,而项目组要求用java,只是因为客户如此要求,或者公司策略如此,而客户或者公司的要求的原因,并非在于java是个OO的语言,而是因为java的跨平台部署特性。
写的应用的大小,用哪个语言,本身就和是不是OO没有关系。
5 楼 dogstar 2007-06-13  
well done,继续写一些好文章。

charon 写道
貌似很多开源包和很多人都实现了自己的extends/mixins或者类似的方法.有些在里面还干了一些非常magic的事情。

这个,大概是用基于prototype的语言来实现这些东西的困惑巴。因为没有在语言级别提供直接的支持,于是大家都百花齐放,或者说的难听一点就是各奔东西了。直接的结果是某些开源包互相之间有冲突,不能拿来一齐使用(我有近半年没用过javascript了,或者现状已经改变了?社区有了大一统的做法?)

另外,这里还差一个多态的实现,虽然简单,但称不上优雅。也一齐补全了吧


javascript应该算是小巧灵性。这些灵活就注定了他不太容易大规模工业生产。比如java。
为什么非要写的那么复杂呢?我在写javascript的时候,顶多就用到一些对象之类的,什么继承之类的考虑都不考虑。写java不也是一个接口,一个实现。连继承都很少有。(不要告诉我,我写的应用太小,哈哈)。所以,语言本身探讨可以,但不要过多吹毛求疵了。
4 楼 dennis_zane 2007-06-13  
charon 写道
貌似很多开源包和很多人都实现了自己的extends/mixins或者类似的方法.有些在里面还干了一些非常magic的事情。

这个,大概是用基于prototype的语言来实现这些东西的困惑巴。因为没有在语言级别提供直接的支持,于是大家都百花齐放,或者说的难听一点就是各奔东西了。直接的结果是某些开源包互相之间有冲突,不能拿来一齐使用(我有近半年没用过javascript了,或者现状已经改变了?社区有了大一统的做法?)

另外,这里还差一个多态的实现,虽然简单,但称不上优雅。也一齐补全了吧


javaeye有人做了个JSI,可以解决各开源js类库的冲突并共同使用
3 楼 dennis_zane 2007-06-13  
第一个例子中在构造函数中创建的函数,很多javascript的书都说这样创建的每个对象都有自己的函数版本,比如这里的Light的每个对象都有自己的turnOn,楼主说“JavaScript 没傻到给每个对象都真去分配一个函数的地步“,这一点如何证明?
2 楼 charon 2007-06-13  
貌似很多开源包和很多人都实现了自己的extends/mixins或者类似的方法.有些在里面还干了一些非常magic的事情。

这个,大概是用基于prototype的语言来实现这些东西的困惑巴。因为没有在语言级别提供直接的支持,于是大家都百花齐放,或者说的难听一点就是各奔东西了。直接的结果是某些开源包互相之间有冲突,不能拿来一齐使用(我有近半年没用过javascript了,或者现状已经改变了?社区有了大一统的做法?)

另外,这里还差一个多态的实现,虽然简单,但称不上优雅。也一齐补全了吧
1 楼 sp42 2007-06-12  
lz好样的
E语言sounds good

相关推荐

    JavaScript语言的特性和应用.pdf

    1. 基于对象的脚本语言:JavaScript 是一种基于对象的脚本语言,面向对象的程序设计(OOP)技术由五个最基本的概念组成:对象、消息、方法、类和继承。 2. 对象的组成:JavaScript 对象由两部分组成:属性...

    EX OOP 编程

    在实际编程中,OOP被广泛应用于各种语言,如Java、C++、Python、JavaScript等。JavaScript中的OOP主要是基于原型的,但在ES6引入了类的概念后,其语法更接近于传统的类式OOP。在`extoop.js`和`test.js`中,我们可以...

    Object-oriented-javascript

    鉴于面向对象编程在JavaScript中的实现与传统语言如Java或C++有所不同,书中可能还会介绍JavaScript特有的OOP特性,如原型继承、对象字面量、工厂模式以及后来的ES6新增的类语法等。 由于内容片段包含了版权声明和...

    悟透JavaScript javascript 圣经

    提到JavaScript的面向对象编程(OOP),它不同于传统的类为基础的OOP,而是基于原型的。在JavaScript中,对象可以直接从其他对象继承属性和方法,无需预先定义类。对象的属性和方法可以动态添加,这提供了很大的灵活...

    高级语言的分类.txt

    面向对象编程(Object-Oriented Programming, OOP)引入了类和对象的概念,以提高代码的复用性和可维护性。Java、C++和Python都是广为人知的面向对象语言。它们允许开发者创建和管理对象,封装数据和方法,实现继承...

    javaScript小游戏

    JavaScript小游戏是一种利用JavaScript编程语言开发的互动娱乐应用。JavaScript,简称JS,是Web开发中不可或缺的一部分,主要用于网页和网络应用的动态化。由于其轻量级、解释型和跨平台的特性,使得JavaScript成为...

    matlab中绿色的代码什么意思-JavaScriptOOP:如何以及何时在JavaScript中使用OOP?

    另一个指标是TypeScript的出现,TypeScript是Microsoft编写的JS的超集,并支持OOP功能:类,名称空间,模块,静态类型,泛型。 在这个简短的概述中,我将回答问题:如何,为什么以及何时在JavaScript中使用OOP? ...

    tetris:使用OOP JavaScript和React构建的俄罗斯方块,可在控制台和浏览器中播放

    《使用OOP JavaScript和React构建俄罗斯方块游戏的探索》 在编程世界中,经典游戏“俄罗斯方块”常被用作学习新语言或技术的示例。本项目,名为“tetris”,就是一个利用面向对象编程(OOP)的JavaScript和React...

    由浅到深了解JavaScript类.doc

    尽管JavaScript的类机制与传统面向对象语言有所不同,但通过构造函数、原型链等方式,依然能够实现强大的面向对象编程特性。未来的学习过程中,我们还可以进一步探索继承、封装等更高级的概念,以提升我们的编程技能...

    sloop:S语言OOP:sailboat:

    标题 "sloop:S语言OOP:sailboat:" 指涉的是一个关于S语言(主要是R语言)面向对象编程(Object-Oriented Programming, OOP)的项目或库,名为"Sloop",可能寓意其像帆船一样引导开发者在R的OOP海洋中航行。...

    oop-game-show-app:团队树屋全栈JavaScript技术学位的第四个项目

    在OOP Game Show App中,JavaScript的面向对象特性将被用于组织代码,创建类和对象,以及实现游戏逻辑。 **可能涉及的知识点:** 1. **JavaScript基础**:变量、数据类型、操作符、流程控制、函数、闭包等。 2. **...

    用英文写一篇短文介绍计算机语言的发展历史和特点,要求简单介绍机器语言、汇编语言、高级语言的简单发展历程和各自的特点。

    例如,JavaScript作为一种脚本语言,不仅应用于网页,还可以在服务器端运行,实现了前后端的统一。而像Go、Rust这样的新语言,则是为了应对多核处理器时代而设计,优化了并发和内存管理。 总的来说,计算机语言从...

    javascript面向对象

    3. **ES6类语法**:现代JavaScript提供了更接近传统面向对象语言的类语法,使得定义类和创建对象更加直观。例如: ```javascript class Person { constructor(name, age) { this.name = name; this.age = age; ...

    javascript 100li

    JavaScript,简称为JS,是一种广泛应用于网页和网络应用开发的轻量级编程语言。它主要负责处理客户端的交互,使得网页具有动态性与用户交互性。JavaScript与PHP都是Web开发中的重要工具,但它们在职责上有所不同:...

    JavaScript面向对象编程

    在JavaScript中,面向对象编程通过原型继承和类的概念实现,尽管ES6及更高版本引入了更接近传统OOP语言风格的类语法。 ##### 2.1 对象构造器 在JavaScript中创建对象的一种方式是使用对象构造函数。构造函数本质上...

    javascript 经典面向对象设计

    标题“JavaScript经典面向对象设计”指出了本书的主要内容是关于如何使用面向对象编程(OOP)原则和技术来编写高质量、可扩展且可重用的JavaScript应用程序及库。描述中提到本书相比其他中文资料更为清晰,深入到...

    javascript 高级程序设计

    - **面向对象编程**:理解类、继承、封装、多态等OOP原则在JavaScript中的实现方式。 - **异步编程**:熟悉回调函数、Promise、async/await等处理异步操作的技术。 #### Web开发技术 2. **HTML与JavaScript交互*...

Global site tag (gtag.js) - Google Analytics