programing

AngularJS에서 스코프 프로토타입/프로토타입 상속의 뉘앙스는 무엇입니까?

sourcetip 2022. 9. 5. 23:25
반응형

AngularJS에서 스코프 프로토타입/프로토타입 상속의 뉘앙스는 무엇입니까?

[ API Reference Scope ]페이지에는 다음과 같이 표시됩니다.

스코프는 부모 스코프에서 상속할 수 있습니다.

Developer Guide Scope 페이지에는 다음과 같이 표시됩니다.

스코프는 (프로토타입적으로) 부모 스코프에서 속성을 상속합니다.

  • 그렇다면 자녀 범위는 항상 부모 범위에서 프로토타입적으로 상속되는 것일까요?
  • 예외가 있나요?
  • 그것이 상속될 때, 그것은 항상 정상적인 JavaScript 프로토타입 상속입니까?

빠른 답변:
하위 범위는 일반적으로 상위 범위로부터 프로토타입적으로 상속되지만 항상 상속되는 것은 아닙니다.이 규칙의 한 가지 예외는 다음과 같은 명령입니다.scope: { ... }--이것에 의해서, 프로토타입으로 계승되지 않는 「특정」스코프가 작성됩니다.이 구성은 "재사용 가능한 구성 요소" 지시문을 작성할 때 자주 사용됩니다.

뉘앙스는 스코프 상속은 보통 간단하지만...스코프에서 2방향 데이터 바인딩(예: 폼 요소, ng-모델)이 필요할 때까지.Ng-repeat, ng-switch 및 ng-include는 자 스코프 내부에서 부모 스코프의 프리미티브(숫자, 문자열, 부울 등)에 바인드하려고 하면 트립이 발생할 수 있습니다.그것은 대부분의 사람들이 예상하는 대로 작동하지 않는다.하위 범위는 동일한 이름의 상위 속성을 숨기거나 섀도우하는 고유한 속성을 가져옵니다.회피책은 다음과 같습니다.

  1. 모델의 상위 개체에서 개체를 정의한 다음 하위 개체의 속성 parentObj를 참조합니다.일부 제안
  2. $parent.parentScopeProperty를 사용합니다(항상 가능한 것은 아니지만 가능한 경우 1.보다 쉽습니다).
  3. 상위 스코프에서 함수를 정의하고 하위 스코프에서 해당 함수를 호출합니다(항상 가능한 것은 아닙니다).

새 각도JS 개발자는 종종 다음과 같은 사실을 깨닫지 못합니다.ng-repeat,ng-switch,ng-view,ng-include그리고.ng-if모두 새로운 아이 스코프를 작성하기 때문에, 이러한 디렉티브가 관련되면, 문제가 자주 발생합니다.(문제의 간단한 설명에 대해서는, 다음의 예를 참조해 주세요).

ng-model에 항상 '.'를 붙이는 "베스트 프랙티스"를 따르면 이 원시 요소의 문제를 쉽게 방지할 수 있습니다. 3분 동안 시청하십시오.Misko는 다음과 같은 기본적인 결합 문제를 보여줍니다.ng-switch.

모델에 '.'를 붙이면 프로토타입 상속을 확실하게 할 수 있습니다.그럼, 을 사용해 주세요.

<input type="text" ng-model="someObj.prop1">

<!--rather than
<input type="text" ng-model="prop1">`
-->


L-o-n-g 응답:

JavaScript 프로토타입 상속

각도에도 배치됩니다.JS Wiki: https://github.com/angular/angular.js/wiki/Understanding-Scopes

먼저 프로토타입 상속을 확실하게 이해하는 것이 중요합니다. 특히 서버 측 배경을 가지고 있으며 클래스 ical 상속을 더 잘 알고 있는 경우에는 더욱 그렇습니다.그럼 먼저 검토해보도록 하겠습니다.

parentScope에 aString, aNumber, anArray, anObject 및 aFunction 속성이 있다고 가정합니다.childScope가 parentScope에서 프로토타입으로 상속하는 경우 다음과 같은 이점이 있습니다.

prototypal inheritance

(공간을 절약하기 위해서,anArray개체는 세 개의 개별 회색 리터럴을 가진 단일 파란색 개체가 아니라 세 개의 값을 가진 단일 파란색 개체로 간주됩니다.)

하위 범위에서 parentScope에 정의된 속성에 액세스하려고 하면 JavaScript는 먼저 하위 범위를 찾아 속성을 찾지 않고 상속된 범위를 찾아 속성을 찾습니다(parentScope에서 속성을 찾지 못한 경우 프로토타입 체인을 계속합니다...루트 스코프까지).다음은 모두 해당됩니다.

childScope.aString === 'parent string'
childScope.anArray[1] === 20
childScope.anObject.property1 === 'parent prop1'
childScope.aFunction() === 'parent output'

다음으로 다음과 같이 하겠습니다.

childScope.aString = 'child string'

프로토타입 체인은 참조되지 않으며 새 aString 속성이 childScope에 추가됩니다.이 새 속성은 동일한 이름의 parentScope 속성을 숨기거나 섀도우합니다.이것은 아래 ng-repeat 및 ng-include에 대해 논의할 때 매우 중요해질 것입니다.

property hiding

다음으로 다음과 같이 하겠습니다.

childScope.anArray[1] = '22'
childScope.anObject.property1 = 'child prop1'

개체(anArray 및 anObject)가 childScope에 없으므로 프로토타입 체인을 참조합니다.개체가 parentScope에서 발견되고 속성 값이 원래 개체에서 업데이트됩니다.childScope에 새 속성이 추가되지 않으며 새 개체도 생성되지 않습니다.(JavaScript 배열 및 함수도 객체입니다.)

follow the prototype chain

다음으로 다음과 같이 하겠습니다.

childScope.anArray = [100, 555]
childScope.anObject = { name: 'Mark', country: 'USA' }

프로토타입 체인은 참조되지 않으며 하위 스코프는 동일한 이름의 parentScope 개체 속성을 숨기거나 음영으로 만드는 두 개의 새 개체 속성을 가져옵니다.

more property hiding

요점:

  • childScope.propertyX를 읽고 childScope에 propertyX가 있는 경우 프로토타입 체인은 참조되지 않습니다.
  • childScope.propertyX를 설정하면 프로토타입 체인은 참조되지 않습니다.

마지막 시나리오:

delete childScope.anArray
childScope.anArray[1] === 22  // true

먼저 childScope 속성을 삭제한 후 해당 속성에 다시 액세스하려고 하면 프로토타입 체인이 참조됩니다.

after removing a child property


각도 범위 상속

경쟁사:

  • ng-repeat, ng-include, ng-switch, ng-controller, 디렉티브는 새로운 범위를 생성하여 프로토타입으로 상속합니다.scope: true명령어, 명령어transclude: true.
  • 다음은 프로토타입으로 상속되지 않는 새로운 범위를 생성합니다. 지시문은 다음과 같습니다.scope: { ... }대신 "고립" 스코프가 생성됩니다.

디폴트로는 디렉티브는 새로운 범위를 작성하지 않습니다.기본값은 다음과 같습니다.scope: false.

ng-interface(ng-interface.

컨트롤러에 다음과 같은 기능이 있다고 가정합니다.

$scope.myPrimitive = 50;
$scope.myObject    = {aNumber: 11};

또, 델의 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>

각 ng-include는 부모 범위로부터 프로토타입으로 상속되는 새로운 자식 범위를 생성한다.

ng-include child scopes

첫 번째 입력 텍스트 상자에 (예를 들어 "77")을 입력하면 하위 스코프가 새로 생성됩니다.myPrimitive동일한 이름의 상위 범위 속성을 숨기거나 숨기는 범위 속성.이것은 아마 당신이 원하는/예상하지 않을 것입니다.

ng-include with a primitive

두 번째 입력 텍스트 상자에 (예를 들어 "99")를 입력해도 새 자식 속성이 생성되지 않습니다.tpl2.html은 모델을 오브젝트 속성에 바인드하기 때문에 ngModel이 오브젝트 myObject를 찾을 때 시제품 상속이 시작됩니다.이것은 상위 스코프에서 검출됩니다.

ng-include with an object

모델을 원시에서 객체로 변경하지 않으려면 $parent를 사용하도록 첫 번째 템플릿을 다시 작성할 수 있습니다.

<input ng-model="$parent.myPrimitive">

이 입력 텍스트 상자에 입력("22")을 입력해도 새 자식 속성이 생성되지 않습니다.이제 모델이 부모 범위의 속성에 바인딩됩니다($parent는 부모 범위를 참조하는 자식 범위 속성이기 때문입니다).

ng-include with $parent

Angular는 모든 범위(프로토타입팔 여부에 관계없이)에서 항상 스코프 속성 $parent, $$child를 통해 부모-자녀 관계(즉 계층)를 추적합니다.헤드와 $$childTail.일반적으로 다이어그램에는 이러한 스코프 속성을 표시하지 않습니다.

폼 요소가 포함되지 않은 시나리오의 경우 부모 스코프에서 함수를 정의하여 프리미티브를 수정하는 방법도 있습니다.그런 다음 아이가 항상 이 기능을 호출하는지 확인하십시오. 시제품 상속으로 인해 어린이 스코프가 이 기능을 사용할 수 있습니다.예.,

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

이 '부모 기능' 접근방식을 사용하는 바이올린의 를 다음에 나타냅니다.(이 바이올린은 이 답변의 일부로 작성되었습니다.https://stackoverflow.com/a/14104318/215945.)

https://stackoverflow.com/a/13782671/215945 및 https://github.com/angular/angular.js/issues/1267 를 참조해 주세요.

ng 스위치

ng-switch 스코프 상속은 ng-switch와 동일하게 동작합니다.따라서 부모 스코프의 프리미티브에 대한 양방향 데이터 바인딩이 필요한 경우 $parent를 사용하거나 모델을 개체로 변경한 후 해당 개체의 속성에 바인딩합니다.이렇게 하면 부모 스코프 속성의 하위 스코프 숨기기/섀도우링이 방지됩니다.

'AngularJS, 스위치 케이스의 바인드 스코프'도 참조해 주세요.

ng-interface(ng-interface.

Ng-repeat은 조금 다르게 작동합니다.컨트롤러에 다음과 같은 기능이 있다고 가정합니다.

$scope.myArrayOfPrimitives = [ 11, 22 ];
$scope.myArrayOfObjects    = [{num: 101}, {num: 202}]

또, 델의 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>

각 항목/반복에 대해 ng-repeat은 새로운 범위를 생성하며, 이는 상위 범위로부터 프로토타입으로 상속되지만, 또한 항목의 값을 하위 범위의 새 속성에 할당합니다.(새 속성의 이름은 루프 변수의 이름입니다).ng-repeat의 Angular 소스 코드는 다음과 같습니다.

childScope = scope.$new();  // child scope prototypically inherits from parent scope
...
childScope[valueIdent] = value;  // creates a new childScope property

항목이 기본(myArrayOfPrimitives)인 경우 기본적으로 값의 복사본이 새 하위 범위 속성에 할당됩니다.하위 범위 속성 값 변경(ng-model 사용, 즉 하위 범위 사용)num)는 부모 스코프가 참조하는 어레이를 변경하지 않습니다.따라서 위의 첫 번째 ng-repeat에서는 각 자 스코프가nummyArrayOfPrimitives 배열과 독립적인 속성:

ng-repeat with primitives

이 ng-repeat은 (원하는 대로/예상대로) 동작하지 않습니다.텍스트 상자에 입력하면 하위 스코프에만 표시되는 회색 상자의 값이 변경됩니다.입력이 myArrayOfPrimitives 배열에 영향을 주는 것이지 하위 범위 프리미티브 속성이 아닙니다.이를 위해서는 모델을 오브젝트 배열로 변경해야 합니다.

따라서 항목이 개체인 경우 복사본이 아닌 원래 개체에 대한 참조가 새 하위 범위 속성에 할당됩니다.하위 범위 속성 값 변경(즉, ng-model 사용)obj.num)는 부모 스코프가 참조하는 오브젝트를 변경합니다.위의 두 번째 ng-repeat에서는 다음이 있습니다.

ng-repeat with objects

(어디로 가고 있는지 알기 위해 한 줄을 회색으로 칠했습니다.)

이것은 예상대로 동작합니다.텍스트 상자에 입력하면 회색 상자의 값이 변경되어 하위 범위와 상위 범위 모두에 표시됩니다.

ng-model, ng-model, ng-model 입력의 어려움 및 https://stackoverflow.com/a/13782671/215945을 참조하십시오.

ng 컨트롤러

ng-controller를 사용하여 컨트롤러를 중첩하면 ng-include 및 ng-switch와 마찬가지로 정상적인 프로토타입 상속이 이루어지므로 동일한 기술이 적용됩니다.단, "2개의 컨트롤러가 $120 상속을 통해 정보를 공유하는 것은 잘못된 형식으로 간주됩니다." http://onehungrymind.com/angularjs-sticky-notes-pt-1-architecture/ 대신 컨트롤러 간에 데이터를 공유하는 서비스를 사용해야 합니다.

(컨트롤러 스코프 상속을 통해 데이터를 공유할 경우 수행할 필요가 없습니다.하위 스코프는 모든 상위 스코프 속성에 액세스할 수 있습니다.로딩 또는 네비게이션컨트롤러 로드 순서가 다름)도 참조해 주십시오.

지시.

  1. 디폴트)scope: false - 스코프를 하지 않기 .)- 「상속되지 않습니다.이는 간단하지만 위험하기도 합니다. 예를 들어 지시문이 기존 속성을 클로빙할 때 새 속성을 스코프에 만들고 있다고 생각할 수 있기 때문입니다.재사용 가능한 컴포넌트로 사용되는 지침 작성에는 적합하지 않습니다.
  2. scope: true으로 상속되는 를 만듭니다. - 부모 스코프로부터 상속됩니다.(같은 DOM 요소에서) 여러 지시문이 새 범위를 요청하면 새 하위 범위 하나만 생성됩니다."정상적인" 프로토타입 상속이 있기 때문에 이는 ng-include 및 ng-switch와 같으므로 부모 스코프 프리미티브에 대한 양방향 데이터 바인딩 및 부모 스코프 속성의 자녀 스코프 숨기기/섀도우링에 주의해야 한다.
  3. scope: { ... }는 새로운 를 만듭니다. - 격리/경계 범위를 만듭니다.원형적으로 상속되지 않습니다.명령어는 실수로 상위 범위를 읽거나 수정할 수 없으므로 재사용 가능한 구성 요소를 만들 때 일반적으로 이 방법을 선택하는 것이 좋습니다.그러나 그러한 지침에는 종종 몇 가지 상위 범위 속성에 대한 액세스가 필요합니다.개체 해시는 상위 범위와 격리 범위 간에 양방향 바인딩('=' 사용) 또는 단방향 바인딩('@' 사용)을 설정하는 데 사용됩니다.을 사용하다따라서 이들 모두 상위 범위에서 파생된 로컬 범위 속성을 만듭니다.속성은 바인딩을 설정하는 데 사용됩니다. 부모 속성에 이것하지 않습니다parentProp된 범위: " " " 。<div my-directive> ★★★★★★★★★★★★★★★★★」scope: { localProp: '@parentProp' }. 각 을 사용해야 합니다.<div my-directive the-Parent-Prop=parentProp> ★★★★★★★★★★★★★★★★★」scope: { localProp: '@theParentProp' }
    __proto__오브젝트를 참조합니다.격리 스코프의 $parent는 상위 스코프를 참조하기 때문에 격리되어 상위 스코프에서 프로토타입으로 상속되지 않지만 여전히 하위 스코프입니다.
    아래 사진은 다음과 같습니다.
    <my-directive interpolated="{{parentProp1}}" twowayBinding="parentProp2">그리고.
    scope: { interpolatedProp: '@interpolated', twowayBindingProp: '=twowayBinding' }
    또, 디렉티브가 링크 기능에서 이것을 실행한다고 가정합니다.scope.someIsolateProp = "I'm isolated"
    isolated scope
    분리 범위의 자세한 내용은http://http://onehungrymind.com/angularjs-sticky-notes-pt-2-isolated-scope/ 를 참조해 주세요.
  4. transclude: true- 지침에서는 새로운 "제외된" 하위 범위를 만듭니다. 이 범위는 원형적으로 상위 범위에서 상속됩니다.변환된 범위와 분리된 범위(있는 경우)는 형제입니다. 각 범위의 $parent 속성은 동일한 상위 범위를 참조합니다.트랜스코프된 범위와 격리된 범위가 모두 존재하는 경우 격리된 범위 속성 $$nextSibling은 트랜스코프된 범위를 참조합니다.나는 변환된 범위의 어떤 뉘앙스도 알지 못한다.
    아래 그림의 경우 위와 같은 지시사항을 추가한다고 가정합니다.transclude: true
    transcluded scope

바이올린은showScope()분리 및 변환된 스코프를 검사하는 데 사용할 수 있는 함수입니다.바이올린의 코멘트에 기재되어 있는 설명을 참조해 주세요.


요약

스코프에는, 다음의 4 종류가 있습니다.

  1. 일반 프로토타입 범위 상속 -- ng-controller, ng-switch, ng-controller, 지시어scope: true
  2. 복사/파일을 사용한 일반 프로토타입 스코프 상속 --ng-displaces.ng-repeat을 반복할 때마다 새로운 자 스코프가 생성되고 그 새로운 자 스코프가 항상 새로운 속성을 가져옵니다.
  3. solate scope -- 명령어scope: {...}시제품은 아니지만 '=', '@', '&'는 속성을 통해 상위 스코프 속성에 액세스할 수 있는 메커니즘을 제공합니다.
  4. transcribed scope -- 지시어transclude: true이 또한 일반적인 프로토타입 스코프 상속이지만 격리 스코프의 형제이기도 합니다.

Angular는 모든 범위(프로토타입팔 여부에 관계없이)에서 항상 속성 $parent 및 $$child를 통해 부모-자녀 관계(즉 계층)를 추적한다.헤드와 $$childTail.

다이어그램은 github에 graphviz ".dot" 파일로 생성되었습니다.Tim Caswell의 "Learning JavaScript with Object Graphs"는 그래프에 GraphViz를 사용한 영감을 주었습니다.

마크의 답변과 경쟁하고 싶지는 않지만 Javascript 상속과 그 원형 체인의 새로운 사람으로서 마침내 모든 것을 클릭하게 만든 작품을 강조하고 싶었다.

속성 읽기만 프로토타입 체인을 검색하며 쓰기는 검색하지 않습니다.그래서 설정했을 때

myObject.prop = '123';

쇠사슬을 찾아보는 건 아니지만

myObject.myThing.prop = '123';

쓰기 작업에서는 소품에 쓰기 전에 mything을 검색하려고 하는 미묘한 판독이 이루어지고 있습니다.그렇기 때문에 자녀로부터 object.properties에 쓰는 것은 부모의 오브젝트에 도달합니다.

@Scott Driscoll의 답변에 javascript를 사용한 시제품 상속 예를 추가하고 싶습니다.EcmaScript 5 사양의 일부인 Object.create()와 함께 기존 상속 패턴을 사용합니다.

먼저 "Parent" 객체 함수를 만듭니다.

function Parent(){

}

그런 다음 "상위" 객체 함수에 프로토타입을 추가합니다.

 Parent.prototype = {
 primitive : 1,
 object : {
    one : 1
   }
}

"하위" 개체 함수 만들기

function Child(){

}

하위 프로토타입 할당(하위 프로토타입이 상위 프로토타입에서 상속되도록 함)

Child.prototype = Object.create(Parent.prototype);

적절한 "하위" 프로토타입 생성자 할당

Child.prototype.constructor = Child;

하위 프로토타입에 메서드 "changeProps"를 추가합니다. 그러면 하위 개체의 "primitive" 속성 값이 다시 작성되고 하위 개체와 상위 개체 모두에서 "object.one" 값이 변경됩니다.

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

부모(아빠) 및 자식(아들) 개체를 시작합니다.

var dad = new Parent();
var son = new Child();

Call Child(아들) change Props 메서드

son.changeProps();

결과를 확인합니다.

상위 기본 속성이 변경되지 않았습니다.

console.log(dad.primitive); /* 1 */

하위 기본 속성이 변경됨(다시 표시됨)

console.log(son.primitive); /* 2 */

Parent and Child object.속성 1개가 변경되었습니다.

console.log(dad.object.one); /* 2 */
console.log(son.object.one); /* 2 */

여기의 작업 예: http://jsbin.com/xexurukiso/1/edit/

Object.create에 대한 자세한 내용은 https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/create를 참조하십시오.

언급URL : https://stackoverflow.com/questions/14049480/what-are-the-nuances-of-scope-prototypal-prototypical-inheritance-in-angularjs

반응형