[译]JavaScript需要类吗?

 

原文:http://www.nczonline.net/blog/2012/10/16/does-javascript-need-classes/


译者注:在我长达一年的工作生涯中,我遇到过有人把构造函数称做类,还有人把对象字面量称做类.这比把火狐扩展叫成插件都令我*疼.下面是Brendan Eich给今年的jsconf.eu录制的视频,其中提到了类.


无论你喜欢还是不喜欢,ECMAScript 6中将会包含类(class)这个新东西了[1].在JavaScript中,对类的需求一直都有两极分化的趋势.有些人特别喜欢JavaScript中没有类,因为这和其他语言不同.另一方面,还有一些人厌恶JavaScript没有类,因为这和其他语言不同.那些从C++或Java转到JavaScript的人们最需要克服的一个心理障碍就是"JavaScript中没有类",有些人和我说过,这就是他们为什么不喜欢Javascript或者不继续深入学习Javascript的原因之一.

JavaScript从发明的那天起就没有真正的类,这使得从一开始就造成了混乱.有不少JavaScript书籍或文章中都讲到了类,就好像JavaScript中真的存在类一样.但其实,他们所说的类只是一些自定义的构造函数,这些函数可以用来构造一些自定义的引用类型.在JavaScript中,引用类型已经是最接近于类的东西了.下面的代码你应该已经很熟悉了:

function MyCustomType(value) {
this.property = value;
} MyCustomType.prototype.method = function() {
return this.property;
};

很多时候,这种代码被解释为是声明了一个MyCustomType类.但实际上,该代码做的所有事情仅仅是声明了一个MyCustomType函数,配合new运算符可以用它创建一个引用类型MyCustomType的实例.该函数和其他的函数并没有什么本质的不同.因为其他自定义的函数也可以作为构造函数来使用.

这样的代码从表面上看起来根本不像是在定义一个类,被定义的构造函数和其原型对象上的方法似乎没有什么联系.如果是JavaScript新手,很可能会认为这是两段完全无关的代码.但实际上,这两段代码有非常紧密的联系,只是和其他语言中的类的写法相差甚远罢了.

更令人困惑的是,一旦谈到继承,大部分人想到的术语是子类和超类等等,这样的概念只有在存在真正的类的前提下才有意义.在JavaScript中,实现继承的代码同样是冗长的:

function Animal(name) {
this.name = name;
} Animal.prototype.sayName = function() {
console.log(this.name);
}; function Dog(name) {
Animal.call(this, name);
} Dog.prototype = new Animal(null);
Dog.prototype.bark = function() {
console.log("Woof!");
};

实现继承需要两个步骤,创建构造函数和重写原型对象,这样的代码非常混乱.

在第一版的《JavaScript高级程序设计》中,我使用过术语"类".但从我收到的反馈中看,这样写是很令人困惑的.所以在第二版中,我把所有的"类(class)"都替换成了"类型(type)".事实表明,使用"类型"这个术语可以减少很多的混乱.

可是,还有一个比较突出的问题:定义一个自定义类型的语法是冗长的,实现两个类型之间的继承会更加复杂.没有什么简单的方法可以调用一个属于超类型的方法.在目前看来,创建并管理一个自定义类型是件很痛苦的事,如果你不信,可以看看有下面有多少JavaScript框架使用了自己的定义自定义类型和继承的方法:

  • YUI – 用Y.extend()来实现继承.使用该方法会在子类型上添加一个"superclass"属性.[2]
  • Prototype – 用Class.create()和Object.extend()来处理对象和"类".[3]
  • Dojo – 使用dojo.declare()和dojo.extend().[4]
  • MooTools – 有一个自定义类型Class,可以用来定义和扩展"类".[5]

这么多的JavaScript框架都有自己的解决方案,这明显是非常混乱的.JavaScript开发者们需要一种更好的实现此功能的语法.

ECMAScript 6中的类其实并没有什么新东西,只是在你已经熟悉的模式上增加了一层语法糖.看看下面这个例子:

class MyCustomType {
constructor(value) {
this.property = value;
} method() {
return this.property;
}
}

这个ECMAScript 6中的类定义其实就是本文上面那个MyCustomType例子的另一种写法.使用这种类创建的对象实例完全和使用构造函数创建的对象实例一样.唯一的区别就是前者拥有更紧凑的语法.下面看看继承的写法:

class Animal {
constructor(name) {
this.name = name;
} sayName() {
console.log(this.name);
}
} class Dog extends Animal {
constructor(name) {
super(name);
} bark() {
console.log("Woof!");
}
}

在实际效果上这个例子也同样等同于前面那种继承的写法.只是复杂的实现步骤被一个简单的extends关键字代替了.在类定义中你还可以直接使用super(),无需明确指出超类型的构造函数.

ECMAScript 6中的类是基于你已经熟知的JavaScript模式.实现继承的原理还和以前一样(基于原型链,调用超类型的构造函数),方法添加在原型上,属性在构造函数中声明.真正的区别只有一个:你可以打更少的字.

所以,如果你现在仍然不赞同ECMAScript 6引入类这么个东西,你可以这么想,要引入的这个类不是什么新东西,也并没有从根本上改变JavaScript的工作机制.不过我个人更推荐使用关键字type而不是class.

那么JavaScript真的需要类吗?答案是不需要,但JavaScript的确需要一个更简洁的方法来创建自定义类型.这恰巧就是ECMAScript 6中的"类"正要做的.如果这个"类"能帮助来自其他语言的开发者们更容易的转向JavaScript,那么它就是好东西.

参考

  1. Maximally minimal classes (ECMA)
  2. YUI extend() (YUILibrary)
  3. Prototype Classes and Inheritance (Prototype)
  4. Creating and Enhancing Dojo Classes (SitePen)
  5. MooTools Class (MooTools)

[译]JavaScript需要类吗?的更多相关文章

  1. 详解javascript的类

    前言 生活有度,人生添寿. 原文地址:详解javascript的类 博主博客地址:Damonare的个人博客 Javascript从当初的一个"弹窗语言",一步步发展成为现在前后端 ...

  2. Javascript定义类(class)的三种方法

    将近20年前,Javascript诞生的时候,只是一种简单的网页脚本语言.如果你忘了填写用户名,它就跳出一个警告. 如今,它变得几乎无所不能,从前端到后端,有着各种匪夷所思的用途.程序员用它完成越来越 ...

  3. Atitit.javascript 实现类的方式原理大总结

    Atitit.javascript 实现类的方式原理大总结 1. 实现类的式::构造方法方式:原型方式:构造方法+原型的混合方式 1 2. 原型方式(function mode)经典式..实现属性推荐 ...

  4. [转]Javascript定义类的三种方法

    作者: 阮一峰 原文地址:http://www.ruanyifeng.com/blog/2012/07/three_ways_to_define_a_javascript_class.html 将近2 ...

  5. javascript 定义类(转载)

    Javascript本身并不支持面向对象,它没有访问控制符,它没有定义类的关键字class,它没有支持继承的extend或冒号,它也没有用来支持虚函数的virtual,不过,Javascript是一门 ...

  6. javascript定义类和类的实现

    首先说说类,在一个类里我们会有以下的几个特征: 1. 公有方法 2. 私有方法 3. 属性 4. 私有变量 5. 析构函数 我们直接看一个例子: /***定义类***/ var Class = fun ...

  7. javascript创建类的6种方式

    javascript创建类的7种方式 一 使用字面量创建 1.1 示例 var obj={}; 1.2 使用场景 比较适用于临时构建一个对象,且不关注该对象的类型,只用于临时封装一次数据,且不适合代码 ...

  8. JavaScript一个类继承中实现

    JavaScript类是默认原型对象继承: var Person = function() { this.name = "people"; this.hello = functio ...

  9. Javascript创建类和对象

    现总结一下Javascript创建类和对象的几种方法: 1.原始的创建方法: <script type="text/javascript"> var person = ...

随机推荐

  1. flume jetty 进程关系 flume jetty 跨域问题 jetty 源码分析

    flume  jetty  跨域问题 13481 httpSource的端口进程号 = flume 启动后的进程号 [root@c log]# netstat -atp Active Internet ...

  2. ruamel.yaml 将字典写入yaml文件

    #安装 pip install ruamel.yaml import os from ruamel import yaml # 将字典写入到yaml my_dic = { 'name': '张三', ...

  3. 单例Singleton模式的两种实现方法

    在设计模式中,有一种叫Singleton模式的,用它可以实现一次只运行一个实例.就是说在程序运行期间,某个类只能有一个实例在运行.这种模式用途比较广泛,会经常用到,下面是Singleton模式的两种实 ...

  4. shell调用python脚本,并且向python脚本传递参数

    1.shell调用python脚本,并且向python脚本传递参数: shell中: python test.py $para1 $para2 python中: import sys def main ...

  5. java-mybaits-00601-查询缓存-一级缓存、二级缓存

    1.什么是查询缓存 mybatis提供查询缓存,用于减轻数据压力,提高数据库性能. mybaits提供一级缓存,和二级缓存. 一级缓存是SqlSession级别的缓存. 在操作数据库时需要构造 sql ...

  6. java-mybaits-00502-案例-映射分析-一对一、一对多、多对多

    1.一对一查询[类属性即可,association ] 案例:查询所有订单信息,关联查询下单用户信息.   注意:因为一个订单信息只会是一个人下的订单,所以从查询订单信息出发关联查询用户信息为一对一查 ...

  7. java 多线程 day11 lock

    import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock; /** * Create ...

  8. 聊一聊 Django 中间件

    Django默认的Middleware有七个: MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.cont ...

  9. python全栈开发从入门到放弃之socket并发编程之协程

    一.为什么会有协程 本节的主题是基于单线程来实现并发,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发,为此我们需要先回顾下并发的本质:切换+保存状态 cpu正在运行一个任务,会在两种情 ...

  10. idea打jar包-MapReduce作业提交到hadoop集群执行

    https://blog.csdn.net/jiaotangX/article/details/78661862 https://liushilang.iteye.com/blog/2093173