JavaScript的类和继承

只谈情不闲聊 提交于 2020-01-24 15:04:46

本文参考了两本书:

<JavaScript: The Good Parts>(JSTGP) by Douglas Crockford

<JavaScript Web Application> (JSWA) by maccman

如何在JavaScript中使用”类“,W3CSHOOL提供了一个貌似不错的解决方案,也就是所谓的PseduoClassical范式:

var Person = function (opt) {
opt = opt ? opt : {};
this.name = opt.name;
};
Person.prototype.hello = function() {
console.log("hello, I'm " + this.name);
};
 
var Programmer = function (opt) {
opt = opt ? opt : {};
Person.apply(this, arguments);
this.language = opt.language;
};
Programmer.prototype = new Person();
Programmer.prototype.coding = function() {
console.log("I'm coding with " + this.language);
};
 
var lucy = new Person({name: "lucy"});
lucy.hello();
var jack = new Programmer({name: "jack", language: "JavaScript"});
jack.hello();
jack.coding();

一切都很熟悉,类有了,继承也很明朗。只是你可能感到疑惑,

*为什么一个类要使用function关键字来定义呢?

*这一句:Programmer.prototype = new Person(); 显得有些别扭,它是如何实现继承关系的?

这是因为,new操作符实际上是JavaScript对面向对象程序员的一种妥协。它做的工作,就是,以Function的prototype为模板创建并返回一个新对象。在JSTGP的Function一章里,给出了如果new的方法实现版本:

Function.prototype.new = function() {
    var that = Object.create(this.prototype);
    var object = this.apply(that, arguments);
    return (object && typeof object === 'object') ? object : that; //如果你用来定义“类”的function有返回值,那么返回该值,一般你不会这么做
};
...
var lucy = Person.new({name: "lucy"});

为什么用function关键字来定义类呢?实际上初学者有一个误区,对prototype chain的误解,看看下面的代码:

var lucy = Person.new({name: "lucy"});
lucy.hello();
var nobody = {};
nobody.prototype = lucy;
nobody.hello();TypeError: Object #<Object> has no method 'hello'

这段代码的问题就是,认为prototype是对象的一个属性,设置了prototype之后,nobody的hello方法就会向上寻址。实际上,prototype是function的一个属性,而它的存在,只是为了上文提到的new操作的抽象。虽然可以说,JavaScript的new操作大致上像其他语言一样是按照模板来创建实例。但是一个显著的不同是,例如c#,一个新对象必须通过new创建,而JavaScript则不然,在上例中,是通过Object.create创建的,而new操作反而是一个语法糖(Sugar),另外,你也能够很容易的通过var a = {};这样的语句来创建一个对象。

JavaScript是一种Prototype Based Language,而不是Class Based Language。本质区别是,Class Based Language的类是静态的,也就是说,一个对象的能力是静态的,而Prototype Based Language的对象的能力是动态的。可以说,JavaScript天然没有类,因而天然没有继承。而JSTGP更是指出,new是JavaScript设计中的缺陷,不要使用new。下面介绍Functional范式,在不使用new的情况下,提供对象模板:

var person = function (name) {
    var that = {};
    that.sayHello = function () {
        console.log("Hello, my name is " + name);
    };
    return that;
};

var programmer = function (name, language) {
    var that = person(name);
    that.code = function () {
        console.log("I'm coding with " + language);
    };
    return that;
};

这种范式有一个好处,就是可以拥有私有成员,因为定义的方法可以访问函数作用域;而一个不好的地方就是,它的每个实例都会有自己的独立的方法,造成了内存的比较大的消耗。

 但是面向对象的概念有助于大型软件的开发,在下一篇文章里,我们将讨论一种巧妙的范式,在不使用别扭的new的情况下,提供明朗的类和继承。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!