AngularJS中范围原型/原型继承的细微差别是什么?

本文翻译自:What are the nuances of scope prototypal / prototypical inheritance in AngularJS?

The API Reference Scope page says: API参考范围”页面显示

A scope can inherit from a parent scope. 范围可以从父范围继承。

The Developer Guide Scope page says: 开发人员指南范围页面显示

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原型继承?


#1楼

参考:https://stackoom.com/question/wwuW/AngularJS中范围原型-原型继承的细微差别是什么


#2楼

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. 该规则的一个例外是带有scope: { ... }的指令scope: { ... } -这会创建一个“隔离”范围,该范围不会被原型继承。 This construct is often used when creating a "reusable component" directive. 创建“可重用组件”指令时,经常使用此构造。

As for the nuances, scope inheritance is normally straightfoward... until you need 2-way data binding (ie, form elements, ng-model) in the child scope. 对于细微差别,作用域继承通常是直截了当的……直到您需要在子作用域中进行2路数据绑定 (即,表单元素,ng-model)。 Ng-repeat, ng-switch, and ng-include can trip you up if you try to bind to a primitive (eg, number, string, boolean) in the parent scope from inside the child scope. 如果您尝试从子作用域内部绑定到父作用域中的原始值 (例如,数字,字符串,布尔值),则Ng-repeat,ng-switch和ng-include可能会使您绊倒。 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 您的解决方法是

  1. define objects in the parent for your model, then reference a property of that object in the child: parentObj.someProp 在模型的父级中定义对象,然后在子级中引用该对象的属性:parentObj.someProp
  2. use $parent.parentScopeProperty (not always possible, but easier than 1. where possible) 使用$ parent.parentScopeProperty(并非总是可能,但比1容易)
  3. define a function on the parent scope, and call it from the child (not always possible) 在父作用域上定义一个函数,然后从子作用域调用它(并非总是可能的)

New AngularJS developers often do not realize that ng-repeat , ng-switch , ng-view , ng-include and ng-if all create new child scopes, so the problem often shows up when these directives are involved. 新的AngularJS开发人员通常不会意识到ng-repeatng-switchng-viewng-includeng-if都会创建新的子范围,因此当涉及这些指令时,常常会出现问题。 (See this example for a quick illustration of the problem.) (有关问题的快速说明,请参见此示例。)

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. 在您的ng模型中 -观看3分钟值得。 Misko demonstrates the primitive binding issue with ng-switch . 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">`
-->


Long 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. 假设parentScope具有属性aString,aNumber,anArray,anObject和aFunction。 If childScope prototypically inherits from parentScope, we have: 如果childScope原型继承自parentScope,则我们具有:

原型继承

(Note that to save space, I show the anArray object 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. 如果我们尝试从子作用域访问在parentScope上定义的属性,JavaScript将首先在子作用域中查找,而不是查找该属性,然后在继承的作用域中查找并找到该属性。 (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). (如果未在parentScope中找到该属性,它将在原型链上一直延续到根范围)。 So, these are all true: 所以,这些都是对的:

 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. 未查询原型链,并且将新的aString属性添加到childScope。 This new property hides/shadows the parentScope property with the same name. 此新属性将隐藏/隐藏具有相同名称的parentScope属性。 This will become very important when we discuss ng-repeat and ng-include below. 当我们在下面讨论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. 之所以查询原型链,是因为在childScope中找不到对象(anArray和anObject)。 The objects are found in the parentScope, and the property values are updated on the original objects. 在parentScope中找到对象,并且在原始对象上更新属性值。 No new properties are added to the childScope; 没有向childScope添加任何新属性; no new objects are created. 没有创建新对象。 (Note that in JavaScript arrays and functions are also objects.) (请注意,在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. 不查询原型链,子作用域将获得两个新的对象属性,这些对象属性将隐藏/阴影具有相同名称的parentScope对象属性。

隐藏更多财产

Takeaways: 外卖:

  • If we read childScope.propertyX, and childScope has propertyX, then the prototype chain is not consulted. 如果我们读取childScope.propertyX,并且childScope具有propertyX,则不会查询原型链。
  • If we set childScope.propertyX, the prototype chain is not consulted. 如果设置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 角范围继承

The contenders: 竞争者:

  • The following create new scopes, and inherit prototypically: ng-repeat, ng-include, ng-switch, ng-controller, directive with scope: true , directive with transclude: true . 以下代码创建新的作用域并进行原型继承:ng-repeat,ng-include,ng-switch,ng-controller, scope: true指令,带transclude: true指令。
  • The following creates a new scope which does not inherit prototypically: directive with scope: { ... } . 以下内容创建了一个新的范围,该范围不会原型继承:具有scope: { ... }指令。 This creates an "isolate" scope instead. 而是创建一个“隔离”范围。

Note, by default, directives do not create new scope -- ie, the default is scope: false . 注意,默认情况下,伪指令不会创建新的作用域-即默认值为scope: false

ng-include ng-include

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都会生成一个新的子作用域,该子作用域通常是从父作用域继承的。

ng-include子作用域

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

ng-include与原语

Typing (say, "99") into the second input textbox does not result in a new child property. 在第二个输入文本框中键入(例如“ 99”)不会导致新的子属性。 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. 因为tpl2.html将模型绑定到对象属性,所以当ngModel查找对象myObject时,原型继承就开始了-它在父作用域中找到它。

ng-include一个对象

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. 在此输入文本框中键入(例如“ 22”)不会产生新的子属性。 The model is now bound to a property of the parent scope (because $parent is a child scope property that references the parent scope). 现在,模型已绑定到父范围的属性(因为$ parent是引用父范围的子范围属性)。

ng-include和$ parent

For all scopes (prototypal or not), Angular always tracks a parent-child relationship (ie, a hierarchy), via scope properties $parent, $$childHead and $$childTail. 对于所有范围(无论是否是原型),Angular始终通过范围属性$ parent,$ childhead和$$ childTail跟踪父子关系(即层次结构)。 I normally don't show these scope properties in the diagrams. 我通常不会在图中显示这些范围属性。

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. 然后确保子级始终调用此函数,由于原型继承,该函数将可用于子级作用域。 Eg, 例如,

 // in the parent scope $scope.setMyPrimitive = function(value) { $scope.myPrimitive = value; } 

Here is a sample fiddle that 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/215945 and https://github.com/angular/angular.js/issues/1267 . 另请参阅https://stackoverflow.com/a/13782671/215945https://github.com/angular/angular.js/issues/1267

ng-switch ng-开关

ng-switch scope inheritance works just like ng-include. ng-switch作用域继承的工作方式与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. 因此,如果您需要与父作用域中的原语进行双向数据绑定,请使用$ parent或将模型更改为对象,然后绑定至该对象的属性。 This will avoid child scope hiding/shadowing of parent scope properties. 这将避免子范围隐藏/隐藏父范围属性。

See also AngularJS, bind scope of a switch-case? 另请参阅AngularJS,绑定开关盒的范围?

ng-repeat ng-repeat

Ng-repeat works a little differently. Ng-repeat的工作方式略有不同。 Suppose we have in our controller: 假设我们在控制器中:

 $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 . 对于每个项目/迭代,ng-repeat都会创建一个新的范围,该范围通常是从父范围继承的, 但也会将该项目的值分配给新的子范围上的新属性 (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的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. 如果item是基元(例如,在myArrayOfPrimitives中),则实质上将值的副本分配给新的子作用域属性。 Changing the child scope property's value (ie, using ng-model, hence child scope num ) does not change the array the parent scope references. 更改子作用域属性的值(即使用NG-模型,因此子范围num改变数组父范围引用。 So in the first ng-repeat above, each child scope gets a num property that is independent of the myArrayOfPrimitives array: 因此,在上面的第一个ng-repeat中,每个子范围都获得一个num属性,该属性独立于myArrayOfPrimitives数组:

用原语进行ng-repeat

This ng-repeat will not work (like you want/expect it to). 此ng-repeat无法正常工作(就像您想要/期望的那样)。 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. 我们想要的是使输入影响myArrayOfPrimitives数组,而不是子作用域原始属性。 To accomplish this, we need to change the model to be an array of objects. 为此,我们需要将模型更改为对象数组。

So, if item is an object, a reference to the original object (not a copy) is assigned to the new child scope property. 因此,如果item是对象,则将对原始对象(不是副本)的引用分配给新的子范围属性。 Changing the child scope property's value (ie, using ng-model, hence obj.num ) does change the object the parent scope references. 更改子范围属性的值(即,使用ng-model,因此使用obj.num确实会更改父范围引用的对象。 So in the second ng-repeat above, we have: 因此,在上面的第二个ng-repeat中,我们有:

ng-repeat with objects

(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 inputs and 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. 使用ng-controller嵌套控制器会导致正常的原型继承,就像ng-include和ng-switch一样,因此适用相同的技术。 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. 但是,“两个控制器通过$ 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 ) (如果您确实想通过Controller作用域继承共享数据,则无需执行任何操作。子作用域将有权访问所有父作用域属性。另请参见加载或导航时Controller的加载顺序有所不同

directives 指令

  1. default ( scope: false ) - the directive does not create a new scope, so there is no inheritance here. default( scope: false )-指令不会创建新的作用域,因此这里没有继承。 This is easy, but also dangerous because, eg, 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. 对于编写旨在用作可重用组件的指令,这不是一个好的选择。
  2. scope: true - the directive creates a new child scope that prototypically inherits from the parent scope. scope: true指令创建一个新的子范围,该子范围典型地从父范围继承。 If more than one directive (on the same DOM element) requests a new scope, only one new child scope is created. 如果有多个指令(在同一DOM元素上)请求一个新范围,则仅创建一个新的子范围。 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. 由于我们具有“常规”原型继承,因此就像ng-include和ng-switch一样,因此请谨慎使用2路数据绑定到父作用域原语,以及子作用域隐藏/遮蔽父作用域属性。
  3. scope: { ... } - the directive creates a new isolate/isolated scope. 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. 请注意,属性用于帮助设置绑定-您不能仅在对象哈希中引用父作用域属性名称,而必须使用属性。 Eg, this won't work if you want to bind to parent property parentProp in the isolated scope: <div my-directive> and scope: { localProp: '@parentProp' } . 例如,如果您想在隔离的范围: <div my-directive>scope: { localProp: '@parentProp' }绑定到父属性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> and scope: { localProp: '@theParentProp' } . 必须使用属性来指定指令要绑定到的每个父属性: <div my-directive the-Parent-Prop=parentProp>scope: { localProp: '@theParentProp' }
    Isolate scope's __proto__ references Object. 隔离范围的__proto__引用对象。 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. 隔离作用域的$ parent引用父作用域,因此,尽管它是隔离的并且不从父作用域继承原型,但它仍然是子作用域。
    For the picture below we have 对于下面的图片,我们有
    <my-directive interpolated="{{parentProp1}}" twowayBinding="parentProp2"> and <my-directive interpolated="{{parentProp1}}" twowayBinding="parentProp2">
    scope: { interpolatedProp: '@interpolated', twowayBindingProp: '=twowayBinding' }
    Also, assume the directive does this in its linking function: scope.someIsolateProp = "I'm isolated" 另外,假设该指令在其链接函数中执行此操作: scope.someIsolateProp = "I'm isolated"
    孤立范围
    For more information on isolate scopes see http://onehungrymind.com/angularjs-sticky-notes-pt-2-isolated-scope/ 有关隔离范围的更多信息,请参见http://onehungrymind.com/angularjs-sticky-notes-pt-2-isolated-scope/
  4. transclude: true - the directive creates a new "transcluded" child scope, which prototypically inherits from the parent scope. transclude: true指令创建一个新的“ transcluded”子作用域,该子作用域典型地从父作用域继承。 The transcluded and the isolated scope (if any) are siblings -- the $parent property of each scope references the same parent scope. 超越范围和隔离范围(如果有的话)是兄弟姐妹-每个范围的$ parent属性引用相同的父范围。 When a transcluded and an isolate scope both exist, isolate scope property $$nextSibling will reference the transcluded scope. 当同时存在一个已包含的范围和一个隔离范围时,隔离范围属性$$ nextSibling将引用该已包含的范围。 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 对于下面的图片,假定与上面相同的指令,并带有以下内容: transclude: true
    超越范围

This fiddle has a showScope() function that can be used to examine an isolate and transcluded scope. 小提琴具有showScope()函数,可用于检查隔离的和被showScope()范围。 See the instructions in the comments in the fiddle. 请参阅小提琴中注释中的说明。


Summary 摘要

There are four types of scopes: 范围有四种类型:

  1. normal prototypal scope inheritance -- ng-include, ng-switch, ng-controller, directive with scope: true 正常的原型作用域继承-ng-include,ng-switch,ng-controller,带有scope: true指令scope: true
  2. normal prototypal scope inheritance with a copy/assignment -- ng-repeat. 正常的原型范围继承,带有复制/赋值-ng-repeat。 Each iteration of ng-repeat creates a new child scope, and that new child scope always gets a new property. ng-repeat的每次迭代都会创建一个新的子范围,并且该新的子范围始终会获得一个新的属性。
  3. isolate scope -- directive with scope: {...} . 隔离范围- scope: {...}指令。 This one is not prototypal, but '=', '@', and '&' provide a mechanism to access parent scope properties, via attributes. 这不是原型,但是'=','@'和'&'提供了一种通过属性访问父范围属性的机制。
  4. transcluded scope -- directive with transclude: true . transcluded scope-带有transclude: true指令。 This one is also normal prototypal scope inheritance, but it is also a sibling of any isolate scope. 这也是正常的原型作用域继承,但它也是任何隔离作用域的同级对象。

For all scopes (prototypal or not), Angular always tracks a parent-child relationship (ie, a hierarchy), via properties $parent and $$childHead and $$childTail. 对于所有作用域(是否是原型),Angular始终通过属性$ parent和$$ childHead和$$ childTail跟踪父子关系(即层次结构)。

Diagrams were generated with "*.dot" files, which are on github . 使用 “ *。dot”文件生成图表,这些文件位于github上 Tim Caswell's " Learning JavaScript with Object Graphs " was the inspiration for using GraphViz for the diagrams. Tim Caswell的“ 使用对象图学习JavaScript ”是使用GraphViz绘制图表的灵感。


#3楼

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的答案抗衡,而只是想强调一下那篇文章,它最终使所有东西成为Java继承及其原型链的新手。

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 operation that tries to look up myThing before writing to its prop. 在该写入操作中进行了一个微妙的读取,该写入尝试在写入其道具之前查找myThing。 So that's why writing to object.properties from the child gets at the parent's objects. 因此,这就是为什么从子级写入object.properties会到达父级的对象的原因。


#4楼

I would like to add an example of prototypical inheritance with javascript to @Scott Driscoll answer. 我想在@Scott Driscoll答案中添加一个使用javascript进行原型继承的示例。 We'll be using classical inheritance pattern with Object.create() which is a part of EcmaScript 5 specification. 我们将对Object.create()使用经典继承模式,这是EcmaScript 5规范的一部分。

First we create "Parent" object function 首先我们创建“父母”对象功能

function Parent(){

}

Then add a prototype to "Parent" object function 然后将原型添加到“父对象”对象函数

 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”原型构造函数

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”,该子原型将重写Child对象中的“ primitive”属性值,并同时更改Child和Parent对象中的“ object.one”值

Child.prototype.changeProps = function(){
    this.primitive = 2;
    this.object.one = 2;
};

Initiate Parent (dad) and Child (son) objects. 启动父(爸爸)和子(儿子)对象。

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 父级和子级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

发布了0 篇原创文章 · 获赞 73 · 访问量 55万+

猜你喜欢

转载自blog.csdn.net/w36680130/article/details/105307531
今日推荐