Javascript AngularJS中范围原型/原型继承的细微差别是什么?
报告说: 作用域可以从父作用域继承 报告说: 作用域(原型)从其父作用域继承属性Javascript AngularJS中范围原型/原型继承的细微差别是什么?,javascript,angularjs,inheritance,prototype,prototypal-inheritance,graphviz,Javascript,Angularjs,Inheritance,Prototype,Prototypal Inheritance,Graphviz,报告说: 作用域可以从父作用域继承 报告说: 作用域(原型)从其父作用域继承属性 那么,子作用域总是从父作用域继承原型吗 有例外吗 当它确实继承时,是否总是正常的JavaScript原型继承 快速回答: 子作用域通常是从父作用域继承的,但并不总是这样。此规则的一个例外是带有作用域:{…}的指令——这将创建一个不典型继承的“隔离”作用域。在创建“可重用组件”指令时经常使用此构造 至于细微差别,范围继承通常是直截了当的。。。直到您需要在子范围中进行双向数据绑定(即表单元素、ng模型)。如果试图从子
- 那么,子作用域总是从父作用域继承原型吗李>
- 有例外吗李>
- 当它确实继承时,是否总是正常的JavaScript原型继承
快速回答:
子作用域通常是从父作用域继承的,但并不总是这样。此规则的一个例外是带有
作用域:{…}
的指令——这将创建一个不典型继承的“隔离”作用域。在创建“可重用组件”指令时经常使用此构造
至于细微差别,范围继承通常是直截了当的。。。直到您需要在子范围中进行双向数据绑定(即表单元素、ng模型)。如果试图从子作用域内部绑定到父作用域中的基元(例如,数字、字符串、布尔值),则Ng repeat、Ng switch和Ng include可能会使您出错。它不像大多数人期望的那样工作。子作用域获取自己的属性,该属性隐藏/隐藏同名的父属性。你的变通办法是
ng repeat
、ng switch
、ng view
、ng include
和ng if
都会创建新的子范围,因此当涉及到这些指令时,问题往往会出现。(有关问题的快速说明,请参阅。)
通过遵循“最佳实践”,可以很容易地避免原语的这个问题–观看3分钟。Misko用ng开关演示了原语绑定问题
在模型中使用“.”将确保原型继承发挥作用。所以,使用
<input type="text" ng-model="someObj.prop1">
<!--rather than
<input type="text" ng-model="prop1">`
-->
假设我们这样做:
childScope.aString = 'child string'
childScope.anArray[1] = '22'
childScope.anObject.property1 = 'child prop1'
childScope.anArray = [100, 555]
childScope.anObject = { name: 'Mark', country: 'USA' }
不参考原型链,并将新的aString属性添加到childScope此新属性隐藏/隐藏具有相同名称的parentScope属性。当我们在下面讨论ng repeat和ng include时,这将变得非常重要
假设我们这样做:
childScope.aString = 'child string'
childScope.anArray[1] = '22'
childScope.anObject.property1 = 'child prop1'
childScope.anArray = [100, 555]
childScope.anObject = { name: 'Mark', country: 'USA' }
由于在childScope中找不到对象(anArray和anObject),因此会参考原型链。这些对象位于parentScope中,并且在原始对象上更新特性值。未向childScope添加新属性;不会创建新对象。(请注意,在JavaScript中,数组和函数也是对象。)
假设我们这样做:
childScope.aString = 'child string'
childScope.anArray[1] = '22'
childScope.anObject.property1 = 'child prop1'
childScope.anArray = [100, 555]
childScope.anObject = { name: 'Mark', country: 'USA' }
不参考原型链,子作用域获得两个新的对象属性,它们隐藏/隐藏具有相同名称的父作用域对象属性
外卖:
- 如果我们阅读childScope.propertyX,并且childScope有propertyX,那么就不会参考原型链
- 如果我们设置childScope.propertyX,则不会参考原型链
最后一种情况:
delete childScope.anArray
childScope.anArray[1] === 22 // true
我们首先删除了childScope属性,然后当我们再次尝试访问该属性时,会参考原型链
角度范围继承
竞争者:
- 以下命令创建新作用域并继承原型:ng repeat、ng include、ng switch、ng controller、带有
scope:true的指令、带有transclude:true的指令
- 下面创建了一个不继承原型的新作用域:带有
scope:{…}
的指令。这将创建一个“隔离”范围
注意,默认情况下,指令不创建新的作用域——即默认值为scope:false
ng包括
假设控制器中有:
$scope.myPrimitive = 50;
$scope.myObject = {aNumber: 11};
$scope.myArrayOfPrimitives = [ 11, 22 ];
$scope.myArrayOfObjects = [{num: 101}, {num: 202}]
在我们的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>
<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>
在此输入文本框中键入(例如,“22”)不会产生新的子属性。模型现在绑定到父范围的属性(因为$parent是引用父范围的子范围属性)
对于所有作用域(原型或非原型),Angular始终通过作用域属性$parent、$$childHead和$$childTail跟踪父子关系(即层次结构)。我通常不会在图表中显示这些范围属性
对于不涉及表单元素的场景,另一种解决方案是在父作用域上定义一个函数来修改原语。然后确保子对象始终调用此函数,由于原型继承,此函数将对子对象作用域可用。例如:
// in the parent scope
$scope.setMyPrimitive = function(value) {
$scope.myPrimitive = value;
}
下面是一个使用这种“父函数”方法的示例。(小提琴是作为回答的一部分写的:)
另见和
ng开关
ng开关作用域继承的工作原理与ng include类似。因此,如果需要将双向数据绑定到父范围中的原语,请使用$parent,或者将模型更改为对象,然后绑定到该对象的属性。这将避免子范围隐藏/隐藏父范围属性
另见
ng重复
Ng repeat的工作原理稍有不同。假设控制器中有:
$scope.myPrimitive = 50;
$scope.myObject = {aNumber: 11};
$scope.myArrayOfPrimitives = [ 11, 22 ];
$scope.myArrayOfObjects = [{num: 101}, {num: 202}]
在我们的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>
<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>
如果项是一个基元(如myArrayOfPrimitives中的基元),则该值的一个副本本质上被分配给新的子范围属性。更改子作用域属性的值(即,使用ng模型,因此子作用域num
)不会更改父作用域引用的数组。因此,在上面的第一次ng重复中,每个子作用域都会获得一个独立于myArrayOfPrimitives数组的num
属性:
Child.prototype.changeProps = function(){
this.primitive = 2;
this.object.one = 2;
};
var dad = new Parent();
var son = new Child();
son.changeProps();
console.log(dad.primitive); /* 1 */
console.log(son.primitive); /* 2 */
console.log(dad.object.one); /* 2 */
console.log(son.object.one); /* 2 */