js 对象继承_JS对象:继承了混乱

js 对象继承

JS对象:TL; DR (JS Objects: TL;DR)

JavaScript has been plagued since the beginning with misunderstanding and awkwardness around its "prototypal inheritance" system, mostly due to the fact that "inheritance" isn't how JS works at all, and trying to do that only leads to gotchas and confusions that we have to pave over with user-land helper libs. Instead, embracing that JS has "behavior delegation" (merely delegation links between objects) fits naturally with how JS syntax works, which creates more sensible code without the need of helpers.

从一开始,JavaScript就一直困扰着其“原型继承”系统,人们对其产生了误解和尴尬,这主要是由于“继承”根本不是JS的工作原理,而试图做到这一点只会导致我们陷入困境和困惑。必须铺平用户土地的帮助库。 相反,认为JS具有“行为委托”(仅是对象之间的委托链接)自然符合JS语法的工作原理,从而无需帮助者即可创建更明智的代码。

When you set aside distractions like mixins, polymorphism, composition, classes, constructors, and instances, and only focus on the objects that link to each other, you gain a powerful tool in behavior delegation that is easier to write, reason about, explain, and code-maintain. Simpler is better. JS is "objects-only" (OO). Leave the classes to those other languages!

当您搁置诸如混合包,多态性,组成,类,构造函数和实例之类的干扰,仅关注彼此链接的对象时,您将获得行为委托中的强大工具,该工具易于编写,推理,解释,和代码维护。 越简单越好。 JS是“仅对象”(OO)。 将课程留给其他语言!

由于感谢 (Due Thanks)

I'd like to thank the following amazing devs for their generous time in feedback/tech review of this article series: David Bruant, Hugh Wood, Mark Trostler, and Mark McDonnell. I am also honored that David Walsh wanted to publish these articles on his fantastic blog.

我要感谢以下出色的开发者在本文系列的反馈/技术评论中所花的大量时间:David Bruant,Hugh Wood,Mark Trostler和Mark McDonnell。 我也很荣幸David Walsh希望将这些文章发布在他的博客上。

完整系列 (Complete Series)

year 2013: Haskell people are still writing monad tutorials, JavaScript people are still trying to explain inheritance.

2013年:Haskell人仍在编写monad教程,JavaScript人仍在尝试解释继承。

— Vyacheslav Egorov (@mraleph) April 12, 2013

— Vyacheslav Egorov(@mraleph) 2013年4月12日

As sad a criticism on JS as that quote is, it's quite true. (I have no perspective on Haskell or Monads, so I'm only talking about the JS and inheritance part). Of all the confusing and, depending on your biases, "bad", parts of this JS language, the behaviors of this and the [[Prototype]] chain have remained some of the most elusive to explain and use accurately.

引用那句对JS的批评感到可悲,这的确是事实。 (我对Haskell或Monads没有任何见解,所以我只在谈论JS和继承部分)。 所有的混乱和,取决于你的偏见,“坏”,这JS语言的部分,的行为, this[[Prototype]]链一直保持一些最难以捉摸的解释和正确使用。

As a bit of background, I've been developing JS full time since 2007. The first major epiphany I had back then was the understanding of how closures work, and how they enable the classic module pattern. The first open-source project I wrote (early 2008) was flXHR, a cross-domain Ajax prollyfill using the standard Ajax (XHR) interface (via a hidden flash element) that relied heavily upon the module pattern.

作为背景,我从2007年开始就全职开发JS。那时我的第一个主要顿悟是了解闭包如何工作以及它们如何启用经典模块模式。 我写的第一个开源项目(2008年初)是flXHR ,这是一个使用标准Ajax(XHR)接口(通过隐藏的Flash元素)的跨域Ajax prollyfill ,它严重依赖于模块模式。

It's quite possibly my "ah-ha!" moment around the module pattern that satisfied me enough that I never really felt a strong need to also apply the "inheritance" pattern to my JS design.

很可能是我的“啊哈!” 围绕模块模式的那一刻让我非常满意,以至于我从没有真正感到强烈需要将“继承”模式应用于我的JS设计。

Nevertheless, like most JS developers, I've read lots of blogs and books over the years that have tried (and mostly failed) to explain the appeal and mystery that is "JavaScript inheritance" (aka, "prototypal inheritance").

但是,像大多数JS开发人员一样,多年来,我已经阅读了许多博客和书籍,这些博客和书籍试图(而且大多失败了)来解释“ JavaScript继承”(又称为“原型继承”)的吸引力和奥秘。

But if it's so hard to understand, and even harder to actually do correctly, the point yet eludes me. And apparently I'm not alone in that frustration.

但是,如果很难理解,甚至很难正确地做正确的事,那么这一点仍然无法理解。 显然,我并不孤单。

JavaScript中的OO (OO in JavaScript)

In traditional Object-oriented languages, the syntax of classes matches the semantics. You can express the object-oriented concepts of classes, inheritance, and polymorphism directly and explicitly using the language's syntax. There's no need to use some helper library to fake your way into OO-like behavior through work-arounds of other language facilities.

在传统的面向对象语言中语法与语义匹配。 您可以使用语言的语法直接明确地表达面向对象的类,继承和多态性的概念。 无需使用其他其他语言工具的变通办法,就可以使用一些帮助程序库来伪装成类似OO的行为。

JavaScript on the other hand has a set of syntax that looks somewhat OO, but which behaves in frustratingly different ways (which we will cover throughout this article series). As a result, the common way that you implement OO patterns in JS is through any of a variety of user-land helper libraries which let you express the desired semantic relationships between your "objects". The reason most JS developers use them is because the underlying JS syntax makes those semantic expressions awkward. It's nice to just let a library handle paving over the confusing syntax hiccups.

另一方面,JavaScript 的语法有点象OO ,但是表现却令人沮丧地不同(我们将在本系列文章中介绍)。 结果,在JS中实现OO模式的常见方式是通过各种用户界面帮助程序库中的任何一种,这些库可让您表达“对象”之间所需的语义关系。 大多数JS开发人员使用它们的原因是因为基本的JS语法使这些语义表达式尴尬。 只是让一个库来处理令人困惑的语法错误,这是很好的。

Libraries like jQuery are useful because they hide the ugly details of dealing with cross-browser differences in JS engines. But these OO-helper libraries are different: they're going to great lengths to hide the true nature of JavaScript's OO mechanisms, instead masking them in a set of patterns that are more familiar to other languages.

jQuery之类的库非常有用,因为它们隐藏了处理JS引擎中跨浏览器差异的丑陋细节。 但是这些OO-helper库是不同的:它们将竭尽全力隐藏JavaScript OO机制的真正本质 ,而不是以其他语言更熟悉的一组模式来掩盖它们。

At this point of understanding, we should really ask ourselves: is the difficulty of expressing classes and inheritance in pure JavaScript a failure of the language (one which can temporarily be solved with user librariesand ultimately solved by additions to the language like class { .. } syntax), as many devs feel, or is it something deeper? Is it indicative of a more fundamental disparity, that we're trying to do something in JS that it'sjust not meant to do?

在理解这一点时,我们应该真正地问自己: 纯JavaScript表达类和继承的困难是该语言的一种失败(可以通过 用户库 临时 解决 ,最终通过添加class { .. }的语言来解决) class { .. }语法),或者像许多开发人员所感觉到的更深? 这是否表明存在更根本的差异,我们试图在JS做一些本来不应该做的事情

Not everyone drank the JS classes kool-aid, so the rest of this article series will favor a different perspective.

并非每个人都喝过JS类kool-aid,因此本系列文章的其余部分将倾向于不同的观点。

蓝图 (Blueprint)

One of the most common metaphors used in traditional class/inheritance OO is that the class represents a "blueprint" for a house to be built, but once you instantiate that class, you are basically copying all the characteristics from the blueprint into the actual built house. This metaphor partially matches, to an extent, what actually happens at a language level when the code is compiled, in that it sort-of flattens the definition of a class (sans "virtual" methods) inheritance hierarchy into the instance.

传统类/继承OO中使用的最常见的隐喻之一是, 该类表示要建造房屋的“蓝图” ,但是实例化该类后,基本上就是将所有特征从蓝图复制到实际建造的房屋中。屋。 这个隐喻在某种程度上与代码在编译时在语言级别上实际发生的情况相匹配,这是因为它将某种类(没有“虚拟”方法)继承层次结构的定义整理到实例中。

Of course, a main pillar of inheritance-oriented coding is overriding and polymorphism, which allows an object toautomatically access the most descendant definition for a method, but also to use super-style relative references to access ancestor (aka "virtual") versions of the same-named method. In those cases, the compiler maintains lookup tables for the virtual methods, but it flattens out the non-virtual parts of the class/inheritance definition. The compiler can determine a lot about what needs to be preserved and not and highly optimize the definition structure it creates in the compiled code.

当然, 面向继承的编码的主要Struts是覆盖和多态性 ,它允许对象自动访问方法的最新派系定义,但也可以使用super样式相对引用来访问祖先(也称为“虚拟”)版本同名方法。 在那些情况下,编译器会维护虚拟方法的查找表,但是会拼凑类/继承定义的非虚拟部分。 编译器可以确定哪些内容需要保留,哪些不需要保留,并可以高度优化其在编译代码中创建的定义结构。

For our purposes, we can think of traditional class-inheritance as basically a flattening "copy" of behavior down the chain to the instance. Here's a diagram to illustrate the inheritance relationship between a parent/base classFoo, and child class Bar, and then instances of each, respectively named foo1foo2bar1, andbar2. Visually, the arrows (aka, "copying") point from left-to-right and top-to-bottom:

出于我们的目的,我们可以将传统的类继承视为从行为链到实例的扁平化“复制”行为。 这是说明父/基类Foo和子类Bar之间的继承关系的图,然后分别说明它们的实例,分别命名为foo1foo2bar1bar2 。 在视觉上,箭头(又名“复制”)从左到右和从上到下指向:

Inheritance Arrows

名字叫什么? (What's in a name?)

Despite the borrowed implications of the common name "prototypal inheritance", JavaScript's mechanism works quite differently, which we'll see in just a moment.

尽管借用了通用名称“原型继承”的含义,但JavaScript的机制却大不相同,我们稍后会看到。

Both definitionally ("...characteristics transmitted from parent to offspring") and behaviorally (as described above), "inheritance" is most closely associated with the idea of "copying" from parent to child.

无论是从定义上 (“ ...从父母传递给后代的特征”)还是从行为上(如上所述),“继承”都与从父母向孩子“复制”的思想最为相关。

When you then take "inheritance" and apply it to a mechanism which has some very different behavior, you are asking for the confusion which has plagued "JavaScript inheritance" documentationeducation, and usage for nearly 2 decades.

然后,当您采用“继承”并将其应用于具有某些截然不同的行为的机制时,您会遇到困扰“ JavaScript继承” 文档培训使用近20年的困惑。

To try to wade through this mess, let's set aside the label "inheritance" and its implications for JS, and hopefully we can arrive at something that is both conceptually more accurate and functionally more useful.

为了解决这个混乱局面,让我们抛开“继承”标签及其对JS的含义,希望我们可以在概念上更准确,功能上更有用。

ABD的:总是委派 (A.B.D's: Always Be Delegating)

JavaScript's OO-like property mechanism for objects is notated by [[Prototype]], which is the internal characteristic of any object called its prototype-chain -- a special link to another object. It's kind of like a scope mechanism, in that the [[Prototype]] linkage describes which alternate object should be referred to if you request a property or method on your object which doesn't exist.

JavaScript的OO状属性机构,用于对象由谱写[[Prototype]]这是任何对象的内部特性称为其原型链-一种特殊的链接到另一个对象。 这有点像作用域机制,因为[[Prototype]]链接描述了如果您请求不存在的对象的属性或方法, 则应引用哪个替代对象

In other words, you're indicating an object to delegate behavior to if that behavior isn't defined on the object in question.

换句话说,如果没有在有关对象上定义行为,则表示要向其委派行为的对象。

The above class-oriented Foo and Bar example, expressed in JS, relates object Bar.prototype toFoo.prototype, and then the foo1foo2bar1 and bar2 objects to their respective [[Prototype]]s. The arrows (not copies but live-links) point in a right-to-left, bottom-to-top fashion in JS:

上面用JS表达的面向类的FooBar示例,将对象Bar.prototypeFoo.prototype Bar.prototype ,然后将foo1foo2bar1bar2对象bar2到它们各自的[[Prototype]] s。 在JS中,箭头(不是副本,而是实时链接)以从右到左,从下到上的方式指向:

Delegation Arrows

"Behavior delegation" is a more accurate term to describe JavaScript's [[Prototype]]. This is not just a matter of word semantics, it's a fundamentally different type of functionality.

“行为委托”是描述JavaScript的[[Prototype]]的更准确的术语。 这不仅仅是单词语义的问题,还是一种根本不同的功能类型。

If you try to illustrate behavior delegation in terms of the "blueprint" metaphor, you quickly see how it totally breaks down. There's no way that my home, lacking a guest bedroom, could simply refer to another house, or to the original blueprints, to provide a bedroom for my mother-in-law when she comes to visit. Though the outcomes you can achieve have some respective similarities, the concepts of "inheritance" and "behavior delegation" are quite different.

如果您尝试用“蓝图”隐喻来说明行为委托,那么您很快就会发现它是如何分解的。 我的家里没有客人卧室,根本无法简单地参考另一所房子或原始设计图,以便为我婆婆来访时提供一间卧室。 尽管您可以实现的结果有一些相似之处,但是“继承”和“行为委托”的概念却截然不同

Some devs insist that "delegation" is just the dynamic version of "inheritance", like two sides of the same coin, but I see them as orthagonal systems.

一些开发人员坚持认为,“委托”只是“继承”的动态版本,就像同一枚硬币的两个侧面一样,但我将它们视为正交系统

如何委托? (How to delegate?)

We'll revisit this later in the article series, but Object.create(..) was added to ES5 to assist with creating an object and then optionally linking its [[Prototype]] to another object. The link that is created is a delegation link, as opposed to an inheritance-by-copy.

我们将在文章系列的后面部分对此进行重新讨论,但是Object.create(..)已添加到ES5中,以帮助创建对象,然后可选地将其[[Prototype]]到另一个对象。 创建的链接是委托链接,而不是按副本继承。

Note: Once an object has its [[Prototype]] chain set at its creation, it should for the most part be considered set in stone and not changeable. Technically, browsers which support the __proto__ property, a public representation of the internal link, allow you to change at any time where an object is linked to. However, this practice is littered with landmines and generally frowned upon -- it's almost certainly something you'd want toavoid in your code.

注意:一旦对象在创建时设置了[[Prototype]]链,就应将其大部分视为固定的,并且不可更改。 从技术上讲,支持__proto__属性 (内部链接的公共表示)的浏览__proto__您可以在链接对象的任何时间进行更改。 但是,这种做法到处都是地雷,人们普遍对此不屑一顾-几乎可以肯定,您希望在代码中避免这种情况。

铁锹 (Spade a Spade)

You've seen how the mechanisms in JavaScript are comparitively different from the mechanisms in other languages. But is it ok to just hand-waive over these differences so we can keep using the term "inheritance" for JS?

您已经了解到JavaScript中的机制与其他语言中的机制相比有何不同。 但是只需要手动放弃这些差异,这样我们就可以继续为JS使用术语“继承”吗?

The fact is, it's just not an accurate usage of the term. By insisting that JavaScript has "inheritance", we're really saying that the meaning of the word "inheritance" doesn't matter, or is rather soft.

事实是,这并不是该术语的准确用法。 通过坚持认为JavaScript具有“继承性”,我们实际上是在说“继承”一词的含义无关紧要,或者说很软。

JS doesn't statically analyze what parts of an inheritance chain it can safely flatten out and copy, it maintains links to the entire delegation chain throughout runtime, as distinct objects, which means our code can take advantage of a variety of powerful "late binding" dynamic patterns.

JS不会静态分析它可以安全地展平并复制的继承链的哪些部分,而是在整个运行时将指向整个委派链的链接保持为不同的对象 ,这意味着我们的代码可以利用各种强大的“后期绑定”动态模式

If we keep trying to mimic inheritance in JavaScript (syntax hurdles be damned), we get distracted and miss out on all that power that was built into our language from the start.

如果我们继续尝试模仿JavaScript中的继承(该死的语法障碍),那么我们会分心,并且一开始就会错过我们语言内置的所有功能

I say: let's call it what it is, and stop trying to pile on JavaScript these other concepts that the "inheritance" label implies.

我说:让我们称之为它,然后停止尝试在JavaScript上堆积“继承”标签所暗示的其他概念。

所以呢? (So What?)

So far, I've tried to identify some misconceptions about JS's [[Prototype]] mechanism and how "inheritance" is not a helpful label.

到目前为止,我已经尝试找出一些关于JS的[[Prototype]]机制以及“继承”不是有用标签的误解。

You may still be skeptical why it actually matters what we call this OO-like mechanism in JS? In the next part of the article series, I'm going to address many of the trappings of traditional "class-based" programming which I think are distractions that lead us to missing out on the essence of how JS objects interoperate. In fact, we could even say that classes/inheritance are a premature optimization for JavaScript.

您可能仍然持怀疑态度,为什么它实际上很重要,我们在JS中称为这种类似于OO的机制? 在本系列文章的下一部分中,我将解决许多传统的“基于类”编程的陷阱,我认为这是使人分神的原因,导致我们错过了JS对象如何进行互操作的本质。 实际上,我们甚至可以说类/继承是 JavaScript 的过早优化

Clearing those distractions out of the way leads us to part 3, where we'll see a simpler and more robust pattern for our JS code, and more importantly, our code will actually match our semantics without us having to jump through hoops to hide the ugly mismatches.

清除这些干扰可以使我们进入第3部分 ,在该部分中 ,我们将看到JS代码更简单,更强大的模式,更重要的是, 我们的代码实际上将与我们的语义相匹配, 而无需我们跳过箍来隐藏代码。丑陋的不匹配。

Look forward to parts 2 and 3 later this week!

期待本周晚些时候的第2部分和第3 部分

翻译自: https://davidwalsh.name/javascript-objects

js 对象继承

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值