Javascript에 실제로 적용 가능한 OO 원칙이 있습니까?


79

Javascript는 프로토 타입 기반 객체 지향 언어이지만 다음 중 한 가지 방법으로 클래스 기반이 될 수 있습니다.

  • 스스로 클래스로 사용할 함수 작성
  • 프레임 워크에서 멋진 클래스 시스템 사용 (예 : mootools Class.Class )
  • Coffeescript에서 생성

처음에는 Javascript로 클래스 기반 코드를 작성하는 경향이 있었고 그것에 크게 의존했습니다. 그러나 최근 에는이 클래스 개념에서 벗어나 다음과 같은 코드의 동적 특성에 더 의존 하는 Javascript 프레임 워크 및 NodeJS를 사용 했습니다.

  • 콜백 / 이벤트를 사용하는 쓰기 코드를 사용하고 쓰는 비동기 프로그래밍
  • RequireJS를 사용하여 모듈로드 (글로벌 네임 스페이스로 누출되지 않도록)
  • 목록 이해 (맵, 필터 등)와 같은 기능적 프로그래밍 개념
  • 다른 것들 사이

지금까지 수집 한 내용은 내가 읽은 대부분의 OO 원칙과 패턴 (SOLID 및 GoF 패턴 등)이 Smalltalk 및 C ++와 같은 클래스 기반 OO 언어 용으로 작성된 것입니다. 그러나 Javascript와 같은 프로토 타입 기반 언어에 적용 할 수있는 것이 있습니까?

Javascript에만 적용되는 원칙이나 패턴이 있습니까? 콜백 지옥 , 악한 평가 또는 기타 반 패턴 등 을 피하는 원칙

답변:


116

여러 번 편집 한 후이 답변의 길이는 괴물이되었습니다. 미리 사과드립니다.

우선, eval()항상 나쁘지는 않으며, 예를 들어 지연 평가에 사용될 때 성능에 이점을 가져올 수 있습니다. 게으른 평가 게으른 로딩과 유사하지만, 당신은 기본적으로 사용 후 문자열 내에서 코드를 저장하고, eval또는 new Function코드를 알아보고자 하였다. 당신이 약간의 트릭을 사용한다면, 그것은 악보다 훨씬 더 유용하게 될 것이지만, 그렇지 않으면 나쁜 일로 이어질 수 있습니다. https://github.com/TheHydroImpulse/resolve.js 패턴을 사용하는 모듈 시스템을 볼 수 있습니다 . Resolve.js는 new Function주로 각 모듈에서 사용 가능한 CommonJS exportsmodule변수 를 모델링하기 위해 eval을 사용 new Function하고 익명 함수 내에서 코드를 래핑하지만, 각 모듈을 eval과 함께 수동으로 수행하는 함수로 래핑합니다.

이에 대한 자세한 내용은 다음 두 기사에서 참조하십시오.

하모니 생성기

이제 생성기가 V8에 도착하여 Node.js에 플래그 ( --harmony또는 --harmony-generators)로 도착했습니다 . 이것들은 당신이 가지고있는 콜백 지옥의 양을 크게 줄입니다. 비동기 코드 작성이 정말 좋습니다.

생성기를 사용하는 가장 좋은 방법은 일종의 제어 흐름 라이브러리를 사용하는 것입니다. 이를 통해 발전기 내에서 생산량을 계속 유지할 수 있습니다.

요약 / 개요 :

생성기에 익숙하지 않은 경우 생성기라고하는 특수 기능의 실행을 일시 중지하는 방법입니다. 이 방법을 키워드 사용한 수익률 이라고 yield합니다.

예:

function* someGenerator() {
  yield []; // Pause the function and pass an empty array.
}

따라서이 함수를 처음 호출 할 때마다 새 생성기 인스턴스가 반환됩니다. 이를 통해 next()해당 객체 를 호출 하여 생성기를 시작하거나 다시 시작할 수 있습니다 .

var gen = someGenerator();
gen.next(); // { value: Array[0], done: false }

return next때까지 계속 호출 done합니다 true. 이는 생성기가 실행을 완전히 완료했으며 더 이상 yield명령문 이 없음을 의미 합니다.

제어 흐름 :

보시다시피 발전기 제어는 자동이 아닙니다. 각각 수동으로 계속 진행해야합니다. 이것이 co 와 같은 제어 흐름 라이브러리 가 사용되는 이유 입니다.

예:

var co = require('co');

co(function*() {
  yield query();
  yield query2();
  yield query3();
  render();
});

이를 통해 동기식 스타일 로 Node (및 Facebook의 Regenerator가 있는 브라우저에서 입력으로 하모니 제너레이터를 사용하는 소스 코드를 사용하고 완벽하게 호환되는 ES5 코드를 분리 하는 브라우저)에 모든 것을 작성할 수 있습니다 .

생성기는 여전히 새롭기 때문에 Node.js> = v11.2가 필요합니다. 이 글을 쓰는 동안 v0.11.x는 여전히 불안정하므로 많은 기본 모듈이 손상되어 기본 API가 중단되는 v0.12까지 있습니다.


원래 답변에 추가하려면 다음을 수행하십시오.

최근 JavaScript에서 더 기능적인 API를 선호하고 있습니다. 컨벤션은 필요할 때 장면 뒤에서 OOP를 사용하지만 모든 것을 단순화합니다.

보기 시스템 (클라이언트 또는 서버)을 예로 들어 보겠습니다.

view('home.welcome');

다음보다 훨씬 쉽게 읽거나 따라갈 수 있습니다 :

var views = {};
views['home.welcome'] = new View('home.welcome');

view함수는 로컬 맵에 동일한 뷰가 이미 있는지 확인합니다. 보기가 존재하지 않으면 새보기를 작성하고 새 항목을 맵에 추가합니다.

function view(name) {
  if (!name) // Throw an error

  if (view.views[name]) return view.views[name];

  return view.views[name] = new View({
    name: name
  });
}

// Local Map
view.views = {};

매우 기본적입니까? 공용 인터페이스를 크게 단순화하고 사용하기가 더 쉽다는 것을 알게되었습니다. 나는 또한 체인 기능을 사용합니다 ...

view('home.welcome')
   .child('menus')
   .child('auth')

내가 개발하고 있거나 (다른 사람과 함께) 다음 버전 (0.5.0)을 개발하고있는 프레임 워크 인 Tower는 대부분의 노출 인터페이스에서이 기능적 접근 방식을 사용합니다.

어떤 사람들은 "콜백 지옥"을 피하기 위해 섬유를 이용합니다. JavaScript와는 상당히 다른 접근 방식이며, 나는 그것을 좋아하지는 않지만 많은 프레임 워크 / 플랫폼에서 사용합니다. Node.js를 스레드 / 연결 플랫폼으로 취급하므로 Meteor를 포함합니다.

콜백 지옥을 피하기 위해 추상적 인 방법을 사용하고 싶습니다. 번거로울 수 있지만 실제 응용 프로그램 코드를 크게 단순화합니다. TowerJS 프레임 워크 구축을 도와 줄 때 많은 문제를 해결했지만 분명히 어느 정도의 콜백이 있지만 중첩이 깊지는 않습니다.

// app/config/server/routes.js
App.Router = Tower.Router.extend({
  root: Tower.Route.extend({
    route: '/',
    enter: function(context, next) {
      context.postsController.page(1).all(function(error, posts) {
        context.bootstrapData = {posts: posts};
        next();
      });
    },
    action: function(context, next) {
      context.response.render('index', context);
      next();
    },
    postRoutes: App.PostRoutes
  })
});

기존의 "레일 유사"과는 상당히 다르지만 현재 개발중인 라우팅 시스템 및 "컨트롤러"의 예입니다. 그러나이 예제는 매우 강력하고 콜백 양을 최소화하며 상황을 상당히 분명하게 만듭니다.

이 접근법의 문제점은 모든 것이 추상화된다는 것입니다. 아무것도 그대로 실행되지 않으며 그 뒤에 "프레임 워크"가 필요합니다. 그러나 이러한 종류의 기능과 코딩 스타일이 프레임 워크 내에서 구현되면 큰 승리입니다.

JavaScript의 패턴의 경우 정직하게 다릅니다. 상속은 CoffeeScript, Ember 또는 "클래스"프레임 워크 / 인프라를 사용할 때만 유용합니다. "순수한"JavaScript 환경에있을 때는 기존의 프로토 타입 인터페이스를 사용하는 것이 매력처럼 작동합니다.

function Controller() {
    this.resource = get('resource');
}

Controller.prototype.index = function(req, res, next) {
    next();
};

Ember.js는 적어도 객체 생성에 다른 접근법을 사용하기 시작했습니다. 각 프로토 타입 방법을 독립적으로 구성하는 대신 모듈 형 인터페이스를 사용합니다.

Ember.Controller.extend({
   index: function() {
      this.hello = 123;
   },
   constructor: function() {
      console.log(123);
   }
});

이들은 모두 "코딩"스타일이 다르지만 코드 기반에 추가하십시오.

다형성

상속을 사용하고 "클래스"와 같은 모델을 복사하는 데 많은 상용구 코드가 필요한 순수 JavaScript에서는 다형성이 널리 사용되지 않습니다.

이벤트 / 컴포넌트 기반 디자인

이벤트 기반 및 구성 요소 기반 모델은 IMO를 수상하거나 가장 손쉬운 작업입니다. 특히 내장 된 EventEmitter 구성 요소가있는 Node.js로 작업 할 때 이러한 이미 터를 구현하는 것은 쉽지 않습니다. .

event.on("update", function(){
    this.component.ship.velocity = 0;
    event.emit("change.ship.velocity");
});

예제 일 뿐이지 만 작업하기 좋은 모델입니다. 특히 게임 / 컴포넌트 지향 프로젝트에서.

구성 요소 디자인 자체는 별도의 개념이지만 이벤트 시스템과 함께 사용하면 매우 효과적이라고 생각합니다. 게임은 전통적으로 객체 지향 프로그래밍으로 구성 요소 기반 디자인으로 유명합니다.

구성 요소 기반 디자인에 사용됩니다. 건물의 시스템 유형에 따라 다릅니다. 웹 응용 프로그램과 함께 작동 할 것이라고 확신하지만 객체 수와 별도의 시스템으로 인해 게임 환경에서 매우 잘 작동하지만 다른 예는 반드시 존재합니다.

펍 / 서브 패턴

이벤트 바인딩과 펍 / 서브는 비슷합니다. pub / sub 패턴은 통합 언어로 인해 Node.js 애플리케이션에서 실제로 빛을 발하지만 모든 언어에서 작동 할 수 있습니다. 실시간 응용 프로그램, 게임 등에서 매우 잘 작동합니다.

model.subscribe("message", function(event){
    console.log(event.params.message);
});

model.publish("message", {message: "Hello, World"});

관찰자

일부 사람들은 관찰자 패턴을 펍 / 서브로 생각하기 때문에 주관적 일 수 있지만 차이점이 있습니다.

"관찰자 (Observer)는 개체 (주체라고도 함)가 개체 (관찰자)에 따라 개체 목록을 유지 관리하여 상태 변경을 자동으로 알려주는 디자인 패턴입니다." - 관찰자 패턴

옵저버 패턴은 일반적인 펍 / 서브 시스템을 넘어서는 단계입니다. 개체는 서로 밀접한 관계 또는 통신 방법을 갖습니다. "제목"개체는 종속 항목 "관찰자"를 유지합니다. 대상은 관찰자의 최신 상태를 유지합니다.

반응성 프로그래밍

리 액티브 프로그래밍은 특히 JavaScript에서 더 작고 알려지지 않은 개념입니다. 이 "반응 형 프로그래밍"을 사용하기 위해 API로 쉽게 작업 할 수있는 하나의 프레임 워크 / 라이브러리 (내가 아는 것)가 있습니다.

반응 형 프로그래밍에 대한 리소스 :

기본적으로 동기화 데이터 세트 (변수, 함수 등)가 있습니다.

 var a = 1;
 var b = 2;
 var c = a + b;

 a = 2;

 console.log(c); // should output 4

반응성 프로그래밍은 특히 명령형 언어에서 상당히 숨겨져 있다고 생각합니다. 특히 Node.js에서 놀랍도록 강력한 프로그래밍 패러다임입니다. Meteor 는 기본적으로 프레임 워크를 기반으로하는 자체 반응 형 엔진을 만들었습니다. Meteor의 반응성은 무대 뒤에서 어떻게 작용합니까? 내부적으로 작동하는 방법에 대한 훌륭한 개요입니다.

Meteor.autosubscribe(function() {
   console.log("Hello " + Session.get("name"));
});

이것은 정상적으로 실행되고의 값을 표시 name하지만 값을 변경하면

Session.set ( 'name', 'Bob');

console.log가 다시 출력됩니다 Hello Bob. 기본적인 예이지만이 기술을 실시간 데이터 모델 및 트랜잭션에 적용 할 수 있습니다. 이 프로토콜 뒤에 강력한 시스템을 만들 수 있습니다.

유성 ...

반응 패턴과 관찰자 패턴은 매우 유사합니다. 주요 차이점은 관찰자 패턴이 전체 객체 / 클래스를 사용하여 데이터 흐름을 일반적으로 설명하고 반응 프로그래밍은 특정 속성에 대한 데이터 흐름을 설명한다는 것입니다.

Meteor 는 반응 형 프로그래밍의 훌륭한 예입니다. JavaScript에는 기본 값 변경 이벤트가 없기 때문에 런타임이 약간 복잡합니다 (하모니 프록시가 변경). 다른 클라이언트 측 프레임 워크 인 Ember.jsAngularJS 도 반응성 프로그래밍 (일부 확장)을 사용합니다.

후자의 두 프레임 워크는 템플릿에서 반응성 패턴을 가장 많이 사용합니다 (즉, 자동 업데이트). Angular.js는 간단한 더티 검사 기술을 사용합니다. 나는 이것을 정확하게 반응하는 프로그래밍이라고 부르지는 않지만 더티 검사는 실시간이 아니기 때문에 가깝습니다. Ember.js는 다른 접근법을 사용합니다. 값에 따라 즉시 업데이트 할 수있는 Ember 사용 set()get()방법 런 루프를 사용하면 매우 효율적이며 각도에 이론적 한계가있는 더 많은 종속 값을 허용합니다.

약속

콜백에 대한 수정은 아니지만 들여 쓰기를 수행하고 중첩 함수를 최소로 유지합니다. 또한 문제에 좋은 구문을 추가합니다.

fs.open("fs-promise.js", process.O_RDONLY).then(function(fd){
  return fs.read(fd, 4096);
}).then(function(args){
  util.puts(args[0]); // print the contents of the file
});

콜백 함수를 확장하여 인라인이 아닌 다른 디자인 결정입니다.

또 다른 방법은 이벤트와 약속을 결합하여 이벤트를 적절하게 디스패치하는 기능이있는 곳으로, 실제 기능 함수 (실제로 논리가있는 기능)는 특정 이벤트에 바인딩됩니다. 그런 다음 각 콜백 위치 내에서 디스패처 메소드를 전달하지만 매개 변수, 디스패치 할 함수 알기 등과 같이 염두에 두어야 할 문제를 해결해야합니다.

단일 기능 기능

콜백 지옥을 망쳐 놓는 대신 단일 기능을 단일 작업으로 유지하고 해당 작업을 잘 수행하십시오. 때때로 당신은 자신보다 앞서서 각 기능 내에서 더 많은 기능을 추가 할 수 있지만, 스스로에게 물어보십시오 : 이것은 독립적 인 기능이 될 수 있습니까? 함수의 이름을 지정하면 들여 쓰기가 정리되고 결과적으로 콜백 지옥 문제가 정리됩니다.

결국, 작은 "프레임 워크"를 개발하거나 사용하는 것이 좋습니다. 기본적으로 응용 프로그램을위한 백본 일뿐입니다. 추상화를하거나 이벤트 기반 시스템을 결정하거나 " 독립적 인 "시스템. 나는 코드가 특히 콜백 지옥으로 지저분하지만 코딩을 시작하기 전에 생각이 부족한 여러 Node.js 프로젝트를 다루었습니다. API 및 구문 측면에서 다양한 가능성을 생각할 시간을 가지십시오.

벤 나델 (Ben Nadel) 은 JavaScript에 관한 좋은 블로그 글과 여러분의 상황에서 작동 할 수있는 매우 엄격하고 진보 된 패턴을 만들었습니다. 내가 강조 할 좋은 글들 :

제어 역전

콜백 지옥과 정확히 관련이 없지만 전반적인 아키텍처, 특히 단위 테스트에서 도움이 될 수 있습니다.

제어 역전의 두 가지 주요 하위 버전은 종속성 주입 및 서비스 로케이터입니다. Dependency Injection과는 달리 JavaScript에서 Service Locator가 가장 쉬운 것으로 나타났습니다. 왜? 주로 JavaScript는 동적 언어이며 정적 입력이 없기 때문입니다. Java와 C #은 유형을 감지 할 수 있고 인터페이스, 클래스 등이 내장되어 있기 때문에 종속성 주입에 대해 "알려져"있습니다. 이는 상당히 쉬운 작업입니다. 그러나 JavaScript 내 에서이 기능을 다시 만들 수는 있지만 동일하지 않고 약간 해 키지 않을 것입니다. 시스템 내에서 서비스 로케이터를 사용하는 것이 좋습니다.

모든 종류의 제어 역전은 언제든지 조롱하거나 위조 할 수있는 별도의 모듈로 코드를 크게 분리합니다. 렌더링 엔진의 두 번째 버전을 설계 했습니까? 굉장히, 기존 인터페이스를 새로운 인터페이스로 대체하십시오. Service Locator는 새로운 Harmony Proxies에 특히 흥미롭지 만 Node.js 내에서만 효과적으로 사용할 수 있기 때문에 Service.get('render');및 대신 사용하는 대신 보다 나은 API를 제공합니다 Service.render. 나는 현재 https://github.com/TheHydroImpulse/Ettore 시스템에서 일하고 있습니다 .

정적 타이핑 부족 (정적 타이핑은 Java, C #, PHP의 의존성 주입에서 효과적인 사용법의 가능한 원인 일 수 있지만 정적 타입은 아니지만 타입 힌트가 있음)이 부정적인 점으로 보일 수 있습니다. 확실히 좋은 점으로 바꾸십시오. 모든 것이 동적이므로 "가짜"정적 시스템을 엔지니어링 할 수 있습니다. 서비스 로케이터와 함께 각 구성 요소 / 모듈 / 클래스 / 인스턴스를 유형에 연결할 수 있습니다.

var Service, componentA;

function Manager() {
  this.instances = {};
}

Manager.prototype.get = function(name) {
  return this.instances[name];
};

Manager.prototype.set = function(name, value) {
  this.instances[name] = value;
};

Service = new Manager();
componentA = {
  type: "ship",
  value: new Ship()
};

Service.set('componentA', componentA);

// DI
function World(ship) {
  if (ship === Service.matchType('ship', ship))
    this.ship = new ship();
  else
    throw Error("Wrong type passed.");
}

// Use Case:
var worldInstance = new World(Service.get('componentA'));

간단한 예입니다. 현실 세계에서 효과적인 사용을 위해서는이 개념을 더 발전시켜야하지만 전통적인 의존성 주입을 원한다면 시스템을 분리하는 데 도움이 될 수 있습니다. 이 개념을 약간 다루어야 할 수도 있습니다. 이전 예제에 대해서는 많이 생각하지 않았습니다.

모델 뷰 컨트롤러

가장 명백한 패턴이며 웹에서 가장 많이 사용됩니다. 몇 년 전, JQuery는 모든 분노로 인해 JQuery 플러그인이 탄생했습니다. 클라이언트 측에서 완전한 프레임 워크가 필요하지 않고 jquery와 몇 가지 플러그인 만 사용하십시오.

이제 클라이언트 측 JavaScript 프레임 워크가 엄청납니다. 대부분 MVC 패턴을 사용하며 모두 다르게 사용합니다. MVC가 항상 동일하게 구현되는 것은 아닙니다.

전통적인 프로토 타입 인터페이스를 사용하는 경우 수동 작업을 원하지 않는 한 MVC 작업시 구문 설탕이나 멋진 API를 얻는 데 어려움을 겪을 수 있습니다. Ember.js는 "클래스"/ 오브젝트 "시스템을 생성하여이 문제를 해결합니다.

 var Controller = Ember.Controller.extend({
      index: function() {
        // Do something....
      }
 });

대부분의 클라이언트 측 라이브러리는 뷰 헬퍼 (뷰가 됨) 및 템플릿 (뷰가 됨)을 도입하여 MVC 패턴을 확장합니다.


새로운 JavaScript 기능 :

이것은 Node.js를 사용하는 경우에만 효과적이지만 그럼에도 불구하고 매우 중요합니다. Brendan Eich의 NodeConf에서 진행되는이 대화에는 멋진 새 기능이 추가되었습니다. 제안 된 함수 구문, 특히 Task.js js 라이브러리

이것은 아마도 함수 중첩과 관련된 대부분의 문제를 해결하고 함수 오버 헤드가 없기 때문에 성능이 약간 향상됩니다.

V8 이이 기능을 기본적으로 지원하는지 확실하지 않습니다. 마지막으로 일부 플래그를 활성화해야한다는 것을 확인했지만 SpiderMonkey를 사용하는 Node.js 포트에서 작동합니다 .

추가 자료 :


2
좋은 글씨. 개인적으로 MV를 사용하지 않습니까? 도서관. 더 복잡한 앱을 위해 코드를 구성하는 데 필요한 모든 것이 있습니다. 그들은 모두 서버 클라이언트 통신에서 실제로 일어난 일에 대해 자신의 다양한 쓰레기통을 던지려 고하는 Java 및 C #을 너무 많이 상기시킵니다. 우리는 DOM을 얻었다. 이벤트 대표단이 있습니다. 우리는 OOP를 얻었다. 내 이벤트를 데이터 변경 tyvm에 바인딩 할 수 있습니다.
Erik Reppen 2016 년

2
"콜백을 망쳐 버리는 대신 단일 기능을 단일 작업으로 유지하고 그 작업을 잘 수행하십시오." - 시.
CuriousWebDeveloper

1
2000 년대 초반에서 중반에 매우 어두운시기에 자바 스크립트를 사용하여 큰 응용 프로그램을 작성하는 방법을 거의 이해하지 못한 자바 스크립트. @ErikReppen이 말했듯이 JS 응용 프로그램이 Java 또는 C # 응용 프로그램처럼 보이는 경우 잘못하고 있습니다.
backpackcoder

3

Daniels 답변에 추가 :

관찰 가능한 값 / 구성 요소

이 아이디어는 MVVM 프레임 워크 Knockout.JS ( ko.observable ) 에서 차용되었으며, 값과 객체는 관찰 가능한 주제가 될 수 있으며 한 값이나 객체에서 변경이 발생하면 모든 관찰자가 자동으로 업데이트됩니다. 기본적으로 Javascript로 구현 된 옵저버 패턴이며, 대부분의 pub / sub 프레임 워크가 구현되는 방식 인 "키"는 임의의 객체가 아닌 주제 자체입니다.

사용법은 다음과 같습니다.

// the subjects
// plain old javascript object with observable values
var shipComponent = {
    velocity : observable(0)
};

// the observer, a player user interface
// implemented with revealing module pattern
var playerUi = (function(ship) {

  var module = {
    setVelocity: function (x) { 
      // ... sets the velocity on the player user interface
    },

    // only called once
    init: function() {

      // subscribe to changes on the velocity value
      // using the module's function as callback
      module.velocity.onChange(playerUi.setVelocity);
    }
  };

  return module;
})(shipComponent).init();

// the player ui will change when the velocity value is changed
shipComponent.velocity.set(10);

아이디어는 일반적으로 관찰자가 주제의 위치와 구독 방법을 알고 있다는 것입니다. pub / sub 대신에 이것의 장점은 리팩토링 단계에서 주제를 제거하는 것이 더 쉽기 때문에 코드를 많이 변경해야하는 경우 눈에 able니다. 나는 당신이 주제를 제거하면 그것에 의존하는 모든 사람들이 실패하기 때문에 이것을 의미합니다. 코드가 빠르게 실패하면 나머지 참조를 제거 할 위치를 알 수 있습니다. 이는 완전히 분리 된 주제 (예 : pub / sub 패턴의 문자열 키)와 대조적이며 특히 동적 키를 사용하고 유지 보수 프로그래머가이를 인식하지 못한 경우 코드에 머무를 가능성이 더 높습니다 유지 보수 프로그래밍의 코드는 성가신 문제입니다).

게임 프로그래밍에서, 이것은 오래된 업데이트 루프 패턴 의 필요성을 줄이고 이벤트 / 반응적인 프로그래밍 관용구에 더 많은 것을 줄입니다. 실행하다. 업데이트 루프 (경과 된 게임 시간과 동기화해야하는 경우)에는 용도가 있지만 때로는 구성 요소 자체가이 패턴으로 자동 업데이트 될 수있을 때 혼란스럽게하고 싶지 않습니다.

관찰 가능한 함수의 실제 구현은 실제로 놀랍게도 작성하고 이해하기 쉽습니다 (특히 자바 스크립트 및 관찰자 패턴으로 배열을 처리하는 방법을 알고있는 경우 ).

var observable = function(v) {
    var val = v, subscribers = [];

    // the observable object,
    // as revealing module
    var output = {

        // subscribes to event
        onChange : function(func) {
            // idiomatic JS to add object to the
            // subscribers array
            subscribers.push(func);

            return output: // enables chaining
        },

        // the method that changes the observable object
        // and emits the event
        set : function(v) {
            var i;
            val = v;
            for (i = 0, i < subscribers.length; i++) {
                // this is hardly fault tolerant but as long
                // as subscribers are functions it'll work
                subscribers[i](v);
            }

            return output;
        }

    };

    return output;
};

나는했습니다 JsFiddle의 감시 오브젝트의 구현 요소를 관찰하고 가입자를 제거 할 수있는과이에 계속됩니다. JsFiddle을 자유롭게 실험 해보십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.