css 原型图片
by Nash Vail
由Nash Vail
使用CSS解释JavaScript的原型继承 (JavaScript’s Prototypal Inheritance Explained Using CSS)
Prototypal inheritance is arguably the least understood aspect of JavaScript. Well the good news is that if you understand how CSS works, you can also understand how JavaScript prototypes work.
原型继承可以说是JavaScript最少了解的方面。 好消息是,如果您了解CSS的工作原理,那么您也可以了解JavaScript原型的工作原理。
It’s beautiful when something simple is able to explain something seemingly complex, an analogy — like a piledriver drives a pole deep into the ground, an analogy drives the point home.
当简单的事物能够解释看似复杂的事物时,就很美,就像一个比喻-例如打桩机将一根杆子推入地面深处,一个比喻将要点指向家。
I am a lover of analogies, an analogyphile.
我是一个类比爱好者,一个类比爱好者。
Here we go.
开始了。
CSS按钮中的原型 (Prototypes in CSS Buttons)
See the two buttons above? We’re going to design them in CSS.
看到上面的两个按钮? 我们将使用CSS设计它们。
Let’s go ahead and quickly write styles for these two buttons, starting with .btn
让我们继续快速编写这两个按钮的样式,以.btn
.btn { min-width: 135px; min-height: 45px; font-family: ‘Avenir Next’, sans-serif; font-size: 18px; font-weight: bold; letter-spacing: 1.3px; color: #4D815B; background-color: #FFF; border: 2px solid #4D815B; border-radius: 4px; padding: 5px 20px; cursor: pointer;}
That’s a reasonably simple block of CSS code.
那是一个相当简单CSS代码块。
Now let’s move to the styles for .btn-solid
现在让我们转到.btn-solid
的样式
.btn-solid { min-width: 135px; min-height: 45px; font-family: ‘Avenir Next’, sans-serif; font-size: 18px; font-weight: bold; letter-spacing: 1.3px; color: #FFF; background-color: #4D815B; border: 2px solid #4D815B; border-radius: 4px; padding: 5px 20px; cursor: pointer;}
As you might have already noticed, other than the bold ones, all the other styles in .btn-solid
are identical to that of .btn
. And If you are familiar with Sass, you may know that .btn-solid
styles can be rewritten in SASS like so:
您可能已经注意到,除了粗体以外, .btn-solid
中的所有其他样式都与.btn
相同。 而且,如果您熟悉Sass ,您可能会知道.btn-solid
样式可以用SASS重写,如下所示:
.btn-solid { @extend .btn; color: #FFF; background-color: #4D815B;}
As you can see, .btn-solid
inherits styles from .btn
, then overrides some of them (font and background color) to create itself. Which leads us to the conclusion that .btn-solid
is a specialized version of .btn
. Or, in other words, .btn-solid
is .btn
but with different font and background colors. That makes sense right? But wait there’s more.
如您所见, .btn-solid
从.btn
继承样式,然后覆盖其中的某些样式(字体和背景颜色)以创建自身。 这导致我们得出以下结论: .btn-solid
是.btn
的专用版本。 换句话说, .btn-solid
是.btn
但是具有不同的字体和背景颜色。 这样说对吗? 但是,等等。
Let’s say we want to create a larger button, .btn-lg
. We’ll use .btn
as a prototype to supply base styles. Then, similar to how we modified background and font colors to create .btn-solid
, we’ll modify the font-size property to a larger value to create a larger button.
假设我们要创建一个更大的按钮.btn-lg
。 我们将使用.btn
作为提供基本样式的原型 。 然后,类似于我们修改背景和字体颜色以创建.btn-solid
,我们将font-size属性修改为更大的值以创建更大的按钮。
Both .btn-lg
and .btn-solid
are specialized versions of .btn
. .btn
supplies base styles to .btn-lg
and .btn-solid
which then overwrite some of the base styles to create themselves. This tells us that a single button that we decide — .btn
in our case — can be used as a supplier of base styles to multiple items.
无论.btn-lg
和.btn-solid
专门的版本.btn
。 .btn
为.btn-lg
和.btn-solid
提供基础样式,然后覆盖一些基础样式以创建自己。 这告诉我们,我们确定的单个按钮(在我们的情况下为.btn
可以用作多个项目的基本样式的提供者。
In this section, we tried to define the concept of prototypes for CSS buttons. A Prototype is an entity that supplies base styles, which can be extended to create different instances of buttons. This definition of a prototype is very close to what prototypes actually mean in programming terms.
在本节中,我们尝试定义CSS按钮原型的概念。 原型是提供基本样式的实体,可以将其扩展以创建按钮的不同实例。 原型的定义非常接近原型在编程方面的实际含义。
In programming terms, a prototype is an object that supplies base behavior to a second object. The second object then extends this base behavior to form its own specialization. Let’s see in the next section how our knowledge of prototypes in CSS buttons maps to JavaScript.
用编程术语来说,原型是为第二个对象提供基本行为的对象。 然后,第二个对象扩展此基本行为以形成其自己的专业化。 在下一部分中,让我们看看我们在CSS按钮中的原型知识如何映射到JavaScript。
JavaScript中的原型 (Prototypes in JavaScript)
Consider the following JavaScript object:
考虑以下JavaScript对象:
let obj = { a: 1};
We know that the value of a
can be accessed by obj.a
, given that a
is clearly a property of obj
. But there’s more, you can also call obj.hasOwnProperty('a')
to check if obj
actually has a property named a
.
我们知道obj.a
可以访问a
的值,因为a
显然是obj
的属性。 但是还有更多,您还可以调用obj.hasOwnProperty('a')
来检查obj
实际上具有名为a
属性。
Now wait a second — from what we can see, obj
has no property called hasOwnProperty
defined on it. Where did hasOwnProperty
come from? To answer this question we’ll have to go back to the buttons we just finished creating.
现在,等待一秒钟-从我们的观察中可以看出, obj
没有定义名为hasOwnProperty
属性。 hasOwnProperty
来自哪里? 要回答这个问题,我们必须回到刚刚完成的按钮。
.btn-solid
just has background and font colors defined on it. Where is it getting, for example, border-radius
from? We know that .btn-solid
is a specialization of .btn
, so we can see that .btn-solid
is getting styles like border-radius
, width
, height
, and padding
from .btn
. Could it be the same with obj
?
.btn-solid
只是具有定义的背景和字体颜色。 它从何处获得border-radius
? 我们知道.btn-solid
是.btn-solid
一种特殊.btn
,因此我们可以看到.btn-solid
从.btn
获得了border-radius
, width
, height
和padding
.btn
。 可以和obj
吗?
Just like .btn-solid
and .btn-lg
get their base styles from .btn
, obj
or any other JavaScript object for that matter receive their base behavior from another object — Object.prototype
. And this Object.prototype
has hasOwnProperty
defined on it. And as a result, this gives obj
access to the hasOwnProperty
method — just like .btn-solid
had access to .btn
's border-radius
property.
就像.btn-solid
和.btn-lg
从.btn
, obj
或任何其他JavaScript对象获取其基本样式.btn
,从另一对象 Object.prototype
接收其基本行为。 并且此Object.prototype
拥有hasOwnProperty
定义。 结果,这使obj
可以访问hasOwnProperty
方法-就像.btn-solid
可以访问.btn
的border-radius
属性一样。
This — an object (obj) inheriting its properties and base-behavior from another object (Object.prototype) — is what we call prototypal inheritance. Notice that there is no class
involved in the interplay.
这就是一个对象 (obj) 从另一个对象 (Object.prototype) 继承其属性和基本行为的方式,我们称之为原型继承。 请注意,交互中不涉及任何class
。
The actual inner workings of JavaScript prototypes and our CSS “prototypes” are way different. But for the purpose of our analogy, we can ignore how they work behind the scenes.
JavaScript原型和CSS“原型”的实际内部运作方式截然不同。 但是出于类推的目的,我们可以忽略它们在后台的工作方式。
Object.prototype
isn’t the only prototype available in JavaScript. There’s Array.prototype
, Function.prototype
, Number.prototype
and several others. The job of all these prototypes is to supply base behavior or utility methods to their instances.
Object.prototype
不是JavaScript中可用的唯一原型。 有Array.prototype
, Function.prototype
, Number.prototype
等。 所有这些原型的工作是为其实例提供基本行为或实用程序方法。
For example every array declared in JavaScript has access to .push
, .sort
, .forEach
, and .map
only because of the prototypal linkage. And for the same reason every function has access to .call
, .apply
, .bind
.
例如,JavaScript中声明的每个数组仅由于原型链接而可以访问.push
, .sort
, .forEach
和.map
。 出于同样的原因,所有的功能访问.call
, .apply
, .bind
。
Prototypes and prototypal inheritance aren’t JavaScript specific. They’re a construct that JavaScript uses internally that allows us to use it in our own programs. Before we look at how exactly we can do that, we need to understand what prototypal chaining is.
原型和原型继承不是特定于JavaScript的。 它们是JavaScript内部使用的结构,允许我们在自己的程序中使用它。 在研究如何精确地做到这一点之前,我们需要了解什么是原型链。
原型链 (Prototypal Chaining)
We’ll need to get back to the buttons analogy for once. Let’s say I want to create a large solid button, .btn-solid-lg
:
我们需要一次回到类比按钮。 假设我要创建一个大的实心按钮.btn-solid-lg
:
The base styles to .btn-solid-lg
are supplied by .btn-solid
, and .btn-solid-lg
overwrites the font-size property to create itself.
.btn-solid-lg
的基本样式由.btn-solid
, .btn-solid-lg
覆盖font-size属性以创建其自身。
Take a closer look though. .btn-solid
has just two styles background-color and color (font) defined on it. This means .btn-solid-lg
has just 3 styles for itself: background-color, color, and font-size. Where are width
, height
, border-radius
coming from?
仔细看看。 .btn-solid
仅有两种样式,背景颜色和定义的颜色(字体)。 这意味着.btn-solid-lg
本身只有3种样式:background-color,color和font-size。 width
, height
, border-radius
从何而来?
Ok, here’s a hint:
好的,这里有个提示:
If you wanted to create an extra large button .btn-solid-xlg
you could do so with .btn-solid-lg
as prototype. But how does all of this map to JavaScript?
如果您想创建一个超大按钮.btn-solid-xlg
,可以使用.btn-solid-lg
作为原型。 但是所有这些如何映射到JavaScript?
In JavaScript, you’re allowed to create prototype chains too. Once you understand this, you unlock a whole set of tools to write amazingly powerful code. Yes, amazingly powerful.
在JavaScript中,您也可以创建原型链。 一旦了解了这一点,便可以解锁整套工具来编写功能强大的代码。 是的, 功能强大 。
Let’s see how prototype chains in JavaScript work.
让我们看看JavaScript中的原型链如何工作。
Remember the object we created in the previous section? The one we carefully named obj
? Did you know that you can create as many objects as you want with obj
as a prototype?
还记得我们在上一节中创建的对象吗? 我们仔细命名为obj
那个? 您是否知道可以使用obj
作为原型创建尽可能多的对象?
Object.create
lets you create a new object from a specified prototype object. This means that you can create another object, obj2
, which has obj
as its first prototype:
Object.create
允许您从指定的原型对象创建新对象。 这意味着您可以创建另一个对象obj2
,该obj
的第一个原型为obj
:
let obj2 = Object.create(obj);
// Add a property 'b' to obj2obj2.b = 2;
If you have been following so far, you should realize that even though obj2
doesn’t have a property a
defined on it, doing console.log(obj2.a)
won’t result in an error, but instead 1
getting logged to the console. Kind of like this:
如果你一直到目前为止之后,你应该明白,即使obj2
没有一个属性a
定义就可以了,这样做console.log(obj2.a)
不会导致错误,而是1
得到记录到安慰。 有点像这样:
When obj2
looks for a
, it first searches its own properties. If it can’t find the corresponding property, it asks its prototype (obj), where it finally finds a
. If such was the case that it still couldn’t find a
, the search would continue up the prototype chain until it reaches the last link, Object.prototype
.
当obj2
查找a
,它首先搜索其自己的属性。 如果无法找到相应的属性,它要求其原型(OBJ),在那里它终于找到a
。 如果仍然无法找到a
,则搜索将继续在原型链上进行,直到到达最后一个链接Object.prototype
。
On the other hand, if a
was defined on obj2
, it would override all other a
s if defined on any of its prototypes. Similar to how .btn-solid
overrode .btn
's color
and background-color
properties. This is called property overshadowing.
在另一方面,如果a
被定义obj2
,它会覆盖所有其他a
,如果在任何原型定义秒。 类似于.btn-solid
如何覆盖.btn
的color
和background-color
属性。 这称为财产遮盖 。
But what about the length of prototype chain? Is there a limit?
但是原型链的长度呢? 有限制吗?
There’s no limit to the length of prototype chain. There also aren’t any limits on branching. This means you can create multiple instances with Object.prototype
, obj
, or obj2
as prototype.
原型链的长度没有限制。 分支也没有任何限制。 这意味着您可以使用Object.prototype
, obj
或obj2
作为原型创建多个实例。
So how will this new knowledge of prototypes and prototypal chaining help you write better code?
那么,有关原型和原型链的新知识将如何帮助您编写更好的代码?
用原型编写更好的代码 (Writing better code with Prototypes)
The goal of this article was to explain to you what prototypes are, and how prototypal inheritance works. I hope I’ve succeeded in this.
本文的目的是向您解释什么是原型,以及原型继承如何工作。 我希望我已经成功了。
For this last section, I’ll allow myself to go on a little rant. I hope you don’t mind.
在最后一部分中,我将允许自己继续讲一点。 我希望你不要介意。
If you look at the JavaScript code available online — whether in open source projects on Github or in pens on Codepen — you’ll find that a majority of them use the constructor pattern for creating objects.
如果您查看在线上可用JavaScript代码(无论是在Github上的开源项目中还是在Codepen上的钢笔中),您会发现其中大多数使用构造函数模式来创建对象。
function Circle(radius) { this.radius = radius;}
Circle.prototype.area = function() { return Math.PI * this.radius * this.radius;}
// Constructor pattern for creating new objectslet circ = new Circle(5);
The constructor pattern looks like classes. In the early days, when JavaScript was far less popular than what it is today, the new
keyword was added as a marketing strategy.
构造函数模式看起来像类。 在早期,JavaScript远不如今天流行, new
关键字被添加为一种营销策略。
This indirection was intended to make JavaScript seem more familiar to classically trained programmers. Though it’s debatable how successful it was in doing so, it unintentionally also obscured the true prototypal nature of the language.
这种间接作用旨在使受过经典训练的程序员对JavaScript更加熟悉。 尽管这样做的成功程度值得商bat,但它无意间也掩盖了语言的真正原型性质。
The reality is that although constructors look like classes, they don’t behave like classes at all. In JavaScript, there are objects, and objects extending from other objects. Constructors and classes never come into picture. The constructor pattern unnecessarily complicates things, there’s a lot that happens behind the scenes.
现实情况是,尽管构造函数看起来像类,但它们的行为完全不像类。 在JavaScript中,存在对象,以及从其他对象扩展的对象。 构造函数和类永远不会出现。 构造函数模式不必要地使事情复杂化, 幕后发生了很多事情。
I implore you — now that you have a solid understanding of prototypes — to stop using the constructor pattern.
我恳请您-现在您已经对原型有了深刻的了解-停止使用构造函数模式。
Why not do this instead?
为什么不这样做呢?
let Circle = { create(radius) { // Creating prototypal linkage using Object.create let obj = Object.create(this); obj.radius = radius; return obj; }, area() { return Math.PI * this.radius * this.radius; }};
let circ = Circle.create(5);
I hope this analogy has helped you better understand prototypes, prototypal chaining and prototypal inheritance with Object.create
. Now you can write better code, and stop using pretentious classes.
我希望这种类比可以帮助您更好地理解Object.create
原型,原型链和原型继承。 现在您可以编写更好的代码,并停止使用自命不凡的类。
Thanks for reading! If my article was helpful, click the little green heart below to recommend it, and please share this with your fellow devs.
谢谢阅读! 如果我的文章有帮助,请单击下面的绿色小心脏以推荐它,并与其他开发人员分享。
And for further reading, check out Aadit Shah’s Why Prototypal Inheritance Matters.
要进一步阅读,请查看Aadit Shah的“ 为什么原型继承很重要” 。
寻找更多? 我定期在我的博客nashvail.me上发布。 到那里见,祝你好运! (Looking for more? I publish regularly on my blog at nashvail.me. See you there, have a good one!)
css 原型图片