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可能会使您出错。它不像大多数人期望的那样工作。子作用域获取自己的属性,该属性隐藏/隐藏同名的父属性。你的变通办法是

  • 在父对象中为模型定义对象,然后在子对象中引用该对象的特性:parentObj.someProp
  • 使用$parent.parentScopeProperty(不总是可能,但比1容易。如果可能的话)
  • 在父作用域上定义一个函数,并从子作用域调用它(并非总是可能的)
  • 新的AngularJS开发人员通常没有意识到
    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 */