Javascript AngularJS 中范围原型/原型继承的细微差别是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14049480/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What are the nuances of scope prototypal / prototypical inheritance in AngularJS?
提问by Mark Rajcok
The API Reference Scope pagesays:
该API参考范围页面说:
A scope caninherit from a parent scope.
作用域可以从父作用域继承。
The Developer Guide Scope pagesays:
该开发者指南范围页说:
A scope (prototypically) inherits properties from its parent scope.
范围(原型)从其父范围继承属性。
- So, does a child scope always prototypically inherit from its parent scope?
- Are there exceptions?
- When it does inherit, is it always normal JavaScript prototypal inheritance?
- 那么,子作用域是否总是原型继承自其父作用域?
- 有例外吗?
- 当它确实继承时,它总是正常的 JavaScript 原型继承吗?
回答by Mark Rajcok
Quick answer:
A child scope normally prototypically inherits from its parent scope, but not always. One exception to this rule is a directive with scope: { ... }-- this creates an "isolate" scope that does not prototypically inherit. This construct is often used when creating a "reusable component" directive.
快速回答:
子作用域通常原型继承自其父作用域,但并非总是如此。此规则的一个例外是指令 with scope: { ... }-- 这会创建一个不典型继承的“隔离”范围。在创建“可重用组件”指令时经常使用此构造。
As for the nuances, scope inheritance is normally straightfoward... until you need 2-way data binding(i.e., form elements, ng-model) in the child scope. Ng-repeat, ng-switch, and ng-include can trip you up if you try to bind to a primitive(e.g., number, string, boolean) in the parent scope from inside the child scope. It doesn't work the way most people expect it should work. The child scope gets its own property that hides/shadows the parent property of the same name. Your workarounds are
至于细微差别,范围继承通常是直接的……直到您需要在子范围中进行2 向数据绑定(即表单元素、ng-model)。如果您尝试从子作用域内部绑定到父作用域中的基元(例如,数字、字符串、布尔值),则Ng-repeat、ng-switch 和 ng-include 可能会绊倒您。它不像大多数人期望的那样工作。子作用域拥有自己的属性,可以隐藏/隐藏同名的父属性。您的解决方法是
- define objects in the parent for your model, then reference a property of that object in the child: parentObj.someProp
- use $parent.parentScopeProperty (not always possible, but easier than 1. where possible)
- define a function on the parent scope, and call it from the child (not always possible)
- 在模型的父对象中定义对象,然后在子对象中引用该对象的属性:parentObj.someProp
- 使用 $parent.parentScopeProperty (并非总是可行,但在可能的情况下比 1. 更容易)
- 在父作用域上定义一个函数,并从子作用域调用它(并非总是可行)
New AngularJS developers often do not realize that ng-repeat, ng-switch, ng-view, ng-includeand ng-ifall create new child scopes, so the problem often shows up when these directives are involved. (See this examplefor a quick illustration of the problem.)
新AngularJS开发商往往没有意识到ng-repeat,ng-switch,ng-view,ng-include和ng-if所有新创建子作用域,因此问题常常显示出来时,这些指令都参与其中。(有关问题的快速说明,请参阅此示例。)
This issue with primitives can be easily avoided by following the "best practice" of always have a '.' in your ng-models– watch 3 minutes worth. Misko demonstrates the primitive binding issue with ng-switch.
通过遵循始终具有 '.'的“最佳实践”,可以轻松避免原语的这个问题。在你的 ng-models 中——观看 3 分钟。Misko 演示了原始绑定问题ng-switch。
Having a '.' in your models will ensure that prototypal inheritance is in play. So, use
有一个 '。' 在您的模型中将确保原型继承发挥作用。所以,使用
<input type="text" ng-model="someObj.prop1">
<!--rather than
<input type="text" ng-model="prop1">`
-->
L-o-n-g answer长答案:
JavaScript Prototypal Inheritance
JavaScript 原型继承
Also placed on the AngularJS wiki:https://github.com/angular/angular.js/wiki/Understanding-Scopes
也放在 AngularJS wiki:https : //github.com/angular/angular.js/wiki/Understanding-Scopes
It is important to first have a solid understanding of prototypal inheritance, especially if you are coming from a server-side background and you are more familiar with class-ical inheritance. So let's review that first.
首先对原型继承有一个扎实的理解是很重要的,特别是如果您来自服务器端背景并且您更熟悉经典继承。所以让我们先回顾一下。
Suppose parentScope has properties aString, aNumber, anArray, anObject, and aFunction. If childScope prototypically inherits from parentScope, we have:
假设 parentScope 具有属性 aString、aNumber、anArray、anObject 和 aFunction。如果 childScope 原型继承自 parentScope,我们有:


(Note that to save space, I show the anArrayobject as a single blue object with its three values, rather than an single blue object with three separate gray literals.)
(请注意,为了节省空间,我将anArray对象显示为具有三个值的单个蓝色对象,而不是具有三个单独的灰色文字的单个蓝色对象。)
If we try to access a property defined on the parentScope from the child scope, JavaScript will first look in the child scope, not find the property, then look in the inherited scope, and find the property. (If it didn't find the property in the parentScope, it would continue up the prototype chain... all the way up to the root scope). So, these are all true:
如果我们尝试从子作用域访问定义在 parentScope 上的属性,JavaScript 将首先在子作用域中查找,未找到该属性,然后在继承的作用域中查找,并找到该属性。(如果它没有在 parentScope 中找到该属性,它将继续沿原型链向上……一直到根作用域)。所以,这些都是真的:
childScope.aString === 'parent string'
childScope.anArray[1] === 20
childScope.anObject.property1 === 'parent prop1'
childScope.aFunction() === 'parent output'
Suppose we then do this:
假设我们然后这样做:
childScope.aString = 'child string'
The prototype chain is not consulted, and a new aString property is added to the childScope. This new property hides/shadows the parentScope property with the same name.This will become very important when we discuss ng-repeat and ng-include below.
不参考原型链,在 childScope 中添加了一个新的 aString 属性。 这个新属性隐藏/隐藏了同名的 parentScope 属性。当我们在下面讨论 ng-repeat 和 ng-include 时,这将变得非常重要。


Suppose we then do this:
假设我们然后这样做:
childScope.anArray[1] = '22'
childScope.anObject.property1 = 'child prop1'
The prototype chain is consulted because the objects (anArray and anObject) are not found in the childScope. The objects are found in the parentScope, and the property values are updated on the original objects. No new properties are added to the childScope; no new objects are created. (Note that in JavaScript arrays and functions are also objects.)
参考原型链是因为在 childScope 中找不到对象(anArray 和 anObject)。在 parentScope 中找到对象,并且在原始对象上更新属性值。childScope 没有添加新的属性;没有创建新对象。(请注意,在 JavaScript 中数组和函数也是对象。)


Suppose we then do this:
假设我们然后这样做:
childScope.anArray = [100, 555]
childScope.anObject = { name: 'Mark', country: 'USA' }
The prototype chain is not consulted, and child scope gets two new object properties that hide/shadow the parentScope object properties with the same names.
不咨询原型链,子作用域获得两个新的对象属性,它们隐藏/隐藏具有相同名称的父作用域对象属性。


Takeaways:
要点:
- If we read childScope.propertyX, and childScope has propertyX, then the prototype chain is not consulted.
- If we set childScope.propertyX, the prototype chain is not consulted.
- 如果我们读取childScope.propertyX,childScope有propertyX,那么就不用参考原型链了。
- 如果我们设置childScope.propertyX,则不参考原型链。
One last scenario:
最后一个场景:
delete childScope.anArray
childScope.anArray[1] === 22 // true
We deleted the childScope property first, then when we try to access the property again, the prototype chain is consulted.
我们先删除了 childScope 属性,然后当我们再次尝试访问该属性时,会参考原型链。


Angular Scope Inheritance
Angular 范围继承
The contenders:
参赛者:
- The following create new scopes, and inherit prototypically: ng-repeat, ng-include, ng-switch, ng-controller, directive with
scope: true, directive withtransclude: true. - The following creates a new scope which does not inherit prototypically: directive with
scope: { ... }. This creates an "isolate" scope instead.
- 以下创建新的范围,并原型继承:ng-repeat、ng-include、ng-switch、ng-controller、directive with
scope: true、directive withtransclude: true。 - 下面创建了一个不继承原型的新范围:指令与
scope: { ... }. 这会创建一个“隔离”范围。
Note, by default, directives do not create new scope -- i.e., the default is scope: false.
请注意,默认情况下,指令不会创建新的作用域——即,默认值为scope: false.
ng-include
ng-包含
Suppose we have in our controller:
假设我们的控制器中有:
$scope.myPrimitive = 50;
$scope.myObject = {aNumber: 11};
And in our HTML:
在我们的 HTML 中:
<script type="text/ng-template" id="/tpl1.html">
<input ng-model="myPrimitive">
</script>
<div ng-include src="'/tpl1.html'"></div>
<script type="text/ng-template" id="/tpl2.html">
<input ng-model="myObject.aNumber">
</script>
<div ng-include src="'/tpl2.html'"></div>
Each ng-include generates a new child scope, which prototypically inherits from the parent scope.
每个 ng-include 都会生成一个新的子作用域,它通常从父作用域继承。


Typing (say, "77") into the first input textbox causes the child scope to get a new myPrimitivescope property that hides/shadows the parent scope property of the same name. This is probably not what you want/expect.
在第一个输入文本框中键入(例如“77”)会导致子作用域获得一个新的myPrimitive作用域属性,该属性隐藏/隐藏同名的父作用域属性。这可能不是您想要/期望的。


Typing (say, "99") into the second input textbox does not result in a new child property. Because tpl2.html binds the model to an object property, prototypal inheritance kicks in when the ngModel looks for object myObject -- it finds it in the parent scope.
在第二个输入文本框中键入(例如“99”)不会产生新的子属性。因为 tpl2.html 将模型绑定到一个对象属性,当 ngModel 寻找对象 myObject 时,原型继承就会启动——它在父作用域中找到它。


We can rewrite the first template to use $parent, if we don't want to change our model from a primitive to an object:
如果我们不想将模型从原始模型更改为对象,我们可以重写第一个模板以使用 $parent:
<input ng-model="$parent.myPrimitive">
Typing (say, "22") into this input textbox does not result in a new child property. The model is now bound to a property of the parent scope (because $parent is a child scope property that references the parent scope).
在此输入文本框中键入(例如“22”)不会产生新的子属性。该模型现在绑定到父作用域的属性(因为 $parent 是引用父作用域的子作用域属性)。


For all scopes (prototypal or not), Angular always tracks a parent-child relationship (i.e., a hierarchy), via scope properties $parent, $$childHead and $$childTail. I normally don't show these scope properties in the diagrams.
对于所有范围(原型与否),Angular 始终通过范围属性 $parent、$$childHead 和 $$childTail 跟踪父子关系(即层次结构)。我通常不会在图表中显示这些范围属性。
For scenarios where form elements are not involved, another solution is to define a function on the parent scope to modify the primitive. Then ensure the child always calls this function, which will be available to the child scope due to prototypal inheritance. E.g.,
对于不涉及表单元素的场景,另一种解决方案是在父作用域上定义一个函数来修改原语。然后确保子级始终调用此函数,由于原型继承,该函数可用于子级作用域。例如,
// in the parent scope
$scope.setMyPrimitive = function(value) {
$scope.myPrimitive = value;
}
Here is a sample fiddlethat uses this "parent function" approach. (The fiddle was written as part of this answer: https://stackoverflow.com/a/14104318/215945.)
这是一个使用这种“父函数”方法的示例小提琴。(小提琴是作为这个答案的一部分编写的:https: //stackoverflow.com/a/14104318/215945。)
See also https://stackoverflow.com/a/13782671/215945and https://github.com/angular/angular.js/issues/1267.
另见https://stackoverflow.com/a/13782671/215945和https://github.com/angular/angular.js/issues/1267。
ng-switch
ng-switch
ng-switch scope inheritance works just like ng-include. So if you need 2-way data binding to a primitive in the parent scope, use $parent, or change the model to be an object and then bind to a property of that object. This will avoid child scope hiding/shadowing of parent scope properties.
ng-switch 作用域继承就像 ng-include 一样工作。因此,如果您需要对父作用域中的原语进行 2 向数据绑定,请使用 $parent,或者将模型更改为对象,然后绑定到该对象的属性。这将避免父范围属性的子范围隐藏/阴影。
See also AngularJS, bind scope of a switch-case?
另请参阅AngularJS,绑定 switch-case 的范围?
ng-repeat
ng-重复
Ng-repeat works a little differently. Suppose we have in our controller:
Ng-repeat 的工作方式略有不同。假设我们的控制器中有:
$scope.myArrayOfPrimitives = [ 11, 22 ];
$scope.myArrayOfObjects = [{num: 101}, {num: 202}]
And in our HTML:
在我们的 HTML 中:
<ul><li ng-repeat="num in myArrayOfPrimitives">
<input ng-model="num">
</li>
<ul>
<ul><li ng-repeat="obj in myArrayOfObjects">
<input ng-model="obj.num">
</li>
<ul>
For each item/iteration, ng-repeat creates a new scope, which prototypically inherits from the parent scope, but it also assigns the item's value to a new property on the new child scope. (The name of the new property is the loop variable's name.) Here's what the Angular source code for ng-repeat actually is:
对于每个项目/迭代,ng-repeat 创建一个新的范围,该范围通常从父范围继承,但它也会将项目的值分配给新子范围上的新属性。(新属性的名称是循环变量的名称。)以下是 ng-repeat 的 Angular 源代码实际上是:
childScope = scope.$new(); // child scope prototypically inherits from parent scope
...
childScope[valueIdent] = value; // creates a new childScope property
If item is a primitive (as in myArrayOfPrimitives), essentially a copy of the value is assigned to the new child scope property. Changing the child scope property's value (i.e., using ng-model, hence child scope num) does notchange the array the parent scope references. So in the first ng-repeat above, each child scope gets a numproperty that is independent of the myArrayOfPrimitives array:
如果 item 是一个原始类型(如在 myArrayOfPrimitives 中),则本质上是将值的副本分配给新的子作用域属性。更改子作用域属性的值(即使用NG-模型,因此子范围num)并不会改变阵列父范围引用。所以在上面的第一个 ng-repeat 中,每个子作用域都获得一个num独立于 myArrayOfPrimitives 数组的属性:


This ng-repeat will not work (like you want/expect it to). Typing into the textboxes changes the values in the gray boxes, which are only visible in the child scopes. What we want is for the inputs to affect the myArrayOfPrimitives array, not a child scope primitive property. To accomplish this, we need to change the model to be an array of objects.
这个 ng-repeat 不起作用(就像你想要/期望的那样)。在文本框中键入会更改灰色框中的值,这些值仅在子作用域中可见。我们想要的是输入影响 myArrayOfPrimitives 数组,而不是子范围的原始属性。为此,我们需要将模型更改为对象数组。
So, if item is an object, a reference to the original object (not a copy) is assigned to the new child scope property. Changing the child scope property's value (i.e., using ng-model, hence obj.num) doeschange the object the parent scope references. So in the second ng-repeat above, we have:
因此,如果 item 是一个对象,则将对原始对象(而不是副本)的引用分配给新的子作用域属性。更改子作用域属性的值(即,使用 ng-model,因此obj.num)确实会更改父作用域引用的对象。所以在上面的第二个 ng-repeat 中,我们有:


(I colored one line gray just so that it is clear where it is going.)
(我将一条线涂成灰色,以便清楚它的去向。)
This works as expected. Typing into the textboxes changes the values in the gray boxes, which are visible to both the child and parent scopes.
这按预期工作。在文本框中键入会更改灰色框中的值,这些值对子作用域和父作用域都是可见的。
See also Difficulty with ng-model, ng-repeat, and inputsand https://stackoverflow.com/a/13782671/215945
另请参阅ng-model、ng-repeat 和输入的难度和 https://stackoverflow.com/a/13782671/215945
ng-controller
ng-控制器
Nesting controllers using ng-controller results in normal prototypal inheritance, just like ng-include and ng-switch, so the same techniques apply. However, "it is considered bad form for two controllers to share information via $scope inheritance" -- http://onehungrymind.com/angularjs-sticky-notes-pt-1-architecture/A service should be used to share data between controllers instead.
使用 ng-controller 嵌套控制器会导致正常的原型继承,就像 ng-include 和 ng-switch 一样,因此应用相同的技术。然而,“两个控制器通过 $scope 继承共享信息被认为是不好的形式” ——http://onehungrymind.com/angularjs-sticky-notes-pt-1-architecture/应该使用一个服务来共享数据控制器代替。
(If you really want to share data via controllers scope inheritance, there is nothing you need to do. The child scope will have access to all of the parent scope properties. See also Controller load order differs when loading or navigating)
(如果您真的想通过控制器范围继承共享数据,则无需执行任何操作。子范围将有权访问所有父范围属性。另请参阅加载或导航时控制器加载顺序不同)
directives
指令
- default (
scope: false) - the directive does not create a new scope, so there is no inheritance here. This is easy, but also dangerous because, e.g., a directive might think it is creating a new property on the scope, when in fact it is clobbering an existing property. This is not a good choice for writing directives that are intended as reusable components. scope: true- the directive creates a new child scope that prototypically inherits from the parent scope. If more than one directive (on the same DOM element) requests a new scope, only one new child scope is created. Since we have "normal" prototypal inheritance, this is like ng-include and ng-switch, so be wary of 2-way data binding to parent scope primitives, and child scope hiding/shadowing of parent scope properties.scope: { ... }- the directive creates a new isolate/isolated scope. It does not prototypically inherit. This is usually your best choice when creating reusable components, since the directive cannot accidentally read or modify the parent scope. However, such directives often need access to a few parent scope properties. The object hash is used to set up two-way binding (using '=') or one-way binding (using '@') between the parent scope and the isolate scope. There is also '&' to bind to parent scope expressions. So, these all create local scope properties that are derived from the parent scope. Note that attributes are used to help set up the binding -- you can't just reference parent scope property names in the object hash, you have to use an attribute. E.g., this won't work if you want to bind to parent propertyparentPropin the isolated scope:<div my-directive>andscope: { localProp: '@parentProp' }. An attribute must be used to specify each parent property that the directive wants to bind to:<div my-directive the-Parent-Prop=parentProp>andscope: { localProp: '@theParentProp' }.
Isolate scope's__proto__references Object. Isolate scope's $parent references the parent scope, so although it is isolated and doesn't inherit prototypically from the parent scope, it is still a child scope.
For the picture below we have<my-directive interpolated="{{parentProp1}}" twowayBinding="parentProp2">andscope: { interpolatedProp: '@interpolated', twowayBindingProp: '=twowayBinding' }
Also, assume the directive does this in its linking function:scope.someIsolateProp = "I'm isolated"
For more information on isolate scopes see http://onehungrymind.com/angularjs-sticky-notes-pt-2-isolated-scope/transclude: true- the directive creates a new "transcluded" child scope, which prototypically inherits from the parent scope. The transcluded and the isolated scope (if any) are siblings -- the $parent property of each scope references the same parent scope. When a transcluded and an isolate scope both exist, isolate scope property $$nextSibling will reference the transcluded scope. I'm not aware of any nuances with the transcluded scope.
For the picture below, assume the same directive as above with this addition:transclude: true
- default (
scope: false) - 该指令不会创建新的作用域,因此这里没有继承。这很容易,但也很危险,因为例如,指令可能认为它正在范围上创建一个新属性,而实际上它正在破坏现有属性。这不是编写旨在作为可重用组件的指令的好选择。 scope: true- 该指令创建一个新的子作用域,该子作用域原型继承自父作用域。如果多个指令(在同一个 DOM 元素上)请求一个新的作用域,则只会创建一个新的子作用域。由于我们有“正常”的原型继承,这就像 ng-include 和 ng-switch,所以要警惕 2-way 数据绑定到父作用域原语,以及父作用域属性的子作用域隐藏/阴影。scope: { ... }- 该指令创建一个新的隔离/隔离范围。它不典型地继承。这通常是创建可重用组件时的最佳选择,因为指令不会意外读取或修改父作用域。但是,此类指令通常需要访问一些父作用域属性。对象哈希用于在父作用域和隔离作用域之间设置双向绑定(使用“=”)或单向绑定(使用“@”)。还有 '&' 可以绑定到父作用域表达式。因此,这些都创建了从父作用域派生的局部作用域属性。请注意,属性用于帮助设置绑定——您不能只在对象哈希中引用父作用域属性名称,您必须使用属性。例如,如果您想绑定到父属性,这将不起作用parentProp在隔离范围内:<div my-directive>和scope: { localProp: '@parentProp' }。必须使用属性来指定指令要绑定到的每个父属性:<div my-directive the-Parent-Prop=parentProp>和scope: { localProp: '@theParentProp' }。
隔离作用域的__proto__引用对象。Isolate 作用域的 $parent 引用了父作用域,因此虽然它是隔离的并且不典型地从父作用域继承,但它仍然是一个子作用域。
对于下面的图片中,我们有<my-directive interpolated="{{parentProp1}}" twowayBinding="parentProp2">和scope: { interpolatedProp: '@interpolated', twowayBindingProp: '=twowayBinding' }
同样,假设该指令执行此操作在其链接功能:scope.someIsolateProp = "I'm isolated"
关于分离范围的详细信息,请参阅http://onehungrymind.com/angularjs-sticky-notes-pt-2-isolated-scope/transclude: true- 该指令创建一个新的“transcluded”子作用域,其原型继承自父作用域。嵌入的和隔离的作用域(如果有)是同级的——每个作用域的 $parent 属性引用相同的父作用域。当一个被嵌入的和一个隔离的作用域都存在时,隔离作用域属性 $$nextSibling 将引用被嵌入的作用域。我不知道嵌入范围的任何细微差别。
对于下图,假设与上面相同的指令加上这个:transclude: true
This fiddlehas a showScope()function that can be used to examine an isolate and transcluded scope. See the instructions in the comments in the fiddle.
该小提琴具有showScope()可用于检查隔离和嵌入范围的功能。请参阅小提琴注释中的说明。
Summary
概括
There are four types of scopes:
有四种类型的范围:
- normal prototypal scope inheritance -- ng-include, ng-switch, ng-controller, directive with
scope: true - normal prototypal scope inheritance with a copy/assignment -- ng-repeat. Each iteration of ng-repeat creates a new child scope, and that new child scope always gets a new property.
- isolate scope -- directive with
scope: {...}. This one is not prototypal, but '=', '@', and '&' provide a mechanism to access parent scope properties, via attributes. - transcluded scope -- directive with
transclude: true. This one is also normal prototypal scope inheritance, but it is also a sibling of any isolate scope.
- 普通原型范围继承——ng-include、ng-switch、ng-controller、指令
scope: true - 带有复制/赋值的普通原型范围继承——ng-repeat。ng-repeat 的每次迭代都会创建一个新的子作用域,并且这个新的子作用域总是有一个新的属性。
- 隔离范围 - 指令与
scope: {...}. 这不是原型,但 '='、'@' 和 '&' 提供了一种通过属性访问父作用域属性的机制。 - 内嵌作用域 - 带有
transclude: true. 这也是正常的原型范围继承,但它也是任何隔离范围的同级。
For all scopes (prototypal or not), Angular always tracks a parent-child relationship (i.e., a hierarchy), via properties $parent and $$childHead and $$childTail.
对于所有范围(原型与否),Angular 始终通过属性 $parent 和 $$childHead 以及 $$childTail 跟踪父子关系(即层次结构)。
Diagrams were generated with graphviz"*.dot" files, which are on github. Tim Caswell's "Learning JavaScript with Object Graphs" was the inspiration for using GraphViz for the diagrams.
图表是使用github上的graphviz"*.dot" 文件生成的。Tim Caswell 的“ Learning JavaScript with Object Graphs”是将 GraphViz 用于图表的灵感来源。
回答by Scott Driscoll
I in no way want to compete with Mark's answer, but just wanted to highlight the piece that finally made everything click as someone new to Javascript inheritance and its prototype chain.
我绝不想与 Mark 的答案竞争,而只是想突出显示最终使所有内容都成为Javascript 继承及其原型链的新手的那篇文章。
Only property reads search the prototype chain, not writes.So when you set
只有属性读取搜索原型链,而不是写入。所以当你设置
myObject.prop = '123';
It doesn't look up the chain, but when you set
它不会查找链条,但是当您设置
myObject.myThing.prop = '123';
there's a subtle read going on within that write operationthat tries to look up myThing before writing to its prop. So that's why writing to object.properties from the child gets at the parent's objects.
在写操作中进行了一个微妙的读操作,试图在写到它的 prop 之前查找 myThing。所以这就是为什么从子对象写入 object.properties 会到达父对象的原因。
回答by tylik
I would like to add an example of prototypical inheritance with javascript to @Scott Driscoll answer. We'll be using classical inheritance pattern with Object.create() which is a part of EcmaScript 5 specification.
我想在@Scott Driscoll 答案中添加一个带有 javascript 的原型继承示例。我们将在 Object.create() 中使用经典的继承模式,它是 EcmaScript 5 规范的一部分。
First we create "Parent" object function
首先我们创建“Parent”对象函数
function Parent(){
}
Then add a prototype to "Parent" object function
然后给“Parent”对象函数添加一个原型
Parent.prototype = {
primitive : 1,
object : {
one : 1
}
}
Create "Child" object function
创建“子”对象函数
function Child(){
}
Assign child prototype (Make child prototype inherit from parent prototype)
分配子原型(使子原型继承父原型)
Child.prototype = Object.create(Parent.prototype);
Assign proper "Child" prototype constructor
分配适当的“子”原型构造函数
Child.prototype.constructor = Child;
Add method "changeProps" to a child prototype, which will rewrite "primitive" property value in Child object and change "object.one" value both in Child and Parent objects
将方法“changeProps”添加到子原型,这将重写子对象中的“原始”属性值并更改子对象和父对象中的“object.one”值
Child.prototype.changeProps = function(){
this.primitive = 2;
this.object.one = 2;
};
Initiate Parent (dad) and Child (son) objects.
启动 Parent(爸爸)和 Child(儿子)对象。
var dad = new Parent();
var son = new Child();
Call Child (son) changeProps method
调用Child(son)changeProps方法
son.changeProps();
Check the results.
检查结果。
Parent primitive property did not change
父原始属性没有改变
console.log(dad.primitive); /* 1 */
Child primitive property changed (rewritten)
子原始属性已更改(重写)
console.log(son.primitive); /* 2 */
Parent and Child object.one properties changed
Parent 和 Child object.one 属性已更改
console.log(dad.object.one); /* 2 */
console.log(son.object.one); /* 2 */
Working example here http://jsbin.com/xexurukiso/1/edit/
这里的工作示例http://jsbin.com/xexurukiso/1/edit/
More info on Object.create here https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/create
关于 Object.create 的更多信息在这里https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/create

