`

JavaScript Garden - 原型

阅读更多

原型

JavaScript 不包含传统的类继承模型,而是使用 prototypal 原型模型。

虽然这经常被当作是 JavaScript 的缺点被提及,其实基于原型的继承模型比传统的类继承还要强大。
实现传统的类继承模型是很简单,但是实现 JavaScript 中的原型继承则要困难的多。
(It is for example fairly trivial to build a classic model on top of it, while the
other way around is a far more difficult task.)

由于 JavaScript 是唯一一个被广泛使用的基于原型继承的语言,所以理解两种继承模式的差异是需要一定时间的。

第一个不同之处在于 JavaScript 使用原型链的继承方式。

注意: 简单的使用 Bar.prototype = Foo.prototype 将会导致两个对象共享相同的原型。
因此,改变任意一个对象的原型都会影响到另一个对象的原型,在大多数情况下这不是希望的结果。

function Foo() {
    this.value = 42;
}
Foo.prototype = {
    method: function() {}
};

function Bar() {}

// 设置Bar的prototype属性为Foo的实例对象
Bar.prototype = new Foo();
Bar.prototype.foo = 'Hello World';

// 修正Bar.prototype.constructor为Bar本身
Bar.prototype.constructor = Bar;

var test = new Bar() // 创建Bar的一个新实例

// 原型链
test [Bar的实例]
    Bar.prototype [Foo的实例] 
        { foo: 'Hello World' }
        Foo.prototype
            {method: ...};
            Object.prototype
                {toString: ... /* etc. */};

*
上面的例子中,test 对象从 Bar.prototype 和 Foo.prototype 继承下来;因此,
它能访问 Foo 的原型方法 method。它也同时能够访问那一个作为它原型的 Foo 实例
的属性 value。需要注意的是 new Bar() 不会创造出一个新的 Foo 实例,而是
重新使用设定为它的原型的实例;也就是说,所有的 Bar 实例都将会有同样的 value 属性。

注意: 不要使用 Bar.prototype = Foo,因为这不会执行 Foo 的原型,而是指向函数 Foo
因此原型链将会回溯到 Function.prototype 而不是 Foo.prototype,因此 method 将不会在 Bar 的原型链上。

属性查找

当查找一个对象的属性时,JavaScript 会向上遍历原型链,直到找到给定名称的属性为止。

到查找到达原型链的顶部 - 也就是 Object.prototype - 但是仍然没有找到指定的属性,就会返回 undefined

原型属性

当原型属性用来创建原型链时,可以把任何类型的值赋给它(prototype)。
然而将原子类型赋给 prototype 的操作将会被忽略。

function Foo() {}
Foo.prototype = 1; // 无效

而将对象赋值给 prototype,正如上面的例子所示,将会动态的创建原型链。

性能

如果一个属性在原型链的上端,则对于查找时间将带来不利影响。特别的,试图获取一个不存在的属性将会遍历整个原型链。

并且,当使用 for in 循环遍历对象的属性时,原型链上的所有属性都将被访问。

扩展内置类型的原型

一个错误特性被经常使用,那就是扩展 Object.prototype 或者其他内置类型的原型对象。

这种技术被称之为 monkey patching 并且会破坏封装。虽然它被广泛的应用到一些 JavaScript 类库中比如 Prototype,
但是我仍然不认为为内置类型添加一些非标准的函数是个好主意。

扩展内置类型的唯一理由是为了和新的 JavaScript 保持一致,比如 Array.forEach

译者注这是编程领域常用的一种方式,称之为 Backport,也就是将新的补丁添加到老版本中。

总结

在写复杂的 JavaScript 应用之前,充分理解原型链继承的工作方式是每个 JavaScript 程序员必修的功课。
要提防原型链过长带来的性能问题,并知道如何通过缩短原型链来提高性能。
更进一步,绝对不要扩展内置类型的原型,除非是为了和新的 JavaScript 引擎兼容。

分享到:
评论

相关推荐

    Javascript Garden 网页的静态文件

    JavaScript Garden,通常被称为JS Garden,是一个在线资源,旨在帮助开发者理解和规避JavaScript中的常见陷阱和微妙之处。这个项目是由Bodo Tasche创建的,它详细解释了JavaScript语言的一些复杂性和不直观的行为,...

    javascript secrit garden

    JavaScript使用原型链实现对象继承,每个对象都有一个`__proto__`属性,指向其构造函数的原型。通过`Object.create()`或`prototype`可以创建继承关系。 7. **异步编程**: JavaScript的异步处理主要依靠回调函数...

    rails-garden-manager

    Ruby 以其简洁、易读的语法而闻名,适合快速开发和原型设计。它的动态类型特性使得开发过程更为灵活,但同时也可能导致一些运行时错误。 从压缩包的文件名 "rails-garden-manager-master" 来看,这可能是项目的主...

    JavaScript 秘密花园.pdf

    JavaScript的原型链机制允许对象通过原型链继承其他对象的属性和方法。每个对象都有一个指向其原型对象的内部链接。当试图访问一个对象的属性时,如果该属性不存在于当前对象,JavaScript引擎会沿着原型链向上查找,...

    javascript_garden:javascript后花园-算法之路

    1. **基础概念**:变量、数据类型、作用域、闭包、原型链、this指向等JavaScript基础。 2. **函数**:函数表达式、高阶函数、箭头函数、函数参数默认值和解构赋值等。 3. **数组和对象操作**:包括遍历、查找、...

    my-garden

    JavaScript是一种解释型的、弱类型的、基于原型的脚本语言,它具有动态类型、函数作为一等公民的特性。在"my-garden"项目中,JavaScript可能用于处理用户的交互,比如点击按钮种植花朵、移动植物、调整花园布局等。 ...

    digital-garden

    2. **面向对象编程**:类与对象的概念,原型链,继承,封装,多态等。 3. **DOM操作**:如何使用JavaScript来操作文档对象模型(DOM),包括选择元素、添加删除元素、改变元素内容和样式等。 4. **事件处理**:...

    lab_garden:苏创新实验室自浇花园

    在lab_garden项目中,JavaScript可能用于创建一个Web应用,让用户可以通过网络远程查看和控制花园的灌溉设置。这显示了物联网(IoT)技术的应用,将物理世界与互联网连接起来。 在"lab_garden-master"这个压缩包中...

    garden:有趣的小网站即将推出

    在压缩包文件名"garden-main"中,“main”通常代表项目的主目录或主要代码库,这可能包含了网站的源代码、样式表(CSS)、脚本(JavaScript)以及其他必要的资源文件。开发者可能使用了现代化的前端框架(如React、...

    pratiknilange.github.io:回家! :house_with_garden:

    :house_with_garden:】这个标题可能指的是一个个人网站或博客,其中“回家”可能意味着访问者回到了该网站的主页或者作者的个人空间。GitHub Pages常用于托管这样的个人项目,它允许用户通过GitHub仓库发布静态网页...

    gardenservice

    рус" 是俄文,直译为 "garden service" 或 "园艺服务",进一步确认了这是一个专注于园艺服务的在线平台。该平台可能是提供园艺维护、设计、咨询等服务的中心。 标签 "HTML" 提示我们这个项目的核心技术是超文本...

Global site tag (gtag.js) - Google Analytics