原型
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,通常被称为JS Garden,是一个在线资源,旨在帮助开发者理解和规避JavaScript中的常见陷阱和微妙之处。这个项目是由Bodo Tasche创建的,它详细解释了JavaScript语言的一些复杂性和不直观的行为,...
JavaScript使用原型链实现对象继承,每个对象都有一个`__proto__`属性,指向其构造函数的原型。通过`Object.create()`或`prototype`可以创建继承关系。 7. **异步编程**: JavaScript的异步处理主要依靠回调函数...
Ruby 以其简洁、易读的语法而闻名,适合快速开发和原型设计。它的动态类型特性使得开发过程更为灵活,但同时也可能导致一些运行时错误。 从压缩包的文件名 "rails-garden-manager-master" 来看,这可能是项目的主...
JavaScript的原型链机制允许对象通过原型链继承其他对象的属性和方法。每个对象都有一个指向其原型对象的内部链接。当试图访问一个对象的属性时,如果该属性不存在于当前对象,JavaScript引擎会沿着原型链向上查找,...
1. **基础概念**:变量、数据类型、作用域、闭包、原型链、this指向等JavaScript基础。 2. **函数**:函数表达式、高阶函数、箭头函数、函数参数默认值和解构赋值等。 3. **数组和对象操作**:包括遍历、查找、...
JavaScript是一种解释型的、弱类型的、基于原型的脚本语言,它具有动态类型、函数作为一等公民的特性。在"my-garden"项目中,JavaScript可能用于处理用户的交互,比如点击按钮种植花朵、移动植物、调整花园布局等。 ...
2. **面向对象编程**:类与对象的概念,原型链,继承,封装,多态等。 3. **DOM操作**:如何使用JavaScript来操作文档对象模型(DOM),包括选择元素、添加删除元素、改变元素内容和样式等。 4. **事件处理**:...
在lab_garden项目中,JavaScript可能用于创建一个Web应用,让用户可以通过网络远程查看和控制花园的灌溉设置。这显示了物联网(IoT)技术的应用,将物理世界与互联网连接起来。 在"lab_garden-master"这个压缩包中...
在压缩包文件名"garden-main"中,“main”通常代表项目的主目录或主要代码库,这可能包含了网站的源代码、样式表(CSS)、脚本(JavaScript)以及其他必要的资源文件。开发者可能使用了现代化的前端框架(如React、...
:house_with_garden:】这个标题可能指的是一个个人网站或博客,其中“回家”可能意味着访问者回到了该网站的主页或者作者的个人空间。GitHub Pages常用于托管这样的个人项目,它允许用户通过GitHub仓库发布静态网页...
рус" 是俄文,直译为 "garden service" 或 "园艺服务",进一步确认了这是一个专注于园艺服务的在线平台。该平台可能是提供园艺维护、设计、咨询等服务的中心。 标签 "HTML" 提示我们这个项目的核心技术是超文本...