oop 유전 작용이 있는 angularjs
추상적인
클라이언트측 프레임워크로서 angular를 사용하고 있는 어플리케이션, angular rocks를 사용하고 있습니다만, 현재는 클래스 계층에 정리하고 싶은 코드를 카피앤페이스트 하는 것이 많이 사용되고 있습니다. 대화 는 공통 닫아야 .이러한 는 「닫아야 합니다」, 「열고 닫다」를 합니다.typeahead기능은 일부 상위 BaseTypeaheadClass에서 상속받는 첫 번째 후보이기도 합니다. 단, 각도에서는 이러한 계층을 표준적으로 구성하는 방법을 찾을 수 없었습니다. 모두 , 그 는 Javascript 기능을 통해 합니다.이 함수는 다음과 같습니다.prototype그래서 질문이 있습니다.
질문.
내 클래스 함수를 구성하는 각도 방법은 무엇입니까? 한 클래스를 다른 클래스에서 파생할 수 있는 표준 메커니즘이 있습니까?
추신.
이 문제에 대한 나의 추측:
- 기본 클래스의 구현을 서비스로 정의하면 특정 클래스가 필요한 컨트롤러 또는 기타 서비스에 쉽게 도입됩니다.
- 의 정의
OOP를define,derivebase등
편집
내가 처음 질문을 했을 때부터 시간이 좀 흘렀다.그 후, 몇개의 프로젝트에 성공해, 매우 마음에 들고, 모두에게 공유하고 싶은 어프로치를 생각해 냈습니다.
현재 angular는 클래스 계층을 구성하기 위한 어떠한 구성도 제공하지 않고 있으며, 다소 큰 응용 프로그램으로는 모델/뷰/컨트롤러만 충분할 수 없기 때문에 유감입니다.코드를 OOP 오브젝트로 정리해야 합니다.
저는 이미 웹 개발 분야에서 오랫동안 일하고 있는데 JavaScript에 의한 OOP를 대량으로 활용한 엔터프라이즈 프로젝트는 단 한 건도 본 적이 없습니다.제가 본 것은 거대하고 깔끔하게 정리된 서버측/데이터베이스측 로직 + 클라이언트측의 프레임워크와 라이브러리의 동물원에 의해 기름칠된 무한 Javascript 스파게티입니다.
MVVM, mvp 프레임워크(knocko.js, backbone 등)는 없습니다.OOP를 대체할 수 있습니다.클래스, 오브젝트, 상속, 추상화, 폴리모르피즘 등의 핵심 프로그래밍 원칙을 사용하지 않는 경우, 매우 긴 Javascript 스파게티로 끝납니다.
Angular에 관해서는 knocko.js/backbone.js/다른 MVV-anything 프레임워크와는 매우 다른 프레임워크라고 생각합니다만, 제 실무에 의하면 OOP를 대체할 수 있는 실버블렛도 아닙니다.OOP를 Angular와 함께 사용하지 않으려고 하면 대부분 컨트롤러에 있는 중복 로직이 발생합니다.그리고 불행히도 그 문제를 해결할 수 있는 깨끗하고 각진 방법은 없다.
하지만 나는 그 문제를 성공적으로 해결했다고 생각한다.
Lib를 콤팩트한 lib를 John Resig's Simple JavaScript Inheritance( https://github.com/tracker1/core-js/blob/master/js-extensions/040-Class.js) )를 참조해 주세요.그 라이브러리의 도움으로 추상적인 메서드를 작성/상속/작성/덮어쓰기, 즉 서버 측에서 익숙한 모든 것을 수행할 수 있었습니다.
다음은 사용 예를 제시하겠습니다.
Application.factory('SomeChildObject', ['$http', 'SomeParentClass', function ($http, SomeParentClass) {
var SomeChildClass = SomeParentClass.extend({
init: function() { // Constructor
this._super.init(123, 231); // call base constructor
},
someFunction: function() {
// Notice that your OOP now knows everything that can be injected into angular service, which is pretty cool :)
$http({method: 'GET', url: '/someUrl'}).then(function(){
this._super.someFunction(); // call base function implementation
});
}
});
// return new SomeChildClass(); // We are not returning instance here!
return SomeChildClass; // Service is a function definition not an instance of an object
}]);
// So now we can both use this service in angular and have the ability to extend it using the `extend` method call, like so:
Application.controller('MegaController', ['$scope', 'SomeChildClass', function ($scope, SomeChildClass) {
$scope.someObject = new SomeChildClass();
}]);
OOP + Angular는 매우 적절하게 연동됩니다.Angular Context에서 작성된 객체는 서비스를 통한 의존성 주입을 자동으로 이용할 수 있으므로 OOP 컨스트럭터에 인스턴스를 삽입할 필요가 없습니다.이 때문에 OOP 계층은 매우 슬림하고 Angular.js에 의해 처리되어야 하는 관련 없는 것이 없어집니다.
이 접근방식을 사용하여 얻은 결과나 문제에 대한 피드백을 제공합니다.
다른 편집
최근 Class.js의 원래 실장에서는 다음과 같은 문제가 거의 발생하지 않았습니다.
1), 메서드는 수 .)그들은 에 대한 언급을 느슨하게 할 것이다.this에는 지금 이 안에 것을 될 this이거나 둘 중 하나입니다.Window아키텍처에 합니다.자바스크립트 특별한 것을 했습니다.ClassMember.Class시 (체크박스를 켜다)Usage★★★★★★★★★★★★★★★★★★」
) 오리지널 2) ★★★★★★★★★★★★★★★★★★★★★★★★★★」Class.js구현은 컨트롤러 방식 선언의 각도 유형에 대해 전혀 알지 못합니다.
Class.extend('YourClassDisplayName', {
ctor: function () {
// Some useful constructor logic
},
controller: ['$scope', '$attrs', function ($scope, $attrs) {
// Do something with $scope and $attrs
}]
});
현재 구현에서는 위의 구문을 이해하고 있습니다.
3) 적절한 취급을 하지 않고 위의 방법을 사용할 경우 각도가 깨질 수 있음$$annotate'위의 예를 참조하면 주입이 불가능해진다'$scope그리고.$attrs으로.ClassMember메서드 또는 를 사용하는 재정의된 메서드this.base(...)츠키노
Gotchas:
사용시 1) this.base(...)핸들러 내(「」등)$http.get(..., function() { self.base(...); })this.base(...) 타임이 , 가 「」를 콜의 라이프 타임이 한정되어 있습니다.this.base(...)가 존재하지 않게 됩니다. 기본
...
var self = this;
var base = this.base;
...
$http.get(..., function () {
base.call(self, ...); // or base.apply(self, ...), or base() if you don't care about `this`
})
위의 모든 문제를 해결했습니다(JavaScript 아키텍처로 인해 해결할 수 없는 gotcha를 제외).여러분들과 공유하겠습니다.이것에서 혜택을 받으시기 바랍니다.
/* Simple JavaScript Inheritance
* By John Resig http://ejohn.org/
* MIT Licensed.
*
* Inspired by base2 and Prototype
* Angular adaptations by Denis Yaremov http://github.com/lu4
* Usage:
---------------------------------
var X = Class.extend('X', {
ctor: function () {
this.name = "I'm X";
},
myOrdinaryMethod: function (x, y, z) {
console.log([this.name, x, y, z]);
},
myClassMemberMethod: ClassMember(function (x, y, z) {
console.log([this.name, x, y, z]);
})
});
var Y = Class.extend('Y', {
ctor: function () {
this.name = "I'm Y";
},
myOrdinaryMethod: function (x, y, z) {
console.log([this.name, x, y, z]);
},
myClassMemberMethod: ClassMember(function (x, y, z) {
console.log([this.name, x, y, z]);
})
});
var x = new X();
var y = new Y();
x.myClassMemberMethod('a', 'b', 'c'); // ["I'm X", "a", "b", "c"]
y.myClassMemberMethod('u', 'v', 'm'); // ["I'm Y", "u", "v", "m"]
x.myOrdinaryMethod('a', 'b', 'c'); // ["I'm X", "a", "b", "c"]
y.myOrdinaryMethod('u', 'v', 'm'); // ["I'm Y", "u", "v", "m"]
y.theirOrdinaryMethod = x.myOrdinaryMethod;
y.theirClassMemberMethod = x.myClassMemberMethod;
y.theirOrdinaryMethod('a', 'b', 'c'); // ["I'm Y", "a", "b", "c"]
y.theirClassMemberMethod('u', 'v', 'm'); // ["I'm X", "u", "v", "m"]
*/
angular.module('app').factory('ClassMember', function () {
return function ClassMember(fn) {
if (this instanceof ClassMember) {
this.fn = fn;
} else {
return new ClassMember(fn);
}
};
});
angular.module('app').factory('Class', function (ClassMember) {
var runtime = { initializing: false },
fnTest = /xyz/.test(function() { xyz; }) ? /\bbase\b/ : /.*/,
FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m,
STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
var toString = Object.prototype.toString;
// The base Class implementation (does nothing)
function Class() { };
Class.members = { };
// Create a new Class that inherits from this class
Class.extend = function extend(displayName, properties) {
var array;
var targetMembers = {};
var sourceMembers = this.members;
for (var memberName in sourceMembers) {
if (sourceMembers.hasOwnProperty(memberName)) {
targetMembers[memberName] = sourceMembers[memberName];
}
}
var base = this.prototype;
// Instantiate a base class (but only create the instance,
// don't run the ctor constructor)
runtime.initializing = true;
var prototype = new this();
runtime.initializing = false;
// Copy the properties over onto the new prototype
for (var name in properties) {
if (properties.hasOwnProperty(name)) {
// Check if we're overwriting an existing function
var property = properties[name];
// Support angular's controller/service/factory declaration notation
if (toString.call(property) === '[object Array]') {
array = property;
var item = array[array.length - 1];
if (toString.call(item) === '[object Function]' || item instanceof ClassMember) {
property = array[array.length - 1];
} else {
array = null;
}
} else {
array = null;
}
var isClassMember = property instanceof ClassMember;
if (isClassMember) {
property = property.fn;
}
if (typeof property === "function") {
if (typeof base[name] === "function" && fnTest.test(property)) {
property = (function (propertyName, fn) {
var args = fn.toString().replace(STRIP_COMMENTS, '').match(FN_ARGS)[1];
return (new Function('propertyName', 'fn', 'base', 'return function (' + args + ') {\n\
var prevBase = this.base;\n\
var hasBase = "base" in this;\n\
\n\
// Add a new .base() method that is the same method\n\
// but on the super-class\n\
\n\
this.base = base[propertyName];\n\
\n\
// The method only need to be bound temporarily, so we\n\
// remove it when we\'re done executing\n\
var ret = fn.call(this' + (!!args ? (', ' + args) : args) + ');\n\
\n\
if (hasBase) {\n\
this.base = prevBase;\n\
} else {\n\
delete this["base"];\n\
}\n\
return ret;\n\
}'))(propertyName, fn, base);
})(name, property);
}
if (isClassMember) {
targetMembers[name] = property;
} else if (name in targetMembers) {
delete targetMembers[name];
}
if (array) {
array[array.length - 1] = property;
property = array;
}
prototype[name] = property;
} else {
prototype[name] = property;
}
}
}
var membersArray = [];
for (var i in targetMembers) {
if (targetMembers.hasOwnProperty(i)) {
membersArray.push({ name: i, fn: targetMembers[i] });
}
}
// All construction is actually done in the ctor method
var ChildClass = (new Function("runtime", "members", "FN_ARGS", "STRIP_COMMENTS", "return function " + (displayName || "Class") + "() {\n\
if (!runtime.initializing && this.ctor)\n\
{\n\
var length = members.length;\n\
for (var i = 0; i < length; i++)\n\
{\n\
var item = members[i];\n\
this[item.name] = (function (me, fn) {\n\
var args = fn.toString().replace(STRIP_COMMENTS, '').match(FN_ARGS)[1];\n\
return args ? (new Function('me', 'fn', 'return function (' + args + ') { return fn.call(me, ' + args + '); }'))(me, fn) : function () { return fn.call(me); };\n\
})(this, item.fn);\n\
\n\
}\n\
this.ctor.apply(this, arguments);\n\
}\n\
}"))(runtime, membersArray, FN_ARGS, STRIP_COMMENTS);
ChildClass.members = targetMembers;
// Populate our constructed prototype object
ChildClass.prototype = prototype;
// Enforce the constructor to be what we expect
ChildClass.prototype.constructor = ChildClass;
// And make this class extendable
ChildClass.extend = extend;
return ChildClass;
};
return Class;
});
다른 편집
결국 저는 원래 John Resig의 angular와 관련된 다른 문제를 발견하게 되었습니다.이 문제는 Function.protype.toString()과 일부 Regex를 사용하여 의존관계 이름을 추출하는 angular의 주석 프로세스(의존성 주입에 사용됨)와 관련이 있습니다.그리고 원래 구현의 문제는 이것이 예상되지 않는다는 것입니다. 따라서 종속성을 받아들이는 방법을 선언할 수 없기 때문에 앞서 설명한 문제를 해결하기 위해 구현을 약간 조정했습니다.다음은 예를 제시하겠습니다.
/* Simple JavaScript Inheritance
* By John Resig http://ejohn.org/
* MIT Licensed.
*
* Inspired by base2 and Prototype
* Angular adaptations by Denis Yaremov http://github.com/lu4
* Usage:
---------------------------------
var X = Class.extend('X', {
ctor: function () {
this.name = "I'm X";
},
myOrdinaryMethod: function (x, y, z) {
console.log([this.name, x, y, z]);
},
myClassMemberMethod: ClassMember(function (x, y, z) {
console.log([this.name, x, y, z]);
})
});
var Y = Class.extend('Y', {
ctor: function () {
this.name = "I'm Y";
},
myOrdinaryMethod: function (x, y, z) {
console.log([this.name, x, y, z]);
},
myClassMemberMethod: ClassMember(function (x, y, z) {
console.log([this.name, x, y, z]);
})
});
var x = new X();
var y = new Y();
x.myClassMemberMethod('a', 'b', 'c'); // ["I'm X", "a", "b", "c"]
y.myClassMemberMethod('u', 'v', 'm'); // ["I'm Y", "u", "v", "m"]
x.myOrdinaryMethod('a', 'b', 'c'); // ["I'm X", "a", "b", "c"]
y.myOrdinaryMethod('u', 'v', 'm'); // ["I'm Y", "u", "v", "m"]
y.theirOrdinaryMethod = x.myOrdinaryMethod;
y.theirClassMemberMethod = x.myClassMemberMethod;
y.theirOrdinaryMethod('a', 'b', 'c'); // ["I'm Y", "a", "b", "c"]
y.theirClassMemberMethod('u', 'v', 'm'); // ["I'm X", "u", "v", "m"]
*/
angular.module('homer').factory('Class', function () {
function ClassMember(fn) {
if (this instanceof ClassMember) {
this.fn = fn;
return this;
} else {
return new ClassMember(fn);
}
}
function ClassEvent() {
if (this instanceof ClassEvent) {
return this;
} else {
return new ClassEvent();
}
}
var runtime = { initializing: false },
fnTest = /xyz/.test(function () { xyz; }) ? /\bbase\b/ : /.*/,
fnArgs = /^function\s*[^\(]*\(\s*([^\)]*)\)/m,
stripComments = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
var toString = Object.prototype.toString;
// The base Class implementation (does nothing)
function Class() { };
Class.events = {};
Class.members = {};
// Create a new Class that inherits from this class
Class.extend = function Extend(displayName, properties) {
var array;
var targetEvents = {};
var sourceEvents = this.events;
var targetMembers = {};
var sourceMembers = this.members;
for (var eventName in sourceEvents) {
if (sourceEvents.hasOwnProperty(eventName)) {
targetEvents[eventName] = sourceEvents[eventName];
}
}
for (var memberName in sourceMembers) {
if (sourceMembers.hasOwnProperty(memberName)) {
targetMembers[memberName] = sourceMembers[memberName];
}
}
var base = this.prototype;
// Instantiate a base class (but only create the instance,
// don't run the ctor constructor)
runtime.initializing = true;
var prototype = new this();
runtime.initializing = false;
// Copy the properties over onto the new prototype
for (var name in properties) {
if (properties.hasOwnProperty(name)) {
// Check if we're overwriting an existing function
var property = properties[name];
// Support angular's controller/service/factory declaration notation
if (toString.call(property) === '[object Array]') {
array = property;
var item = array[array.length - 1];
if (toString.call(item) === '[object Function]' || item instanceof ClassMember) {
property = array[array.length - 1];
} else {
array = null;
}
} else {
array = null;
}
var isClassMember = property instanceof ClassMember;
if (isClassMember) {
property = property.fn;
}
var isClassEvent = property instanceof ClassEvent;
if (isClassEvent) {
property = (function() {
function Subscriber(fn) {
Subscriber.listeners.push(fn.bind(this));
};
Subscriber.listeners = [];
Subscriber.fire = function() {
var listeners = Subscriber.listeners;
for (var i = 0; i < listeners.length; i++) {
var result = listeners[i].apply(this, arguments);
if (result !== undefined) return result;
}
return void 0;
}
return Subscriber;
})();
}
if (typeof property === "function") {
if (typeof base[name] === "function" && fnTest.test(property)) {
property = (function (propertyName, fn) {
var args = fn.toString().replace(stripComments, '').match(fnArgs)[1];
return (new Function('propertyName', 'fn', 'base', 'return function (' + args + ') {\n\
var prevBase = this.base;\n\
var hasBase = "base" in this;\n\
\n\
// Add a new .base() method that is the same method\n\
// but on the super-class\n\
\n\
this.base = base[propertyName];\n\
\n\
// The method only need to be bound temporarily, so we\n\
// remove it when we\'re done executing\n\
var ret = fn.call(this' + (!!args ? (', ' + args) : args) + ');\n\
\n\
if (hasBase) {\n\
this.base = prevBase;\n\
} else {\n\
delete this["base"];\n\
}\n\
return ret;\n\
}'))(propertyName, fn, base);
})(name, property);
}
if (isClassEvent) {
targetEvents[name] = property;
} else {
delete targetEvents[name];
}
if (isClassMember) {
targetMembers[name] = property;
} else if (name in targetMembers) {
delete targetMembers[name];
}
if (array) {
array[array.length - 1] = property;
property = array;
}
prototype[name] = property;
} else {
prototype[name] = property;
}
}
}
var eventsArray = [];
for (var targetEventName in targetEvents) {
if (targetEvents.hasOwnProperty(targetEventName)) {
eventsArray.push({ name: targetEventName, fn: targetEvents[targetEventName] });
}
}
var membersArray = [];
for (var targetMemberName in targetMembers) {
if (targetMembers.hasOwnProperty(targetMemberName)) {
membersArray.push({ name: targetMemberName, fn: targetMembers[targetMemberName] });
}
}
// All construction is actually done in the ctor method
var ChildClass = (new Function("runtime", "events", "members", "FN_ARGS", "STRIP_COMMENTS", "return function " + (displayName || "Class") + "() {\n\
if (!runtime.initializing && this.ctor)\n\
{\n\
var length = members.length;\n\
var bind = function (me, $$fn$$) {\n\
var args = $$fn$$.toString().replace(STRIP_COMMENTS, '').match(FN_ARGS)[1];\n\
var result = args ? (new Function('me', '$$fn$$', 'return function (' + args + ') { return $$fn$$.apply(me, arguments); }'))(me, $$fn$$) : function () { return $$fn$$.apply(me, arguments); };\n\
return result;\n\
};\n\
for (var i = 0; i < length; i++)\n\
{\n\
var item = members[i];\n\
var fn = item.fn;\n\
var name = item.name;\n\
var property = this[name] = bind(this, fn);\n\
if (fn.fire) {\n\
property.fire = bind(this, fn.fire);\n\
}\n\
if (fn.listeners) {\n\
property.listeners = fn.listeners;\n\
}\n\
}\n\
\n\
var length = events.length;\n\
for (var i = 0; i < length; i++)\n\
{\n\
var item = events[i];\n\
var fn = item.fn;\n\
var name = item.name;\n\
var property = this[name] = bind(this, fn);\n\
if (fn.fire) {\n\
property.fire = bind(this, fn.fire);\n\
}\n\
if (fn.listeners) {\n\
property.listeners = fn.listeners;\n\
}\n\
}\n\
this.ctor.apply(this, arguments);\n\
}\n\
}"))(runtime, eventsArray, membersArray, fnArgs, stripComments);
ChildClass.members = targetMembers;
// Populate our constructed prototype object
ChildClass.prototype = prototype;
// Enforce the constructor to be what we expect
ChildClass.prototype.constructor = ChildClass;
// And make this class extendable
ChildClass.extend = Extend;
ChildClass.event = ClassEvent;
ChildClass.member = ClassMember;
return ChildClass;
};
Class.member = ClassMember;
Class.event = ClassEvent;
return Class;
});
당신의 추측은 완벽하게 들어맞는 것 같군요.
부모 스코프에 부가된 메서드를 호출하는 것만으로 부모 컨트롤러에 정의되어 있는 기능을 재사용할 수 있습니다.
HTML
<div ng-controller="ParentCtrl">
<!-- Something here ... -->
<div ng-controller="ChildCtrl">
<!-- Something here ... -->
</div>
<!-- Something here ... -->
</div>
자바스크립트
function ParentCtrl($scope) {
$scope.parentMethod = function () {
//method body
};
}
function ChildCtrl($scope) {
$scope.childMethod = function () {
//functionality
$scope.parentMethod();
//functionality
};
}
프로토타입 상속과 함께 JavaScript 방식을 사용하려는 경우 다음을 사용할 수 있습니다.
var myApp = angular.module('myApp',[]);
function Parent($scope) {
$scope.name = 'Superhero';
$scope.clickParent = function() {
$scope.name = 'Clicked from base controller';
}
}
function Child($scope, $injector) {
debugger;
$injector.invoke(Parent, this, {$scope: $scope});
$scope.name = 'Superhero Child';
$scope.clickChild = function(){
$scope.clickParent();
}
}
Child.prototype = Object.create(Parent.prototype);
http://jsfiddle.net/mhevery/u6s88/12/
예를 들어 서비스의 경우 다음을 사용할 수 있습니다.
(function () {
function ParentService(arg1) {
this.arg1 = arg1;
}
function ChildService(arg1, arg2) {
ParentService.call(this, arg1);
this.arg2 = arg2;
}
ChildService.prototype = new ParentService();
app.service('ChildService', ChildService);
}());
또한 이 토론과 Angular에서의 상속에 대한 블로그 게시물을 확인하십시오.JS 제가 올렸어요.
앵글 / 상속 상황에 대한 의견을 말씀드리겠습니다.
Angular.js에서는 클래스/프로토타입 상속을 하지 않습니다.그것은 테스트하기 어려울 수 있고, 그것이 문제입니다.Angular에서 '상속'을 찾고 계신 분께는 다음을 추천합니다.
기본 클래스는 컨트롤러입니다.컨트롤러는 어쨌든 추상적인 모델이기 때문에 그 목적에 딱 맞습니다.컨트롤러에서 $scope.init() 함수를 사용하되, 거기에서 호출하지 마십시오.
컨트롤러의 기능을 '확장'하려면 디렉티브를 사용합니다.directive link() 함수로 컨트롤러의 $scope.init()를 호출합니다.(컴파일 할 때 angular run 컨트롤러가 먼저 실행되며 그 후에 Directive Link 기능이 실행됩니다).스코프에 다음이 있는 경우
$scope.name='base'에서는, 「Directive Link」에서는, 「 Link」의 「Definition$scope.name=child그 $ 、 $140.입문하다하지만 기다려!그러나 이것은 단일 수준의 상속만을 허용한다. - 네, 그렇습니다.그러나 다중 수준 상속을 원하는 경우 서비스를 사용해야 합니다.
다단계 상속은 계층 클래스 구조에서 동일한 코드를 공유하는 것 외에 다른 것은 없습니다. 이를 위해 서비스를 사용하고 이러한 서비스를 종속성 주입기와 함께 지침에 추가합니다.쉬워요.이것은 달성하기 쉽고 이해하기 쉬우며 테스트가 원활하게 진행되어야 합니다.
디렉티브는 매우 강력한 툴입니다.부분을 컨트롤러와 동적으로 결합할 수 있기 때문입니다.
당신의 추측은 꽤 좋은 것 같고, 저는 몇 가지 접근 방식을 가지고 놀았지만, 모두 제가 기대했던 것보다 더 장황하게 되었습니다.
관리 인터페이스의 탭으로 복잡한 대화 상자를 개발하는 데 문제가 있었습니다만, 사용자 섹션의 팝업에서 거의 동일한 대화 상자를 원했지만 데이터가 다른 소스에서 입력되고 버튼이 몇 개 더 있을 것입니다.기본적으로 고전적인 유전의 훌륭한 후보지.UI 측에서는 컨트롤러가 다른 두 곳에 포함된 템플릿을 사용했습니다.그러나 컨트롤러에서 복잡한 UI 로직이 중복되는 것을 방지하기 위해 상속을 사용하고 싶었습니다.
스코프 상속 방식은 애플리케이션 구조에 따라 달라지며 두 UI가 효과적으로 다른 애플리케이션에 있었기 때문에 적절하지 않았습니다.각 컨트롤러 메서드가 서비스에 대해 동등한 메서드를 호출해야 하므로 재사용된 코드를 서비스에 넣는 방법은 결국 상세하게 설명됩니다.그래서 JavaScript 상속에는 다음과 같은 간단한 방법을 사용했습니다.
/**
* Effective base class for Thing Controllers.
* This should be considered abstract since it does not define
* $scope.readData() or $scope.saveData() which may be called from its
* other functions.
*/
function BaseThingController($scope, $http){
$scope.data = []; // local data store;
$scope.validateForm(){...}
$scope.edit(){...}
$scope.cancel(){...}
$scope.reset(){...}
$scope.otherMethod1(){...}
$scope.otherMethod2(){...}
$scope.otherMethod3(){...}
}
/**
* AdminThingController effectively extends BaseThingController
*/
function AdminThingController($scope, $http){
// Calling BaseThingController as a function defines all the needed
// functions and properties in our scope.
BaseThingController($scope, $http)
$scope.readData(){
// $scope.data = data from admin data source
}
$scope.saveData(newData){
// save to special admin service
}
// initialize local data
$scope.readData()
}
/**
* UserThingController effectively extends BaseThingController
*/
function UserThingController($scope, $http){
// Calling BaseThingController as a function defines all the needed
// functions and properties in our scope.
BaseThingController($scope, $http)
$scope.readData(){
// $scope.data = data from user data source
}
$scope.saveData(newData){
// save to user service
}
/**
* Overriding base class behaviour here
*/
$scope.otherMethod1(){...}
// initialize local data
$scope.readData()
}
따라서 $scope는 쉽게 구할 수 있기 때문에 프로토타입 상속은 사용하지 않았습니다.하지만 기본 컨트롤러에서 모든 동작을 얻었고 원하는 것만 추가하거나 재정의했습니다.뷰는 어느 하나의 컨트롤러로 설정할 수 있으며 변경하지 않고 동작합니다.
언급URL : https://stackoverflow.com/questions/17389291/angularjs-with-oop-inheritance-in-action
'source' 카테고리의 다른 글
| NSManagedObject 속성 값에 대한 NSNull 처리 (0) | 2023.03.27 |
|---|---|
| 'module-name' 모듈에 대한 선언 파일을 찾을 수 없습니다.'/path/to/module-name.module'에는 암묵적으로 '임의' 유형이 있습니다. (0) | 2023.03.27 |
| @types/*가 'dependencies' 또는 'devendencies' 중 어느 쪽으로 갈지 어떻게 판단합니까? (0) | 2023.03.27 |
| 구글 앵글JS 프레임워크 - 위험을 감수할 가치가 있습니까? (0) | 2023.03.27 |
| 에서 차단되는 크로스 오리진 요구 (0) | 2023.03.27 |