출처 : http://blog.aliencube.org/

이 포스트는 Stack Overflow의 What does “use strict” do in JavaScript, and what is the reasoning behind it?의 질문과 답변을 번역한 내용입니다.

자바스크립트에서 use strict는 뭘 하는 것이고, 왜 그걸 써야 하나요?

질문:

최근에 내가 짰던 자바스크립트 코드를 크록포드의 JSLint를 통해 실행시켰더니 아래와 같은 에러가 나타났습니다:

Problem at line 1 character 1: Missing “use strict” statement.

검색을 좀 해봤는데, 몇몇 사람들이 "use strict;" 라인을 그들의 자바스크립트 코드에 추가했다는 것을 알아챘습니다. 저도 이것을 따라서 추가해 봤더니, 위의 에러가 더이상 나타나지 않네요. 구글에서 검색을 해 봤는데, 이것을 추가하는 이유에 대해서 딱히 찾을 수가 없더라구요. 분명히 이것을 통해 브라우저가 자바스크립트를 해석하는 데 영향을 주는 것 같은데, 이걸 사용하면 나타날 수 있는 효과에 대한 것에 대한 것을 전혀 모르겠습니다.

"use strict";가 도대체 무엇이고, 이것이 의미하는 것은 무엇이며, 필요하긴 한 건가요?

현재 쓰이고 있는 브라우저들이 이 "use strict"; 문자열에 대응하는지요, 아니면 향후에 쓰일 것에 대한 대비인가요?


답변: (가장 추천수가 높은 것만을 번역했습니다: 역자 주)

이 문서가 도움이 될 겁니다: John Resig – ECMAScript 5 Strict Mode, JSON, and More

인상적인 부분을 살짝 인용하자면:

Strict Mode is a new feature in ECMAScript 5 that allows you to place a program, or a function, in a “strict” operating context. This strict context prevents certain actions from being taken and throws more exceptions.

Strict Mode는 ECMAScript 5 버전에 있는 새로운 기능으로써, 당신의 프로그램 또는 함수를 엄격한 운용 콘텍스트 안에서 실행시킬 수 있게끔 합니다. 이 엄격한 콘텍스트는 몇가지 액션들을 실행할 수 없도록 하며, 좀 더 많은 예외를 발생시킵니다.

이와 더불어:

Strict mode helps out in a couple ways:

  • It catches some common coding bloopers, throwing exceptions.
  • It prevents, or throws errors, when relatively “unsafe” actions are taken (such as gaining access to the global object).
  • It disables features that are confusing or poorly thought out.

Strict Mode는 몇가지 면에서 도움이 되는데:

  • 흔히 발생하는 코딩 실수를 잡아내서 예외를 발생시킵니다.
  • 상대적으로 안전하지 않은 액션이 발생하는 것을 방지하거나 그럴 때 예외를 발생시킵니다. 예를 들자면 전역객체들에 접근하려 한다거나 하는 것들이겠지요.
  • 혼란스럽거나 제대로 고려되지 않은 기능들을 비활성화시킵니다.

이 strict mode는 파일 전체에 적용시킬 수도 있고, 아니면 특정한 함수 안에서만 적용시킬 수도 있습니다.

위와 같은 방식으로 한다면, 예전의 레거시 코드와 새 코드가 한 파일 안에 섞여 있을 때 도움이 될 것입니다.

아마도 이 "use strict";는 왠지 Perl 에서 온 것 같기도 하네요. 이것을 사용함으로써 오류가 발생할 수 있는 좀 더 많은 부분을 검사할테니, 훨씬 더 적은 에러를 만들 수 있을 겁니다.


역자 추가:

위의 내용과 더불어 Can I use ECMAScript 5 Strict Mode? 페이지를 보면 지원하는 브라우저의 버전을 제공하고 있는데, IE는 이strict mode를 버전 10부터 지원한다. 그렇다고 해서 낮은 버전의 IE를 위해서 쓰지 말아야 하는가 하면 그렇지도 않다. 위에 언급한John Resig의 포스트를 다시 인용하자면:

This means that you can turn strict mode on in your scripts – today – and it’ll have, at worst, no side effect in old browsers.

strict mode를 지금 당장 활성화 시켜야 한다는 것을 의미하고, 이전 브라우저에서는 최악의 경우에라도 아무런 부작용이 없습니다.

따라서, 기존의 자바스크립트 코드에 대해 좀 더 엄격한 검사를 실행시키고 싶다면 문서의 첫 줄에 "use strict";를 추가하고, 기존의 것은 그대로 놔두고, 새로운 코드에 대해서만 추가하고 싶다면 각각의 함수 블록 처음에 추가하는 것이 좋겠다.

출처 : http://blog.coderifleman.com

오픈소스나 레거시 읽다 보면 종종 +function(){}() 같은 코드를 마주하게됩니다. 이 코드가 혼란스러운 분들을 위해 +function(){}()이 무엇인지 그리고 어떻게 동작하는 것인지 간략히 정리해보겠습니다.

엔진이 함수를 실행하는 방법

함수를 실행하기 위해서는 이름(식별자)이 필요합니다. 이름이 있어야 스코프에서 값을 참조할 수 있기 때문입니다.

예를 들어 function foo(){}를 정의하면 foo(); 구문을 이용해 함수를 실행할 수 있습니다.

함수를 실행하는 흐름<그림 1 함수를 실행하는 흐름>

엔진이 함수 선언문을 만나면 식별자를 관리하는 특별한 집합(EnviromentRecord)에 함수의 이름을 식별자로 넣고 함수 객체를 생성하여 참조합니다. 그리고 함수 실행 구문 중 foo를 만나면 값을 스코프를 통해 가져옵니다. 그 다음 구문이 () 이므로 실행 가능하다면 실행합니다.

만약 스코프에서 식별자를 찾지 못했다면 참조 에러(ReferenceError)를 출력하고, 식별자는 찾았지만 실행할 수 없는 타입이라면 타입 에러(TypeError)를 출력합니다.

not(); // ReferenceError: not is not defined

var foo = 'some';
foo(); // TypeError: foo is not a function

익명함수를 선언하는 방법

function(){} 구문은 이름 없는 “익명함수” 이므로 엔진이 스코프를 통해 값을 가져올 수 있는 방법이 없습니다. 따라서 이 문법을 실행하면 함수의 이름이 필요하다고 문법 오류를 출력합니다.(이 오류 메시지는 브라우저 마다 다릅니다.)

function(){} // SyntaxError: function statement requires a name

이름 없는 함수를 선언할 수 있는 유일한 경우는 함수를 값으로 사용(전달, 대입, 반환, 연산)할 때 입니다.

var func = function(){console.log('ok');}() // ok
some(function(){console.log('ok');})() // ok
return function(){console.log('ok');}() // ok
(function(){console.log('ok');})(); // ok
+function(){console.log('ok');}() // ok
!function(){console.log('ok');}() // ok

자바스크립트 엔진은 단항연산자(-, +, ~, !)를 만나게 되면 function(){}을 값으로 평가합니다. 쉽게 말해 연산을 위해 함수 객체를 생성하게 되고 최종적으로 () 구문을 이용해 실행할 수 있는 것입니다.

+function(){}은 함수 객체를 + 하려고 했으므로 결과로 NaN이 출력됩니다.

+function(){} // NaN

결론

결국 +function(){}()은 익명 함수를 즉시 실행시키기 위해 엔진의 원리를 이용해 만든 편법입니다.

이 원리를 이용한 즉시 실행 함수 중 가장 대중적인 방식은 (function(){})()입니다. ()는 구문 평가를 하는데 평가된 결과가 함수이니 함수 객체를 만들고 이어서 () 구문으로 즉시 실행하는 방식입니다.

(function(){}) // function() 객체
(function(){})() // 즉시 실행

남이 읽을때 혼란스럽지 않아야 좋은 코드라고 할 수 있겠죠. 따라서 비대중적인 +function(){}() 보다 (function(){})() 사용하여 코드를 읽는 개발자가 즉시 실행하는 함수 임을 쉽게 알 수 있도록 하는편이 좋겠습니다.

자바스크립트는 구문이 유연하기 때문에 자신만의 규칙이나 법칙을 만들기 쉽습니다. 하지만 이는 협업시 독이 될 수 있음을 명심해야합니다.

HTML5 API 인 FormData 객체를 사용하여 데이터를 할당하는 도중,

삽질된통 했다.


나중에 How to FormData Object Inspect 라고 구글링 하면 여러 결과를 확인할 수 있지만 백문이불여일타다.

직접 쳐보는게 제일 좋다.

간단히 내가 겪은 상황은 아주 단순 심플하다.


var formData = new FormData();
formData.append('id', 'JKUN.NET');
console.log(formData);


위와 같은 상황이라면 요소검사의 떡하니 폼데이터 객체에 id 속성이 할당된줄만 알았다.

그래서 찍어보니... 없다... 아 돌아가시는 줄 알았다.


여기서 제가 찾은 방법은 XHR - AJAX 를 이용하여 네트워크에서 확인하는 방법말고는 특별히 없었습니다.

더 심플하고 좋으신 방법 있으신분들 조언 부탁드립니다.^^;;


일단은 내가 확인한 방법은 다음과 같다.


var formData = new FormData();
formData.append('id', 'JKUN.NET');

var xhr = new XMLHttpRequest();
xhr.open('post', 'sample', true);
xhr.send(formData);

실행결과


요 따위 삽질을 혹시나 겪으신 분이 있을수도 있어서 별거아닌 포스팅 합니다.


  1. 힘없는염소 2015.11.13 17:45 신고

    크롬 콘솔로 안보이데..삽질...ㄷㄷㄷㄷㄷ

  2. 아놔 2018.03.05 19:56 신고

    앜ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ 저 구글링 해서 찾으려고했는데 이거보고 욕을했습니다 왜 분명 넣었는데 콘솔로 안나오길레 뭐가 문제인지 몰라 무려 4시간을 뻘짓을하고말았습니다.. ㅠㅠ

본문링크 : http://youngman.kr/?p=457


개요

아직도 많은 개발자들은 자바스크립트를 단순히 클라이언트 상의 액션을 실행하기 위한 함수 기반의 스크립트 언어라고 생각하고 있다. 하지만 자바스크립트는 객체 지향 언어이다. 비록 자바나 C#처럼 완벽하지는 않지만 기본적인 클래스 개념과 상속, 은닉 등을 제공한다. 이번 장에서는 자바스크립트의 OOP 요소들을 하나하나 예제로 풀어가며 알아보도록 할 것이다.

클래스 정의

function MyClass() {
}

var MyClass = function() {
}
// -- 위의 두 구문은 동일하게 MyClass 클래스를 선언한다.
// -- 필자는 가독성 측면에서 두 번째 방식을 선호한다

(1) 접근 제어자

자바스크립트는 클래스 내부에서 정의할 수 있는 두 가지의 접근 제어자를 제공한다.

var Student = function(id, name) {
     var id = id;
     this.name = name;
}

var my = new Student("Seogi1004", "Moon-Hak-I");
alert(my.id + ", " + my.name);

위의 소스 코드의 출력 메시지는 ’undefined, Moon-Hak-I’이다. 클래스 내부에 선언된 변수의 지정자가 ‘var’일 경우에는 해당 클래스 내부에서만 접근이 가능하며 자바의 ‘private’와 같다라고 생각하면 된다. 그리고 클래스 외부에서도 사용하기 위해서는 ’ this 키워드’를 사용하면 된다.

위에서 보여진 변수 접근 제어자는 메소드에도 동일하게 적용된다. 

var People = function(name, age) {
     var name = name;
     var age = age;

     var isAdult = function() {
          if(age > 19) return true;
          else return false;
     }

     this.viewMyInfo = function() {
          if(isAdult()) {
               return name + "님은 성인이 맞습니다.";
          } else {
               return name + "님은 성인이 아닙니다.";
          }
     }
}

var people = new People("Moon-Hak-I", 26);
alert(people.isAdult());          // Uncaught TypeError: Object [object Object] has no method 'isAdult'
alert(people.viewMyInfo());

위의 소스 코드에서 22라인 ’people.isAdult()’ 부분을 주의깊게 볼 필요성이 있다. var 키워드를 사용하여 정의된 메소드는 외부에서 호출되지 못한다. 즉, People 클래스에서 외부에서 직접적으로 사용할 수 있는 메소드는 ’viewMyInfo’뿐이다.

OOP에서 이런 개념을 캡슐화라고 하는데 클래스 내부의 연산 과정을 숨김으로써 보다 독릭접인 코드 구성을 꾀할 수 있고, 예기치 못한 접근을 차단하여 무분별한 함수 사용을 미연에 방지할 수 있다. 

아래 소스 코드는 일반적으로 사용되는 함수 정의 방법이며 기능은 위의 예제와 동일하다. 

unction isAdult(age) {
     if(age > 19) return true;
     else return false;
}

function viewMyInfo(name, age) {
     if(isAdult(age)) {
          return name + "님은 성인이 맞습니다.";
     } else {
          return name + "님은 성인이 아닙니다.";
     }
}

alert(isAdult(26));
alert(viewMyInfo("Moon-Hak-I", 26)); 


첫번째 예제와 달리 ’isAdult 함수’가 정상적으로 호출 된다. 실제로 대다수의 웹 개발자들이 위와 같은 형태로 함수 정의를 하는데 이러한 방식은 많은 문제점을 발생시킨다. 요약하자면 아래와 같다.


1. 해당 페이지에 포함되는 자바스크립트가 많을 경우 동일한 함수가 재정의 될 가능성이 있다. 스크립트 언어 특성상 마지막에 정의된 함수를 사용하게 된다. (기능이 전혀 다른 함수일 경우, 매우 심각한 문제)

2. 하나의 기능을 수행하고자 다수의 비즈니스 로직 처리 함수를 사용한다면 가독성에 문제가 생길 수 밖에 없다. 위의 예제와 같은 함수 정의 방식은 지극히 수평적이고 함수와 함수 간의 관계를 증명할 방법이 없다. (기껏해야 주석 또는 네이밍 규칙)

 

(2) 정적 클래스 

자바스크립트에서 정적 클래스는 별도로 인스턴스를 생성하지 않으며 선언과 동시에 정의가 된다. 정적 클래스는 일반적으로 유틸리티 형태의 기능 구현을 할 때 주로 사용된다.

아래 소스 코드는 일반 클래스와 정적 클래스의 메소드를 사용하는 예제이다.

var MyClass = function() {
     this.show = function() {
          return "MyClass";
     }
}
var MyStaticClass = new function() {
     this.show = function() {
          return "MyStaticClass";
     }
}

var cls = new MyClass();
alert(cls.show());

// -- 별도의 인스턴스 생성을 하지 않는다.
alert(MyStaticClass.show());


심화

자바스크립트에서 변수(or 프로퍼티)와 함수(or 메소드)를 접근하는 방법은 크게 외부에서 가능한지 아닌지로 나눌 수 있다. 일반적으로 ‘public’이라고 불리우는 메소드는 클래스 안의 ‘private’으로 정의된 요소들을 접근할 수 있지만 자바스크립트에서는 불가능하다. 외부에서도 접근이 가능하고 클래스 안에 ‘private’으로 정의된 요소들을 접근할 수 있는 메소드를 자바스크립트에서는 ‘public’이 아닌 ‘privileged’라고 한다. 

그럼, 지금부터 아래 예제를 통해 각각의 유형에 대해서 자세히 알아보도록 하자.

function Person(firstName, lastName) {
     // 객체 생성시 증가
     this.constructor.population++;

     // **********************************************************************
     // PRIVATE VARIABLES AND FUNCTIONS
     // 'PRIVELEGED METHODS'만 읽기/쓰기/수정 가능
     // **********************************************************************
     var alive = true;
     function getFullName() {
          return lastName + ", " + firstName;
     }

     // **********************************************************************
     // PRIVILEGED METHODS
     // 공개적으로 호출할 수 있으며, 'PRIVATE' 항목에 유일하게 접근 가능
     // 하지만 수정할 수 없고, 'PUBLIC'과 대체 가능
     // **********************************************************************
     this.toString = function(){
          return getFullName();
     };

     this.isAlive = function()  {
          return alive;
     };

     // **********************************************************************
     // PUBLIC PROPERTIES -- 누구나 읽기/쓰기 가능
     // **********************************************************************
     this.age = 1;
};

// *************************************************************************
// PUBLIC METHODS -- 누구나 읽기/쓰기 가능
// *************************************************************************
Person.prototype.addAge = function() {
     this.age++;
};

// *************************************************************************
// PROTOTYOPE PROERTIES -- 누구나 읽기/쓰기 가능 (but may be overridden)
// *************************************************************************
// Person.prototype.age = 0;

// *************************************************************************
// STATIC PROPERTIES -- 누구나 읽기/쓰기 가능
// *************************************************************************
Person.population = 0;

// *************************************************************************
// STATIC METHODS -- 누구나 읽기/쓰기 가능
// *************************************************************************
Person.showTotalPopulation =  function (msg) { 
     alert(msg +  " : "  + Person.population);
} 


var personList = [ new Person('Jae-Seok', 'Hong'), new Person('Ji-Sung', 'Jung') ];

$("#result")
    .append("'" + personList[0] + "'과 '" + personList[1] + "'이 태어났습니다.
") .append("현재 인구는 " + Person.population + "명 입니다.

"); for(var i = 0; i < 25; i++) { personList[0].addAge(); personList[1].addAge(); } $("#result") .append("'" + personList[0] + "'은 " + personList[0].age + "살이 되었습니다.
"); Person.showTotalPopulation("총 인구");


(1) 변수 (or 프로퍼티)

private 변수는 앞서 설명한 것처럼 클래스 안에서 ‘var’ 키워드를 사용하여 선언되며, 오직 ‘private/privileged 함수’에서만 접근할 수 있다.

public 프로퍼티는 클래스 안에서 ‘this.propertyName’ 형태로 선언되며 외부에서도 읽기/쓰기가 가능하다.

prototype 프로퍼티는 클래스 외부에서 정의되며 ‘Classname.prototype.propertyName = someValue’ 형태로 사용하지만 동일한 이름의 public 프로퍼티가 존재하지 않을 경우에만 정의할 수 있다. (예제의 46라인의 주석을 해제하여 실행을 하여도 결과 값은 동일함)

static 프로퍼티는 ‘Classname.propertyName’ 형태로 정의되며 인스턴스의 생성과는 별개의 영역에 존재한다. (예제의 3라인처럼 클래스 내부적으로 static 프로퍼티는 ‘this.constructor.prototyeName’ 형태로 접근할 수 있음)
 

(2) 함수 (or 메소드)

private 함수는 클래스 내부적으로 ‘function functionName() {…} or var functionName = function() {…}’와 같은 형태로 선언되며 생성자와 privileged 메소드를 통해서만 호출될 수 있다.

privileged 메소드는 ‘this.methodName = function() {…}’와 같은 형태로 선언되며 클래스 외부에서도 실행할 수 있다. 하지만 외부에서는 ‘prototype’을 이용한 재정의를 할 수가 없다.

public 메소드는 클래스 외부에서 ‘Classname.prototype.methodName = function() {…}’와 같이 자유롭게 정의할 수 있지만 클래스 내부에 정의된 ‘private’ 요소들은 접근할 수 없다. 또한 prototype 프로퍼티와 마찬가지로 클래스 내부에 동일한 이름의 privileged 메소드가 존재하지 않을 경우에만 정의할 수 있다. 

static 메소드는 ‘Classname.methodName’ or ‘Functionname.methodName’ 형태로 정의되며 인스턴스 생성과는 별개의 영역에 존재한다. 자주 사용되는 static 메소드는 대표적으로 call/apply 메소드가 있다. (static 프로퍼티와 마찬가지로 클래스 내부적으로 ‘this.constructor.methodName’ 형태로 접근할 수 있음)
 

(3) 참고 사항

변수와 프로퍼티(or 함수/메소드)는 비슷한 의미를 가지고 있지만 결정적인 차이가 있다. 먼저 변수와 함수는 클래스 내부에서만 존재하며 선언적 의미를 가지고 있다. 프로퍼티와 메소드는 정의되는 것이라 할 수 있는데, 여기서 말하는 정의란 클래스가 구체화되어 인스턴스가 생성되는 것을 말한다. 이때 프로퍼티와 메소드는 생성된 인스턴스를 통해 접근할 수 있다.

오브젝트형태의 데이터를 문자열로 전환하여 확인할때

function objToString (obj) {
    var str = '';
    for (var p in obj) {
        if (obj.hasOwnProperty(p)) {
            str += p + '::' + obj[p] + '\n';
        }
    }
    return str;
}

새로 생길때마다 코드를 추가하고, 날짜를 업데이트 할 예정입니다.^^



필자는 최전방 개발자로서 자바스크립트를 사용하는 사람들을 많이 만난다. 이들 대부분은 주로 jQuery와 몇 가지 플러그인을 사용해 멋진 라이트박스 효과나 이미지 슬라이더를 추가하는 정도의 작업을 하지만, 그중 일부는 키보드 위로 손을 올려 놓기만 해도 코드가 저절로 써진다는 ‘제다이’급 개발자들이 있다.

이 두 가지 기술 수준의 중간 어딘가에 있는 사람은 때로 어떻게 해야 할지 모르는 상황에 부닥친다. 전문적인 지식을 찾는 길은 많다. 지금 구덩이에 빠져 도움이 필요하다면 모든 자바스크립트 전문가가 알아야 하는 다음과 같은 몇 가지 개념을 살펴보라.

자바스크립트 비밀 1: 클로저(Closures)
자바스크립트의 클로저는 함수에 부모 함수의 범위에 대한 접근성을 제공한다. 개발자에게는 극히 혼란스러운 개념이다. 필자는 자바스크립트를 배울 당시 의도하지 않은 클로저로 인해 코드를 디버깅하는 데 몇 시간을 소비한 적이 있다. 이런 실수를 통해 배운 이후에는 클로저가 상당히 멋지다고 생각했고 다시 몇 시간 동안 클로저를 사용하여 문제를 해결하려 헛되이 노력하기도 했다.

결국, 배운 것은 클로저는 부모 범위에 대한 접근성을 가진 안쪽 함수(아래 고차 함수 참조)를 반환할 때 유용하다는 점이다. 이로써 변수를 보관하기 위한 일종의 비공개, 또는 보호된 환경이 만들어진다. 아래 예에서 count는 threeTimer가 호출될 때 접근 및 증분되며, 점이나 괄호 기호를 통해 직접 접근할 수는 없다.

// **Closures** function makeThreeTimer(){     var count = 0;     return function(){         if(count < 3){             console.log('doing work');             count++;         }         else {             throw new Error('No more work');         }     } } var threeTimer = makeThreeTimer();     threeTimer(); // logs 'doing work' (count gets incremented)     threeTimer(); // logs 'doing work' (count gets incremented)     threeTimer(); // logs 'doing work' (count gets incremented)     threeTimer(); // throws an error     threeTimer.count; // returns undefined

자바스크립트 비밀 2: 고차 함수
기능적 프로그래밍 언어에서 함수는 1급 구성원이다. 다른 모든 값과 마찬가지로 전달할 수 있으며 이로써 흥미로운 가능성이 열린다. 고차 함수는 다른 함수를 소비 또는 생산하는 함수를 말한다. call 또는 bind와 같은 function 프로토타입의 메소드는 모두 고차 함수다. 커링(currying), 메모이제이션(memoization)과 같은 기법을 고차 함수로 표현할 수 있다. 자바스크립트에서 고차 함수를 사용하면 관점 지향 프로그래밍(Aspect-oriented programming)도 가능하다.

자바스크립트 비밀 3: 함수 호출
함수를 호출하는 가장 일반적인 방법(괄호 연산자를 사용하는 방법)을 이해한 다음에는 call과 apply를 사용하는 방법을 배울 차례다. 괄호 연산자 대비 call/apply를 사용할 때의 장점은 함수가 실행되는 컨텍스트를 지정할 수 있다는 점이다(this의 값). 이러한 형태는 고차 함수, 특히 이러한 고차 함수가 나중에 실행되는 함수를 소비할 때 볼 수 있다. Function 프로토타입에서 bing 메소드의 내부는 call/apply의 훌륭한 예다.


// Possible implementation of bind using apply function bind(func, context){     return function(){     func.apply(context, Array.prototype.slice.apply(arguments));     } }

자바스크립트 비밀 4: this는 무엇인가?
this 키워드는 많은 자바스크립트 개발자에게 큰 장애물로, 어떤 사람들은 아예 이 키워드를 외면한다. 필자가 지금까지 접한 이 키워드에 대한 최고의 설명은 예후다 캐츠가 함수 호출에 대한 블로그에 쓴 글이다. call/apply 또는 bind를 사용하지 않을 경우 this 값은 다음과 같은 경우를 제외하고 항상 전역 객체를 참조한다.

1. 문제의 함수가 new 연산자를 사용하여 호출된 경우, 현재 만들어지고 있는 새로운 객체를 가리킨다.
2. 문제의 함수가 객체의 멤버인 경우, 이 객체를 가리킨다.

단, 호출되는 함수가 클릭 핸들러 또는 setTimeout 등에서 비동기적으로 호출될 때는 2번 규칙을 무시해야 한다. 다음을 참고하라.


Person.getName(); // 'this' points to Person
setTimeout(Person.getName, 1000); // 'this' points to the global object
JavaScript secret No. 5: Protecting the global scope

자바스크립트 비밀 5: 전역 범위 보호
자바스크립트의 결함 중 하나는 페이지의 모든 스크립트가 공유되는 전역 컨텍스트에서 실행된다는 점이다. 이 결함이 악용될 경우 웹 사이트는 교차 사이트 스크립팅 공격에 취약하게 된다. 공유 전역 컨텍스트는 다른 문제도 일으킨다. 예를 들어 많은 스크립트가 한 페이지에서 실행되는데, 모든 스크립트를 개발자가 결정하는 것은 아니다(광고 스크립트 등이 대표적이다). 이 스크립트들은 전역 공간에서 실행되며 모두 같은 전역 변수에 접근할 수 있다. 이러한 스크립트 두 개가 같은 전역 변수를 사용하게 되면 서로 간섭하기 시작하고, 그러면 코드는 망가지게 된다.

전역 범위의 사용을 최소화하는 것은 간섭을 막고 긴 디버깅 시간을 줄이는 데 도움이 되는 방어적 기법이다. 변수를 전역적으로 저장하는 것을 완전히 없앨 수는 없지만 네임스페이싱과 같은 기법을 사용하면 최소화할 수 있다.


// **Namespacing** // The global footprint is a single object containing // all other references needed. var MyApp = {}; MyApp.id = 42; MyApp.utils = {     validate: function(){     //do work     } };

또는 모듈 패턴도 있다.


// **Module pattern** // This relies on immediately invoked anonymous functions and the // closure they create to maintain access to variables within the // function. var MyApp = (function(){     //declare a local variable     var appId = 42;     function getAppId(){         //referring to a variable in this function's parent scope         return appId;     }         return {         getAppId: getAppId     }; }()); appId; // undefined MyApp.appId; //undefined MyApp.getAppId(); // returns 42. (Brought to you by closures) JavaScript secret No. 6: Inheritance

자바스크립트 비밀 6: 상속
자바스크립트에서 상속은 여러 가지 이유로 긴 혼란의 역사를 갖고 있다. 대부분 개발자(필자가 만난 많은 자바스크립트 개발자들 포함)들은 클래스 모델을 충실하게 이해하지만, 프로토타입 모델에 대해서는 매우 혼란스러워한다. 프로토타입 상속을 사용하는 언어 목록을 살펴보고 나면 아마 이러한 현상을 이해할 수 있을 것이다.

자바스크립트를 제외한 다른 주류 언어에는 프로토타입 상속이 없다. 게다가 자바스크립트에서는 클래스 모델을 에뮬레이션하는 것이 가능하다. 그 결과 상속에 대한 접근 방식이 매우 다양하며, 이들 중 상당수가 독선적, 모순적이다. 의사 클래스 방식(pseudo-classical approach)은 자바스크립트의 함정 중 하나이므로 필자는 절대 사용하지 말 것을 제안한다. 대부분 개발자에게 친숙하게 보이겠지만 사실 근사치일 뿐이므로 금방 깨진다. 


출처 : http://www.itworld.co.kr/news/84870

미래는 자바스크립트다. 오늘 간단히 둘러보며 확신을 갖는다.

앞으로 자바스크립트와 HTML5 . 웹에 몰빵이다!! ㅋㅋㅋㅋ

안그래도 요새 타이타늄 스튜디오에 계속 관심이 가드만..
자바스크립트로 웹 / 서버사이드 / 데스크톱 애플리케이션까지 개발이 가능해지고 있다.
엄청난 영역파괴이지만.. 하나의 어플리케이션이 단일언어로만 개발되어 있다면.. 엄청나게 큰 매력으로 작용
하지 않을까란 생각이다.
공부할게 더 늘어서 짜증나지만 좋기도 한다. 고로 나는 또 공부한다.


(function ($) {
 
    $.ua = $.ua || {
        platform: {},
        browser: {},
        engine: {}
    };
 
    var ua = navigator.userAgent.toLowerCase(),
        p = $.ua.platform,
        b = $.ua.browser,
        e = $.ua.engine,
        u = 'unknown';

    //alert(navigator.userAgent);
 
    // detect platform
    p.name = (/(win|mac|linux|iphone|ipod|android)/.exec(ua) || [, u])[1];
    p[p.name] = true;
 
    // detect browser
    b.name = (/(msie|firefox|chrome|safari|opera)/.exec(ua) || [, u])[1]; // chrome must be tested before safari
    b[b.name] = true;
    b.version = (b.unknown)? 0: /(?:msie |firefox\/|chrome\/|version\/)(\d+(\.\d+)*)/.exec(ua)[1];
 
    // detect engine
    e.name = (/(trident|webkit|gecko|presto)/.exec(ua) || [, u])[1]; // webkit must be tested before gecko
    e[e.name] = true;
    e.version = (e.unknown)? 0: /(?:trident\/|rv:|webkit\/|presto\/)(\d+(\.\d+)*)/.exec(ua)[1];
 
    // add classes to html element
    $('html').addClass([
        p.name,
        b.name,
        b.name + parseInt(b.version, 10),
        e.name,
        e.name + parseInt(e.version, 10)
    ].join(' '));
 
})(jQuery);

function CastUserAgent(AgentCase) {
	var c = [], i, j;
	var d = 0;
	for (i in $.ua) {
		if (i === 'data' || i === 'init') {
			continue;
		}
		for (j in $.ua[i]) {
			d = 0;
			if (i === AgentCase) {
				if (d != 0) {
					c[c.length] = ',';
				}
				c[c.length] = '\'' + j + '\'' + ':\'' + $.ua[i][j] + '\'';
				d++;
			}
		}
	}
	c.join();
	return eval('({' + c.toString() + '})');
}

아래 CastUserAgent 함수를 추가하였다. 파라메터를 문자열 형태로 'platform, browser, engine'

로 넘겨주면 name, version 을 반환한다.

아래와 같이 호출하여 사용하면 된다.

var bw = CastUserAgent ('browser').name;
alert(bw);



<iframe id="TargetFrame"></iframe>


1. 속성변경

$('#TargetFrame').attr('src', 'http://www.jkun.net');

$('#TargetFrame').attr({

  'src' : 'http://www.jkun.net',

  'width' : '100',

  'height' : '100',

  'scrolling' : 'no'

});


2. 프레임내 문서객체 요소 접근

$('#TargetFrame').contents().find('div.target-panel');


3. 부모 요소에 접근

- $('#TargetFrame', parent.document);

- parent.$('#TargetFrame');

'Development > JavaScript | jQuery' 카테고리의 다른 글

PlugIn - jquery-user-agent (유저에이전트)  (0) 2013.11.15
window.resize 크로스 브라우징  (0) 2013.11.15
jQuery 아이프레임, iframe  (0) 2013.08.20
jQueryPlugIn - jQueryScroll  (0) 2013.01.22
jQuery Cookie  (0) 2012.07.29
유용한 jQuery 플러그인  (0) 2010.07.29

JavaScript ( 출처 링크 연결 )
개체 지향 기술을 이용한 고급 웹 응용 프로그램 만들기
Ray Djajadinata

이 기사에서 다루는 내용:
  • 프로토타입 기반 언어로서의 JavaScript
  • JavaScript를 사용한 개체 지향 프로그래밍
  • JavaScript에서의 코딩 트릭
  • JavaScript의 미래
이 기사에서 사용하는 기술: 
JavaScript
최근에 필자는 웹 응용 프로그래밍 개발 부문에 5년 경력을 가진 소프트웨어 개발자와 인터뷰를 했습니다. 그녀는 4년 6개월 동안 JavaScript를 사용했으며 스스로의 JavaScript 숙련도를 매우 높게 평가하고 있었습니다. 나중에 알게 되었지만 이 개발자는 JavaScript에 대해서 그리 많은 것을 알고 있지는 못했습니다. 이 개발자를 탓하고자 하는 것은 아닙니다. JavaScript에는 이렇듯 상당히 재미있는 면이 있습니다. 많은 개발자들이 C/C++/C#에 대해 알고 있거나 프로그래밍 경험이 있다는 이유만으로 자신이 JavaScript에 대해 많은 것을 알고 있다고 착각하곤 합니다. 필자 역시 최근까지 그러했습니다.
이러한 가정이 전혀 근거가 없는 것은 아닙니다. JavaScript를 사용하여 간단한 작업을 수행하기는 상당히 쉬우며 시작하기도 어렵지 않습니다. 이 언어는 또한 까다롭지 않으며 코딩을 시작하기 전에 많은 것을 배우도록 요구하지도 않습니다. 프로그래머가 아니더라도 몇 시간만 작업하면 홈페이지를 위한 유용한 스크립트를 작성할 수 있을 정도입니다.
사실 최근까지도 필자는 JavaScript에 대한 짧은 지식과 MSDN® DHTML 참조, 그리고 C++/C# 경험을 활용하여 필요한 작업을 수행할 수 있었습니다. 필자의 JavaScript 실력이 부족하다는 것을 느끼게 된 것은 현실적인 AJAX 응용 프로그램을 작성하기 시작하면서부터였습니다. 이 신세대 웹 응용 프로그램의 복잡성과 상호 작용성은 JavaScript 코드를 작성하는 데 있어 완전히 다른 방식을 요구하고 있습니다. 이것은 본격적인 JavaScript 응용 프로그램이며 지금까지 스크립트를 작성하던 느슨한 방법으로는 이러한 응용 프로그램을 작성할 수 없습니다.
개체 지향 프로그래밍(OOP)은 여러 JavaScript 라이브러리에서 코드베이스를 더욱 유지 관리하기 쉽게 하기 위해 널리 사용되는 방법입니다. JavaScript는 OOP를 지원하지만 널리 사용되는 Microsoft® .NET Framework 지원 언어인 C++, C# 또는 Visual Basic®에서 지원하는 방법과는 상당히 다른 방법으로 제공합니다. 따라서 이러한 언어를 오랫동안 사용한 개발자라면 JavaScript에서 OOP를 사용하는 것이 낯설고 처음에는 사용하기 까다롭게 느껴질 수 있습니다. 이 기사에서는 JavaScript 언어에서 어떻게 개체 지향 프로그래밍을 지원하는지 자세히 살펴보고 이러한 지원을 사용하여 JavaScript에서 효과적으로 개체 지향 개발을 수행하는 방법을 알아보겠습니다. 우선 무엇보다 중요한 개체에 대해서 살펴보겠습니다.

JavaScript 개체는 사전입니다.
C++나 C#에서의 개체는 클래스나 구조체의 인스턴스를 의미합니다. 개체는 어떤 템플릿(클래스)에서 인스턴스화했는지에 따라 다른 속성 및 메서드를 가지지만 JavaScript 개체는 이와 다릅니다. JavaScript의 개체는 단순히 이름/값 쌍의 컬렉션입니다. JavaScript 개체는 문자열 키가 있는 사전으로 생각할 수 있습니다. 익숙한 "."(점) 연산자나 일반적으로 사전을 처리할 때 사용되는 "[]" 연산자를 사용하여 개체 속성을 얻거나 설정할 수 있습니다. 다음 코드 조각을 살펴보십시오.
var userObject = new Object();
userObject.lastLoginTime = new Date();
alert(userObject.lastLoginTime);    
위 코드는 다음 코드와 정확히 같은 작업을 수행합니다.
var userObject = {}; // equivalent to new Object()
userObject[“lastLoginTime”] = new Date();
alert(userObject[“lastLoginTime”]);
다음과 같이 userObject 정의 내에서 직접 lastLoginTime 속성을 정의할 수도 있습니다.
var userObject = { “lastLoginTime”: new Date() };
alert(userObject.lastLoginTime);
C# 3.0 개체 이니셜라이저와 비슷하다는 것을 알 수 있을 것입니다. 또한 Python에 익숙한 개발자라면 두 번째와 세 번째 코드 조각에서 userObject를 인스턴스화하는 방식이 Python에서 사전을 지정하는 방식과 동일하다는 것도 알 수 있습니다. 유일한 차이는 JavaScript 개체/사전은 문자열 키만 받지만 Python 사전에는 hashable과 같은 개체를 사용할 수 있다는 것입니다.
이러한 예는 JavaScript 개체가 C++ 또는 C# 개체에 비해 얼마나 유연한가를 보여 줍니다. lastLoginTime을 앞서 선언할 필요는 없으며 userObject에 해당하는 이름의 속성이 없는 경우에는 간단하게 userObject에 속성이 추가됩니다. JavaScript 개체가 사전이라는 사실을 기억한다면 이것은 그리 놀라운 일이 아닙니다. 사전에는 항상 새로운 키와 해당하는 값을 추가할 수 있습니다.
개체 속성은 앞서 설명한 것과 같습니다. 그렇다면 개체 메서드는 어떨까요? 이번에도 역시 JavaScript는 C++/C#과는 다릅니다. 개체 메서드를 이해하기 위해서는 먼저 JavaScript 함수를 살펴볼 필요가 있습니다.

JavaScript에서는 함수가 가장 중요합니다.
함수와 개체를 서로 다른 것으로 취급하는 프로그래밍 언어가 많습니다. JavaScript에서는 이 차이가 모호합니다. JavaScript 함수는 실행 가능한 코드와 연결된 개체입니다. 다음과 같은 일반적인 함수를 예로 들어 보겠습니다.
function func(x) {
    alert(x);
}
func(“blah”);
이 코드는 JavaScript에서 일반적으로 함수를 정의하는 방법을 보여 줍니다. 그러나 다음과 같이 익명의 함수 개체를 만들고 변수 func에 할당하는 방법으로도 동일한 함수를 정의할 수 있습니다.
var func = function(x) {
    alert(x);
};
func(“blah2”);
또는 다음과 같이 Function 생성자를 사용할 수도 있습니다.
var func = new Function(“x”, “alert(x);”);
func(“blah3”);
이를 통해서 함수는 함수 호출 작업을 지원하는 개체라는 것을 알 수 있습니다. Function 생성자를 사용하여 함수를 정의하는 마지막 방법은 자주 사용되지는 않지만 흥미로운 가능성을 열어 줍니다. 그 이유는 함수 본문이 Function 생성자에 대한 String 매개 변수이기 때문입니다. 이것은 런타임에 임의의 함수를 작성할 수 있음을 의미합니다.
함수가 개체라는 것을 확인시켜 주는 예로서 다른 JavaScript 개체를 대상으로 작업할 때와 마찬가지로 함수에 대해 속성을 설정하거나 추가할 수 있습니다.
function sayHi(x) {
    alert(“Hi, “ + x + “!”);
}
sayHi.text = “Hello World!”;
sayHi[“text2”] = “Hello World... again.”;

alert(sayHi[“text”]); // displays “Hello World!”
alert(sayHi.text2); // displays “Hello World... again.”
함수는 개체이므로 변수에 할당하고 다른 함수에 인수로 전달하며 다른 함수에서 값으로 반환하는 것은 물론, 개체의 속성이나 배열의 요소로 저장하는 등의 작업이 가능합니다. 그림 1에는 이에 대한 예가 나와 있습니다.
// assign an anonymous function to a variable
var greet = function(x) {
    alert(“Hello, “ + x);
};
greet(“MSDN readers”);

// passing a function as an argument to another
function square(x) {
    return x * x;
}
function operateOn(num, func) {
    return func(num);
}
// displays 256
alert(operateOn(16, square));

// functions as return values
function makeIncrementer() {
    return function(x) { return x + 1; };
}
var inc = makeIncrementer();
// displays 8
alert(inc(7));

// functions stored as array elements
var arr = [];
arr[0] = function(x) { return x * x; };
arr[1] = arr[0](2);
arr[2] = arr[0](arr[1]);
arr[3] = arr[0](arr[2]);
// displays 256
alert(arr[3]);

// functions as object properties
var obj = { “toString” : function() { return “This is an object.”; } };
// calls obj.toString()
alert(obj);
이를 기억한다면 이름을 선택하고 이 이름에 함수를 할당하는 작업으로 간단하게 개체에 메서드를 추가할 수 있습니다. 여기에서는 익명 함수를 해당 메서드 이름에 할당하여 개체에 3개의 메서드를 정의했습니다.
var myDog = {
    “name” : “Spot”,
    “bark” : function() { alert(“Woof!”); },
    “displayFullName” : function() {
        alert(this.name + “ The Alpha Dog”);
    },
    “chaseMrPostman” : function() { 
        // implementation beyond the scope of this article 
    }    
};
myDog.displayFullName(); 
myDog.bark(); // Woof!
C++/C# 개발자에게는 displayFullName 함수 내에 사용된 "this" 키워드가 친근하게 느껴질 것입니다. 이 키워드는 메서드를 호출한 개체를 참조합니다. Visual Basic 개발자에게도 역시 생소하지는 않을 것입니다. Visual Basic에서는 이를 "Me"라고 합니다. 따라서 위 예에서 displayFullName의 "this" 값은 myDog 개체입니다. 그러나 "this"의 값은 정적이지 않습니다. 그림 2에서 보여 주고 있는 것처럼 다른 개체를 통해 호출된 경우에는 "this" 값이 해당 개체를 가리키도록 변경됩니다.
function displayQuote() {
    // the value of “this” will change; depends on 
    // which object it is called through
    alert(this.memorableQuote);    
}

var williamShakespeare = {
    “memorableQuote”: “It is a wise father that knows his own child.”, 
    “sayIt” : displayQuote
};

var markTwain = {
    “memorableQuote”: “Golf is a good walk spoiled.”, 
    “sayIt” : displayQuote
};

var oscarWilde = {
    “memorableQuote”: “True friends stab you in the front.” 
    // we can call the function displayQuote
    // as a method of oscarWilde without assigning it 
    // as oscarWilde’s method. 
    //”sayIt” : displayQuote
};

williamShakespeare.sayIt(); // true, true
markTwain.sayIt(); // he didn’t know where to play golf

// watch this, each function has a method call()
// that allows the function to be called as a 
// method of the object passed to call() as an
// argument. 
// this line below is equivalent to assigning
// displayQuote to sayIt, and calling oscarWilde.sayIt().
displayQuote.call(oscarWilde); // ouch!
그림 2의 마지막 줄에서는 개체의 메서드로 함수를 호출하는 대안을 보여 줍니다. JavaScript에서 함수는 개체라는 사실을 기억하십시오. 모든 함수 개체에는 함수를 첫 번째 인수의 메서드로 호출하는 메서드 이름 호출이 있습니다. 즉, 호출에 전달하는 개체의 첫 번째 인수가 이 함수 호출에서 "this" 값이 됩니다. 뒤에 살펴보겠지만 이것은 기본 클래스 생성자를 호출하는 유용한 기술입니다.
한 가지 기억해야 할 것은 개체를 소유하지 않은 상태에서 "this"가 포함된 함수를 호출해서는 안 된다는 것입니다. 이러한 호출에서 "this"는 Global 개체를 참조하므로 전역 네임스페이스를 어지럽히게 되고 이것은 응용 프로그램에 심각한 재앙이 될 수 있습니다. 예를 들어 아래의 스크립트는 JavaScript의 전역 함수 isNaN의 동작을 변경하며 이러한 일은 절대 피해야 합니다.
alert(“NaN is NaN: “ + isNaN(NaN));

function x() {
    this.isNaN = function() { 
        return “not anymore!”;
    };
}
// alert!!! trampling the Global object!!!
x();

alert(“NaN is NaN: “ + isNaN(NaN));
지금까지 개체를 만들고 속성과 메서드로 완성하는 방법을 살펴보았습니다. 그러나 위의 코드 조각을 자세히 살펴보면 속성과 메서드가 개체 정의 자체 내에 코드로 포함되어 있다는 것을 알 수 있습니다. 개체 생성에 대한 더 본격적인 제어가 필요한 경우에는 어떻게 해야 할까요? 예를 들어 몇 가지 매개 변수의 값에 따라 개체 속성의 값을 계산해야 할 수 있습니다. 또는 런타임에만 얻을 수 있는 값으로 개체 속성을 초기화해야 할 수 있습니다. 이외에도 개체의 인스턴스를 두 개 이상 만들어야 할 수 있는데 이것은 매우 일반적인 요구 사항입니다.
C#에서는 개체 인스턴스를 인스턴스화하는 데 클래스를 사용하지만 JavaScript에는 클래스가 없으므로 상황이 다릅니다. 다음 섹션에서 살펴보겠지만 JavaScript에서는 "new" 연산자와 함께 사용하는 경우 함수가 생성자처럼 동작한다는 사실을 활용하게 됩니다.

생성자 함수는 있지만 클래스는 없습니다.
JavaScript OOP의 특이한 점은 앞서 언급했듯이 JavaScript에는 C# 또는 C++와 같은 클래스가 없다는 것입니다. C#에서의 작업 방법은 다음과 같습니다.
Dog spot = new Dog();
위 코드를 수행하면 클래스 Dog의 인스턴스인 개체를 얻을 수 있습니다. 그러나 JavaScript에서는 클래스가 없습니다. 클래스와 가장 비슷한 효과를 얻는 방법은 다음과 같이 생성자 함수를 정의하는 것입니다.
function DogConstructor(name) {
    this.name = name;
    this.respondTo = function(name) {
        if(this.name == name) {
            alert(“Woof”);        
        }
    };
}

var spot = new DogConstructor(“Spot”);
spot.respondTo(“Rover”); // nope
spot.respondTo(“Spot”); // yeah!
여기에서는 무슨 일이 일어나고 있을까요? DogConstructor 함수 정의에 대해서는 잠시 무시하고 다음 줄을 살펴보십시오.
var spot = new DogConstructor(“Spot”);
"new" 연산자가 수행하는 일은 간단합니다. 우선 이 연산자는 비어 있는 새 개체를 만듭니다. 그런 다음 비어 있는 새 개체를 함수 내의 "this" 값으로 설정하고 이어지는 함수를 호출합니다. 다른 말로 하면 위의 코드에서 "new" 연산자는 아래의 두 줄과 비슷하다고 생각할 수 있습니다.
// create an empty object
var spot = {}; 
// call the function as a method of the empty object
DogConstructor.call(spot, “Spot”);
DogConstructor의 본문에서 볼 수 있는 것처럼 이 함수를 호출하면 해당 호출 시 키워드 "this"가 참조하는 대상으로 개체를 초기화합니다. 이러한 방법으로 개체의 템플릿을 만드는 것이 가능합니다. 비슷한 개체를 만들어야 할 때마다 생성자 함수로 "new"를 호출하면 완전하게 초기화된 개체를 결과로 얻을 수 있습니다. 클래스와 비슷하게 느껴지지 않습니까? 실제로 JavaScript에서 일반적으로 생성자 함수의 이름은 시뮬레이트하는 클래스의 이름이며 따라서 위 예에서는 생성자 함수 이름을 Dog로 지정할 수 있습니다.
// Think of this as class Dog
function Dog(name) {
    // instance variable 
    this.name = name;
    // instance method? Hmmm...
    this.respondTo = function(name) {
        if(this.name == name) {
            alert(“Woof”);        
        }
    };
}

var spot = new Dog(“Spot”);
위의 Dog 정의에서 필자는 name이라는 인스턴스 변수를 정의했습니다. Dog를 생성자 함수로 사용하여 생성한 모든 개체는 자체 인스턴스 변수 이름의 복사본을 가지게 됩니다. 이것은 앞서 언급했듯이 개체 사전에 대한 항목입니다. 예상할 수 있듯이 결국 모든 개체는 자체 상태를 저장하기 위한 자체 인스턴스 변수 복사본이 필요합니다. 그러나 다음 줄을 보면 Dog의 모든 인스턴스가 respondTo 메서드의 자체 복사본을 가지고 있음을 알 수 있습니다. 이것은 낭비이며 respondTo의 한 인스턴스를 Dog 인스턴스 간에 공유하면 충분합니다. 다음과 같이 respondTo 정의를 Dog 외부에 배치함으로써 이 문제를 해결할 수 있습니다.
function respondTo() {
    // respondTo definition
}

function Dog(name) {
    this.name = name;
    // attached this function as a method of the object
    this.respondTo = respondTo;
}
이 방법을 사용하면 Dog의 모든 인스턴스(즉, 생성자 함수 Dog를 사용하여 만든 모든 인스턴스)가 respondTo의 한 인스턴스를 공유할 수 있습니다. 그러나 메서드의 멤버가 늘어나면 이 방법은 점차 관리하기 어렵게 됩니다. 코드베이스 내에 많은 전역 함수가 생기게 되며 "클래스"의 수가 많아질수록, 해당 메서드의 이름이 비슷할수록 상황은 더욱 악화됩니다. 프로토타입 개체를 사용하는 더 좋은 방법이 있으며 자세한 내용은 다음 섹션에서 살펴보겠습니다.

프로토타입
프로토타입 개체는 JavaScript의 개체 지향 프로그램에서 핵심적인 개념입니다. 프로토타입이라는 이름은 JavaScript에서 기존 예(말하자면 프로토타입) 개체의 복사본에서 개체를 만들기 때문에 붙여진 것입니다. 이 프로토타입 개체의 모든 속성 및 메서드는 이 프로토타입의 생성자로 만드는 모든 개체의 속성 및 메서드로 나타나게 됩니다. 이러한 개체가 해당 프로토타입에서 속성 및 메서드를 상속받는다고 할 수 있습니다. 다음과 같이 새 Dog 개체를 만든다고 가정해 보겠습니다.
var buddy = new Dog(“Buddy“);
프로토타입을 가져온 단 한 라인에서는 명백하게 보이지 않을 수 있지만 buddy에서 참조한 개체는 해당 프로토타입에서 속성 및 메서드를 상속하게 됩니다. 개체 buddy의 프로토타입은 생성자 함수(이 경우에는 Dog 함수)의 속성에서 가져옵니다.
JavaScript의 모든 함수에는 프로토타입 개체를 참조하는 "prototype"이라는 속성이 있습니다. 이 프로토타입 개체에는 함수 자체를 참조하는 "constructor"라는 이름의 속성이 있습니다. 이것은 일종의 순환 참조라고 할 수 있는데 그림 3에서는 이러한 순환 관계를 더 잘 보여 주고 있습니다.
그림 3 모든 함수 프로토타입에는 생성자 속성이 있음 
이제 "new" 연산자로 개체를 만들기 위해 함수(이 예에서는 Dog)를 사용하면 결과 개체는 Dog.prototype의 속성을 상속하게 됩니다. 그림 3을 보면 Dog.prototype 개체에 다시 Dog 함수를 가리키는 생성자 속성이 있음을 알 수 있습니다. 따라서 모든 Dog 개체(Dog.prototype에서 상속한) 또한 Dog 함수를 가리키는 생성자 속성을 가지는 것처럼 보입니다. 그림 4의 코드에서 이를 확인할 수 있습니다. 생성자 함수, 프로토타입 개체 및 이들 사용하여 만든 개체 간의 관계는 그림 5에 표시되어 있습니다.
var spot = new Dog(“Spot”);

// Dog.prototype is the prototype of spot
alert(Dog.prototype.isPrototypeOf(spot));

// spot inherits the constructor property
// from Dog.prototype
alert(spot.constructor == Dog.prototype.constructor);
alert(spot.constructor == Dog);

// But constructor property doesn’t belong
// to spot. The line below displays “false”
alert(spot.hasOwnProperty(“constructor”));

// The constructor property belongs to Dog.prototype
// The line below displays “true”
alert(Dog.prototype.hasOwnProperty(“constructor”));
그림 5 해당 프로토타입에서 상속된 인스턴스 
그림 4에서 hasOwnProperty 및 isPrototypeOf 메서드에 대한 호출을 볼 수 있을 것입니다. 이러한 메서드는 어디에서 온 것일까요? Dog.prototype에서 온 것은 아닙니다. 실제로 Dog.prototype 및 Dog의 인스턴스에서 호출할 수 있는 toString, toLocaleString 및 valueOf와 같은 다른 메서드도 있으며 이들 역시 Dog.prototype에서 온 것은 아닙니다. .NET Framework에도 모든 클래스에 대한 궁극적인 기본 클래스 역할을 하는 System.Object가 있는 것처럼 JavaScript에도 모든 프로토타입에 대한 궁극적인 기본 프로토타입인 Object.prototype이 있습니다. Object.prototype의 프로토타입은 Null입니다.
이 예에서는 Dog.prototype이 개체라는 것을 기억하십시오. 보이지는 않지만 이 개체는 Object 생성자 함수를 호출함으로써 생성되었습니다.
Dog.prototype = new Object();
따라서 Dog의 인스턴스가 Dog.prototype에서 상속하는 것처럼 Dog.prototype은 Object.prototype에서 상속합니다. 결국 Dog의 모든 인스턴스는 Object.prototype의 메서드 및 속성 또한 상속하게 됩니다.
모든 JavaScript 개체는 Object.prototype으로 끝나는 프로토타입의 체인을 따라 상속합니다. 지금까지 살펴본 이 상속은 라이브 개체 간의 상속입니다. 선언되는 시점에 클래스 간에 일어나는 상속의 일반적인 개념과는 차이가 있습니다. 결과적으로 JavaScript 상속은 훨씬 동적이며 다음과 같은 간단한 알고리즘을 사용합니다. 개체의 속성/메서드에 액세스하려고 시도하면 JavaScript는 해당 속성/메서드가 개체에 정의되어 있는지 확인합니다. 개체에 정의되어 있지 않은 경우에는 개체의 프로토타입을 확인합니다. 여기에도 정의되어 있지 않으면 Object.prototype에 이를 때까지 개체 프로토타입의 프로토타입을 계속 확인합니다. 그림 6에서는 이러한 확인 프로세스를 보여 줍니다.
그림 6 프로토타입 체인에서 toString() 메서드 확인 (더 크게 보려면 이미지를 클릭하십시오.)
JavaScript가 속성 액세스와 메서드 호출을 동적으로 확인함에 따르는 몇 가지 효과가 있습니다.
  • 프로토타입 개체에 대한 변경은 개체가 생성된 이후에도 개체에 영향을 줍니다.
  • 개체에 속성/메서드 X를 정의하여 동일한 이름의 속성/메서드는 해당 개체의 프로토타입에서 숨겨집니다. 예를 들어 Dog.prototype에서 toString 메서드를 정의하여 Object.prototype의 toString 메서드를 다시 정의할 수 있습니다.
  • 변경은 프로토타입에서 해당 파생 개체로 한 방향으로만 진행하며 반대로는 진행하지 않습니다.
그림 7에서는 이러한 결과를 보여 줍니다. 그럼 7에서는 또한 앞서 발생했었던 불필요한 메서드 인스턴스 문제를 해결하는 방법도 보여 줍니다. 모든 개체가 별도의 함수 개체를 가지도록 하는 것이 아니라 메서드를 프로토타입 내에 배치함으로써 개체가 메서드를 공유하도록 할 수 있습니다. 이 예에서 getBreed 메서드는 spot에서 toString 메서드를 다시 정의하기 전까지 rover 및 spot에 의해 공유됩니다. 이후에 spot은 자신의 getBreed 메서드 버전을 가지지만 rover 개체 및 새 GreatDane으로 만든 이후 개체는 GreatDane.prototype 개체에 정의된 getBreed 메서드의 인스턴스를 공유하게 됩니다.
function GreatDane() { }

var rover = new GreatDane();
var spot = new GreatDane();

GreatDane.prototype.getBreed = function() {
    return “Great Dane”;
};

// Works, even though at this point
// rover and spot are already created.
alert(rover.getBreed());

// this hides getBreed() in GreatDane.prototype
spot.getBreed = function() {
    return “Little Great Dane”;
};
alert(spot.getBreed()); 

// but of course, the change to getBreed 
// doesn’t propagate back to GreatDane.prototype
// and other objects inheriting from it,
// it only happens in the spot object
alert(rover.getBreed());

정적 속성 및 메서드
인스턴스가 아닌 클래스에 연결된 속성이나 메서드, 말하자면 정적 속성 및 메서드가 필요가 경우가 있습니다. JavaScript에서 함수는 원하는 대로 속성과 메서드를 설정할 수 있는 개체이므로 이러한 경우에 대처하기가 수월합니다. JavaScript에서는 생성자 함수가 클래스를 대신하므로 다음과 같이 생성자 함수에 정적 메서드와 속성을 설정함으로써 클래스에 추가하는 효과를 얻을 수 있습니다.
    function DateTime() { }

    // set static method now()
    DateTime.now = function() {
        return new Date();
    };

    alert(DateTime.now());
JavaScript에서 정적 메서드를 호출하기 위한 구문은 C#에서의 구문과 거의 동일합니다. 생성자 함수의 이름은 사실상 클래스의 이름이므로 이는 놀라운 일이 아닙니다. 이제 클래스와 공용 속성/메서드, 그리고 정적 속성/메서드가 있습니다. 이외에 어떤 것이 필요할까요? 우선 전용 멤버가 있습니다. 그러나 JavaScript에는 전용 멤버에 대한 기본 지원이 없습니다. 적어도 보호되는 것은 없으며 모두가 개체의 모든 속성과 메서드에 액세스할 수 있습니다. 클래스에 전용 멤버를 추가하는 방법이 있지만 이를 위해서는 먼저 차단에 대해서 이해해야 합니다.

차단
필자는 스스로 원해서 JavaScript를 배운 것은 아니었으며 JavaScript를 사용하지 않고 현실적인 AJAX 응용 프로그램을 개발한다는 것이 불가능하다는 것을 깨달은 후에야 배우기 시작했습니다. 처음에는 필자의 프로그래머 수준이 몇 단계가 떨어지는 것이 아닌가 하는 생각도 들었습니다. (JavaScript라니! C++를 사용하는 친구들이 뭐라고 말할까?) 그러나 처음 가지고 있던 거부감을 떨쳐내자 JavaScript가 상당히 강력하고 인상적이며 콤팩트한 언어라는 사실을 깨달았습니다. 필자는 또한 널리 사용되는 다른 언어에서 이제 막 지원하기 시작한 기능에 대해서 자랑하기도 했습니다.
JavaScript의 고급 기능 중 하나로 C# 2.0에서는 익명 메서드를 통해 지원되는 차단에 대한 지원이 있습니다. 차단은 안쪽 함수(C#에서는 안쪽 익명 메서드)가 바깥쪽 함수의 로컬 변수와 바인딩되었을 때 일어나는 런타임 현상입니다. 분명한 것은 이 안쪽 함수가 바깥쪽 함수 외부에서 액세스 가능하지 않다면 이것이 의미가 없게 된다는 것입니다. 한 가지 예를 살펴보겠습니다.
예를 들어 100보다 큰 수만 통과할 수 있고 나머지는 필터링되는 간단한 조건으로 일련의 수를 필터링해야 한다고 가정해 보겠습니다. 그림 8와 같이 함수를 작성할 수 있습니다.
function filter(pred, arr) {
    var len = arr.length;
    var filtered = []; // shorter version of new Array();
    // iterate through every element in the array...
    for(var i = 0; i < len; i++) {
        var val = arr[i];
        // if the element satisfies the predicate let it through
        if(pred(val)) {
            filtered.push(val);
        }
    }
    return filtered;
}

var someRandomNumbers = [12, 32, 1, 3, 2, 2, 234, 236, 632,7, 8];
var numbersGreaterThan100 = filter(
    function(x) { return (x > 100) ? true : false; }, 
    someRandomNumbers);

// displays 234, 236, 632
alert(numbersGreaterThan100);
그런데 이제는 다른 필터링 조건, 예를 들어 300보다 큰 수만 통과하도록 다른 필터링 조건을 만들어야 한다고 가정해 보겠습니다. 이제 다음과 같은 코드를 사용할 수 있습니다.
var greaterThan300 = filter(
    function(x) { return (x > 300) ? true : false; }, 
    someRandomNumbers);
그리고 50, 25, 10, 600 등의 수보다 큰 수를 필터링하게 할 수 있습니다. 영리한 독자라면 이 필터가 모두 "보다 큰"이라는 동일한 조건자를 사용하고 있으며 수만 다르다는 것을 간파할 수 있을 것입니다. 따라서 함수에서 수를 인수로 만들어 다음과 같이 작성할 수 있습니다.
function makeGreaterThanPredicate(lowerBound) {
    return function(numberToCheck) {
        return (numberToCheck > lowerBound) ? true : false;
    };
}
이제 다음과 같이 작업할 수 있습니다.
var greaterThan10 = makeGreaterThanPredicate(10);
var greaterThan100 = makeGreaterThanPredicate(100);
alert(filter(greaterThan10, someRandomNumbers));
alert(filter(greaterThan100, someRandomNumbers));
makeGreaterThanPredicate 함수에서 반환된 안쪽 익명 함수를 눈여겨보십시오. 이 익명 안쪽 함수는 makeGreaterThanPredicate로 전달된 인수인 lowerBound를 사용합니다. 일반적인 범위 지정의 규칙에 따르면 makeGreaterThanPredicate가 존재할 때는 lowerBound가 범위를 벗어나게 됩니다. 그러나 이 경우에 안쪽 익명 함수는 makeGreaterThanPredicate가 존재하는 한참 후에도 lowerBound를 가지고 있습니다. 이를 차단이라고 하는 것은 안쪽 함수가 정의된 위치에서 환경에 대해(바깥쪽 함수의 인수 및 지역 변수) 차단을 수행하기 때문입니다.
차단은 처음에는 사소한 기능처럼 보일 수도 있습니다. 그러나 제대로만 활용한다면 개발자의 아이디어를 코드로 구현하는 새롭고 흥미로운 가능성을 열어 줄 수 있습니다. JavaScript에서 가장 흥미로운 차단의 활용 예는 클래스의 전용 변수를 시뮬레이트하는 것입니다.

전용 속성 시뮬레이션
차단을 사용하여 전용 멤버를 시뮬레이트하는 방법을 살펴보겠습니다. 함수의 지역 변수는 일반적으로 함수 외부에서는 액세스할 수 없습니다. 함수가 더 이상 존재하지 않게 되면 지역 변수의 모든 실질적인 용도는 완전히 사라집니다. 그러나 지역 변수가 안쪽 함수의 차단에 의해 캡처되면 계속 존재하게 됩니다. 이것이 바로 JavaScript 전용 속성을 시뮬레이션하기 위한 핵심입니다. 다음 Person 클래스를 살펴보십시오.
function Person(name, age) {
    this.getName = function() { return name; };
    this.setName = function(newName) { name = newName; };
    this.getAge = function() { return age; };
    this.setAge = function(newAge) { age = newAge; };
}
인수 name과 age는 생성자 함수 Person에 대해 로컬입니다. Person이 반환하는 순간 name과 age는 완전히 사라지게 됩니다. 그러나 여기에서 name과 age는 Person 인스턴스의 메서드로 할당된 네 함수에서 캡처되어 계속 유지되며 이러한 네 메서드 내에서만 엄격하게 액세스할 수 있게 됩니다. 즉, 다음과 같은 코드가 가능합니다.
var ray = new Person(“Ray”, 31);
alert(ray.getName());
alert(ray.getAge());
ray.setName(“Younger Ray”);
// Instant rejuvenation!
ray.setAge(22);
alert(ray.getName() + “ is now “ + ray.getAge() + 
      “ years old.”);
생성자에서 초기화되지 않은 전용 멤버는 다음과 같은 생성자 함수의 지역 변수가 될 수 있습니다.
function Person(name, age) {
    var occupation;
    this.getOccupation = function() { return occupation; };
    this.setOccupation = function(newOcc) { occupation = 
                         newOcc; };
  
    // accessors for name and age    
}
이러한 전용 멤버와 C#에서 사용하던 전용 멤버 사이에는 미세한 차이점이 있습니다. C#에서 클래스의 공용 메서드는 클래스의 전용 멤버를 액세스할 수 있었습니다. 그러나 JavaScript에서는 자체 차단 내에 이러한 전용 멤버를 가지고 있는 메서드를 통해서만 이러한 전용 멤버를 액세스할 수 있습니다. 이러한 메서드는 일반적인 공용 메서드와는 다르므로 보통 권한 있는 메서드라고 불립니다. 따라서 Person 공용 메서드 내에서도 전용 메서드에 접근하려면 권한 있는 접근자 메서드를 통해야 합니다.
Person.prototype.somePublicMethod = function() {
    // doesn’t work!
    // alert(this.name);
    // this one below works
    alert(this.getName());
};
Douglas Crockford는 차단을 사용하여 전용 멤버를 시뮬레이트하는 기술을 발견(또는 발표)한 첫 번째 인물로 널리 알려져 있습니다. 그의 웹사이트(javascript.crockford.com)에는 JavaScript에 대한 많은 정보가 있습니다. JavaScript에 관심이 있는 개발자라면 반드시 들러 보아야 할 곳입니다.

클래스로부터 상속
지금까지 생성자 함수가 작동되는 방법과 프로토타입 개체를 사용하여 JavaScript에서 클래스를 시뮬레이트하는 방법을 살펴보았으며 프로토타입 체인을 통해 모든 개체가 Object.prototype의 메서드를 공통적으로 가진다는 것을 확인했습니다. 차단을 사용하여 클래스의 전용 멤버를 시뮬레이트하는 방법도 확인했습니다. 그러나 여기에는 무엇인가가 빠져 있습니다. C#에서는 일상적인 작업이라고 할 수 있는 클래스에서 파생시키는 방법을 아직 설명하지 않았습니다. 아쉽게도 JavaScript에서 클래스를 상속하는 것은 C#에서 콜론을 입력하는 것처럼 단순하지 않으며 그 이상의 작업이 필요합니다. 반면에 JavaScript는 매우 유연하여 클래스에서 상속하는 다양한 방법을 사용할 수 있습니다.
그림 9에서 보여 주는 것처럼 Pet이라는 기본 클래스가 있고 여기에서 파생된 Dog 클래스가 있다고 가정해 보겠습니다. JavaScript에서는 이를 어떻게 구현해야 할까요? Pet 클래스는 간단하며 지금까지 배운 내용으로 구현할 수 있습니다.
그림 9 클래스 
// class Pet
function Pet(name) {
    this.getName = function() { return name; };
    this.setName = function(newName) { name = newName; };
}

Pet.prototype.toString = function() {
    return “This pet’s name is: “ + this.getName();
};
// end of class Pet

var parrotty = new Pet(“Parrotty the Parrot”);
alert(parrotty);
그렇다면 이제 Pet에서 파생된 Dog 클래스를 만들고자 한다면 어떻게 해야 할까요? 그림 9에서 볼 수 있는 것처럼 Dog에는 breed라는 추가 속성이 있으며 Pet의 toString 메서드를 다시 정의하였습니다. C#에서는 메서드와 속성의 이름에 파스칼식 대/소문자가 권장되지만 JavaScript에서는 카멜식 대/소문자를 사용하는 것이 관례입니다. 그림 10에서는 이러한 작동 방식을 보여 줍니다.
// class Dog : Pet 
// public Dog(string name, string breed)
function Dog(name, breed) {
    // think Dog : base(name) 
    Pet.call(this, name);
    this.getBreed = function() { return breed; };
    // Breed doesn’t change, obviously! It’s read only.
    // this.setBreed = function(newBreed) { name = newName; };
}

// this makes Dog.prototype inherits
// from Pet.prototype
Dog.prototype = new Pet();

// remember that Pet.prototype.constructor
// points to Pet. We want our Dog instances’
// constructor to point to Dog.
Dog.prototype.constructor = Dog;

// Now we override Pet.prototype.toString
Dog.prototype.toString = function() {
    return “This dog’s name is: “ + this.getName() + 
        “, and its breed is: “ + this.getBreed();
};
// end of class Dog

var dog = new Dog(“Buddy”, “Great Dane”);
// test the new toString()
alert(dog);

// Testing instanceof (similar to the is operator)
// (dog is Dog)? yes
alert(dog instanceof Dog);
// (dog is Pet)? yes
alert(dog instanceof Pet);
// (dog is Object)? yes
alert(dog instanceof Object);
여기서 사용된 프로토타입 대체 트릭은 프로토타입 체인을 올바르게 설정하므로 C#에서와 마찬가지로 instanceof 테스트도 작동합니다. 또한 권한 있는 메서드 역시 예상대로 작동합니다.

네임스페이스 시뮬레이션
C++와 C#에서 네임스페이스는 이름 충돌의 우려를 최소화하기 위해 사용됩니다. .NET Framework에서 네임스페이스는 예를 들어 Microsoft.Build.Task.Message 클래스와 System.Messaging.Message 클래스를 구별하는 데 사용됩니다. JavaScript에는 네임스페이스 지원과 관련된 세부적인 언어 지원은 없지만 개체를 사용하여 손쉽게 네임스페이스를 시뮬레이트할 수 있습니다. JavaScript 라이브러리를 만들고자 한다고 가정해 보겠습니다. 함수 및 클래스를 전역으로 정의하는 대신 다음과 같이 네임스페이스 내에 래핑할 수 있습니다.
var MSDNMagNS = {};

MSDNMagNS.Pet = function(name) { // code here };
MSDNMagNS.Pet.prototype.toString = function() { // code };

var pet = new MSDNMagNS.Pet(“Yammer”);
한 수준의 네임스페이스는 고유하지 않을 수 있으므로 다음과 같이 중첩된 네임스페이스를 만들 수 있습니다.
var MSDNMagNS = {};
// nested namespace “Examples”
MSDNMagNS.Examples = {}; 

MSDNMagNS.Examples.Pet = function(name) { // code };
MSDNMagNS.Examples.Pet.prototype.toString = function() { // code };

var pet = new MSDNMagNS.Examples.Pet(“Yammer”);
짐작할 수 있겠지만 긴 중첩 네임스페이스를 입력하는 일은 금방 성가시게 느껴지게 됩니다. 다행스럽게도 라이브러리 사용자는 짧은 이름으로 네임스페이스에 별칭을 붙일 수 있습니다.
// MSDNMagNS.Examples and Pet definition...

// think “using Eg = MSDNMagNS.Examples;” 
var Eg = MSDNMagNS.Examples;
var pet = new Eg.Pet(“Yammer”);
alert(pet);
Microsoft AJAX 라이브러리의 소스 코드를 살펴보면 라이브러리의 저자 역시 네임스페이스를 구현하기 위해 비슷한 기술을 사용했음을 알 수 있습니다. 정적 메서드 Type.registerNamespace의 구현을 살펴보십시오. 자세한 내용은 보충 기사 "OOP 및 ASP.NET AJAX"를 참조하십시오.

JavaScript에서 이와 같이 코딩해야 할까요?
지금까지 JavaScript에서도 개체 지향 언어를 문제 없이 지원한다는 것을 확인했습니다. 프로토타입 언어로 설계되었지만 JavaScript는 유연하고 강력하므로 널리 사용되는 다른 언어에서 일반적으로 사용되는 클래스 기반 프로그래밍 스타일을 지원할 수 있습니다. 그러나 문제는 JavaScript에서 이와 같이 코딩해야 하는지 결정하는 것입니다. C# 또는 C++에서 코딩하는 방식대로 JavaScript로 코딩하면서 없는 기능은 시뮬레이트하는 것이 현명한 방법일까요? 각각의 프로그래밍 언어는 서로 다르며 한 언어의 최상의 방법이 다른 언어에서는 최상의 방법이 아닐 수 있습니다.
JavaScript에서는 클래스가 다른 클래스에서 상속하는 것과 달리 개체가 다른 개체에서 상속하는 것을 확인했습니다. 따라서 정적 상속 계층을 사용하여 많은 클래스를 만들기는 가능하지만 이것은 JavaScript에 맞는 방식은 아닙니다. Douglas Crockford가 그의 자료 "JavaScript의 프로토타입 상속"에서 밝힌 것처럼 JavaScript에 맞는 프로그래밍 방식은 프로토타입 개체를 만들고 해당 원본 개체에서 상속하는 새 개체 아래에 간단한 개체 함수를 만드는 방식일지도 모르겠습니다.
    function object(o) {
        function F() {}
        F.prototype = o;
        return new F();
    }
JavaScript의 개체는 유연하므로 만든 후에 필요에 따라 새 필드와 새 메서드를 사용하여 손쉽게 개체를 보강할 수 있습니다.
지금까지는 모두 좋지만 전 세계에 있는 개발자 대부분이 클래스 기반 프로그래밍에 익숙하다는 사실은 부인할 수 없습니다. 클래스 기반 프로그래밍은 또한 계속해서 유지될 것입니다. 발표 예정인 버전 4 ECMA-262 규약(ECMA-262는 JavaScript의 공식 사양)에 따르면 JavaScript 2.0에는 진정한 클래스가 추가될 예정입니다. 즉, JavaScript는 클래스 기반 언어로 변화하고 있습니다. 그러나 JavaScript 2.0이 널리 보급되기까지는 몇 년이 걸릴 것입니다. 그 전까지는 현재의 JavaScript로 프로토타입 기반 스타일과 클래스 기반 스타일 코드를 모두 읽고 작성할 수 있다는 사실을 알고 있는 것이 중요합니다.

앞으로의 전망
클라이언트에 크게 의존하는 대화식 AJAX 응용 프로그램이 확산됨에 따라 JavaScript는 빠른 속도로 .NET 개발자를 위한 가장 유용한 도구로 자리를 잡고 있습니다. 그러나 JavaScript의 프로토타입 특성은 C++, C# 또는 Visual Basic과 같은 언어에 익숙해 있던 개발자들에게 다소 생소할 수 있습니다. 필자의 경험을 이야기하자면 과정에 어려움이 없었던 것은 아니지만 JavaScript를 배우는 과정은 충분히 가치가 있었다고 생각합니다. 이 기사를 통해 여러분의 과정을 도울 수 있다면 좋다면 좋겠습니다. 바로 그것이 필자의 목표입니다.
OOP 및 ASP.NET AJAX
ASP.NET AJAX에 구현된 OOP와 이 기사에서 설명한 정식 구현과는 약간의 차이점이 있습니다. 이러한 차이점이 있는 이유는 두 가지입니다. ASP.NET AJAX 버전에서는 xml-script 및 매개 변수 유효성 검사와 같은 선언적 구문에 필수적인 리플렉션에 대한 더 많은 가능성을 제공하며 ASP.NET AJAX는 .NET을 사용하는 개발자에게 익숙한 속성, 이벤트, 열거형 및 인터페이스와 같은 몇 가지 추가 구조를 JavaScript에 제공하는 데 초점을 맞추고 있습니다.
현재 널리 사용 가능한 버전의 경우 JavaScript에는 .NET 개발자에게 익숙한 몇 가지 핵심 OOP 개념이 빠져 있지만 ASP.NET AJAX에서는 이러한 대부분의 개념을 에뮬레이트합니다.
클래스에 명명 규칙 기반의 속성 접근자(예는 조금 뒤에 있음)는 물론 .NET에서 제공되는 패턴을 비슷하게 따르는 멀티캐스트 이벤트를 추가할 수 있습니다. 전용 변수는 밑줄로 시작하는 멤버는 전용이라는 관례에 바탕을 두고 있습니다. 진정한 전용 변수가 필요한 경우는 드물지만 이 정책은 디버거에서 이러한 변수를 검사할 수 있도록 해 줍니다. 일반적인 오리 형식 지정을 벗어난 형식 검사 시나리오를 지원하기 위해 인터페이스가 추가되었습니다. 오리 형식 지정이란 어떤 것이 오리처럼 걷고 오리 같은 소리를 낸다면 이것은 오리이거나 최소한 오리와 같이 취급해야 한다는 개념에 바탕을 둔 것입니다.

클래스와 리플렉션
JavaScript에서 함수의 이름을 알아낼 수 있는 방법은 없습니다. 이것이 가능하다고 하더라도 네임스페이스 변수에 익명 함수를 할당함으로써 클래스 생성자를 작성하는 대부분의 상황에는 큰 도움이 되지 않을 것입니다. 실제 형식 이름을 구성하는 것은 동등한 수준으로 액세스가 불가능하며 생성자 함수 자체가 아무런 정보도 없는 이 변수의 정규화된 이름입니다. 이러한 한계를 해결하고 JavaScript 클래스에 대한 풍부한 리플렉션을 제공하기 위해 ASP.NET AJAX에서는 형식의 이름을 등록하도록 요구하고 있습니다.
ASP.NET AJAX의 리플렉션 API는 기본 제공 형식, 클래스, 인터페이스, 네임스페이스는 물론 열거형을 포함하여 어떤 형식에 대해서도 작동하며 런타임에 클래스 계층을 검사하기 위한 isInstanceOfType 및 inheritsFrom와 같은 .NET Framework와 비슷한 함수도 포함합니다. ASP.NET AJAX는 또한 디버그 모드에서 약간의 형식 검사를 수행하여 개발자가 더 일찍 버그를 찾을 수 있도록 지원합니다.

클래스 계층 및 호출 기반 등록
ASP.NET AJAX에서 클래스를 정의하려면 해당 생성자를 변수에 할당해야 합니다. 생성자가 기반을 호출하는 방법을 확인하십시오.
MyNamespace.MyClass = function() {
    MyNamespace.MyClass.initializeBase(this);
    this._myProperty = null;
}
Then, you need to define the class members itself in its prototype:

MyNamespace.MyClass.prototype = {
    get_myProperty: function() { return this._myProperty;},
    set_myProperty: function(value) { this._myProperty = value; },
    doSomething: function() {
        MyNamespace.MyClass.callBaseMethod(this, “doSomething”);
        /* do something more */
    }
}
이제 최종적으로 클래스를 등록하게 됩니다.
MyNamespace.MyClass.registerClass(
    “MyNamespace.MyClass “, MyNamespace.BaseClass);
생성자와 프로토타입 계층은 registerClass 함수에 의해 자동으로 관리되므로 직접 관리할 필요가 없습니다.

Bertrand Le Roy는 ASP.NET AJAX 팀의 소프트웨어 설계 엔지니어 II입니다.

출처 : http://asrada2001.tistory.com/163


스쿨에 javascript 의 색다른 표현식에 관한 글이 올라왔다(by 행복한고니)

그중 new Object === {} 라는 고니님의 의견에 숨어지내리님이 급 제동을 걸어왔다.
너무나도 살벌한 분위기 속에서 결국 두 분의 논쟁에는 결론이 나질 않았고
나는 개인적으로 무소레즈님의 코멘트를 이 논쟁의 결론으로 치부한다.


무소레즈님의 댓글


--------------------------------------- 
1. new Object() === {} 가 같다? 
2. Object 가 {} 으로 만들어진다? 
3. constructor 의 비교로 객체가 똑같다고 말할수 있다? 
4. Object 는 Function 의 instance 이다? 
--------------------------------------- 

1. new Object() === {} 가 같다? 
답변 1. 엄밀하게 다릅니다. 

    ( new Object() === {} )  의 결과는 false 입니다. 
    하지만 함수 객체타입은 같기에  instance 를 비교하면 true 입니다. 
    왜냐하면 같은 Object 함수의 객체타입으로 생성되기 때문입니다. 
    어떤 함수든 new 통하여 새로운 instance 개체를 생성하면 
    어떤 instance 개체든 Object 함수 객체타입의 instance 를 갖습니다. 

    예를 들어 

        today = new Date(); 

        today 라는 instance 개체는 
        Date 함수객체타입의 instance 이기도 하지만 
        Object 함수 객체타입의 instance 이기도 합니다. 

    또한 사용자 정의 함수를 통하여 새로운 instance 개체를 생성해도 마찬가지입니다. 

        function funcName() { 
        } 
        fn = new funcName(); 

        fn 이라는 instance 개체는 
        funcName 함수객체타입의 instance 이기도 하지만 
        Object 함수 객체타입의 instance 이기도 합니다. 

        fn 은 독립적인 instance 개체로서 
        funcName 이라는 함수객체에서 정의된 구조(초기환경설정)의 instance 을 가졌다는 것이지요. 

        만약 funcName 함수로 또다른 instance 개체를 생성한다면 

        fn2 = new funcName(); 

        fn2 은 fn 과는 서로다른  instance 개체이지만 
        funcName 이라는 함수명으로 정의된 구조를 가진 같은 instance 를 가집니다. 
        fn1 과 fn2 는 같은 instance 를 가지고 있지만 서로 다른 개체입니다. 


    (new Object) 와  {} 에의해 생성된 각각의 instance 객체변수로 비교하자면 

        x1=new Object 
        x2=new Object 
        y1={}; 
        y2={}; 

        (x1 === x2); 
        (y1 === y2) 
        (x1 === y1); 
        (x2 === y2); 

    모두 false 입니다.  생성된 instance 개체가 서로 독립적이기 때문이지요. 
    하지만  instanceof 연산자를 이용하여 비교해보면 모두 같은 instance 를 가지고 있습니다. 

    Object 함수객체 타입은  ( Object.prototype.constructor ) 로 알아낼수 있습니다. 
      결과는 :  function Object() { [native code] } 
    funcName 함수객체 타입은  ( funcName.prototype.constructor ) 로 알아낼수 있습니다. 
      결과는 : function funcName() { } 

    (new Object ) 와 {} 는 미리 정의된 Object 함수 객체를 통하여 
    서로다른 새로운 instance 개체들을 생성합니다. 
    사용자 정의 함수에서 처럼  funcName 이 없기때문에 
    Object 함수 객체타입의 instance 만을 갖게 되는 것입니다. 

    ★ 그렇다고 (new Object) 와 {} 가 Object 함수객체 내부에서 주어진 정의가 완전히 같은가? 
    그렇지 않습니다. 
    {} 는 Object initializer (개체 초기화 지정자) 라고 불리우며, 
    Object initializer 라 불리우는 {} 를 다른 함수의 내부에서 사용시 
    Object initializer 를 호출할때 마다, {} 에의 정의된  속성과 그에 할당된 표현식이나 값을 
    매번 다시 해석(interpret) 한다는 것이 (new Object) 와 다릅니다. 

    함수내부에서 개체 초기화 지정자인 {} 를 정의하고 
    그 함수를  호출하면 {} 에의해 정의된 속성과 그 값을 다시 해석하여 
    매번 초기화 시킨다는것입니다. 

        function funcName (cond) { 
                A=3; 
                B={ A:5 }; 
                C=new Object; 
                Object.prototype.A=7; 

                if(cond==1) return B.A; 
                else if( cond==2) return C.A; 
                else  return A; 
        } 

        A1=funcName(0); 
        B1=funcName(1); 
        C1=funcName(2); 

        A2=funcName(0); 
        B2=funcName(1); 
        C2=funcName(2); 


        A1 과 A2 는 메모리에 이미 저장된 "3" 이란 값을 반환 받습니다. 
        C1 과 C2 도 메모리에 이미 저장된 "7" 이란 값을 반환 받습니다. 
        B1 과 B2 는 각각 호출시 초기화 지정자를 재 해석하여 메모리에 다시 올려 놓고, 
        그 후에 "5" 라는 값을 반환합니다. 

        B 는  초기화 지정자 {}로 할당 받았기 때문에 
        매번 함수를 호출 할때마다  B 의 속성과 값을 재 해석하여 메모리에 재 저장합니다. 
        즉, 함수를 호출할때마다 매번 다시 초기화 시킨다는 말입니다. 


        만약 함수 외부에서 초기화 지정자를 사용했다면 
        var G={ A: 9 }; 
        G.A 를 호출할때 이미 초기화되어 메모리에 저장되어 있는 "9" 라는 값을 불러오게 됩니다. 
        다른 곳에서 G.A 를 호출해도 역시 이미 저장되어 있는 값 "9"를 반환합니다. 
        함수 내부에서 처럼 재 해석하여 재 초기화 시키는 것이 아닙니다. 

        C1 과 C2 를 호출하면 이미 메모리에 저정되어 있는  "7" 이라는 값을 반환합니다. 
        B1 과 B2 처럼 호출할때마다 재 초기화 시키는 것이 아닙니다. 

        그렇게 (new Object ) 와 {} 는 다릅니다. 


2. Object 가 {} 으로 만들어진다? 
답변 2. 
    {} 를 호출하면 내부에서 새로운 (new Object) 를 생성하여 instance 개체를 반환한다고 알고 있습니다. 


3. constructor 의 비교로 객체가 똑같다고 말할수 있다? 
답변 3. 
    (객체.constructor) 의 사용은 생성자가 어떤 객체타입을 가지고 있는지 참조할수 있도록 
    미리 정의되어 있는 Object 의 prototype 일뿐입니다. 
    프로그램의 처리 로직에따라 객체의 속성으로써 prototype 정의는 언제든 변경 가능하며 
    변경된 결과를 처리 조건에따라 필요할때 마다 활용할 수 있습니다. 

    (개체.constructor) 는  
    개체를 새로 생성했을때 그 개체가 
    어떤 객체 타입을 가진 생성자 함수로부터 생성된 개체인지를 참조할 수 있도록 
    Javascript 에서 미리 정의해둔 하나의 속성 일뿐입니다. 
    변경 불가한 상수가 아니란 것이지요. 
    프로그램 처리의 상황에따라 그 값을 변경하며, 참조하여 활용할 수 있습니다. 

    "constructor 의 비교로 객체가 똑같다고 말할수 있습니다." 
    에대해서는 그럴수도 있고 아닐수도 있겠지요. 
    프로그램의 처리 상황에따라 그 속성을 주어진대로 활용하거나, 변경하여 사용하거나 
    아니면 사용하지 않거나.. 
    엿을 파는 엿장수 맘 아니겠습니까? 

    엿장수 맘대로 사용했을때 문제가 발생할 여지가 있다면야 그렇게 사용해서는 안되겠지요. 
    어느 분이든...  어떤 경우에 문제가 생기는지 알려주시면 
    저도 다음부터는 유의하여 사용해 보겠습니다. 


4. Object 는 Function 의 instance 이다? 
답변 4. 
    이미 정의되어 있는 Object 는 Function 함수 객체로부터 생성된 함수 객체이기때문에 
        Function 함수 객체타입의 instance 를 갖습니다. 
        또한 동시에 new 를 통하여 생성되기때문에 Object 객체타입의 instance  를 갖기도 합니다.

검색엔진을 뒤지면서 보다가 너무나 깔끔하게 정리된

자바스크립트가 있기에 퍼옴. GENERAL 님의 정리 감사합니다.

댓글은 아래 링크 블로그에 달아주세요~ ^^


링크 : http://blog.naver.com/minis24/80094251902

2006년 정도 인걸로 기억이 나는데요.. ajax 가 한참 이슈가 되던 시절이 있었습니다.

지금도 ajax를 많이 쓰고는 있지만 그 당시 처럼 환상에 가려진, 신비의 테크닉이라는 고급기술에서

범용 테크닉으로 많이 일반화 되었지요..

 

무턱대고 ajax 책을 사서 보았는데..음 당췌 무슨 말인지 이해가 안되더군요..

시간이 약이라고 해야하나요? 한몇년 그렇게 해매면서 고민하면서 정리하면서 살다보니

어느덧 익숙해지더라구요~ 아직 많은 부분이 부족하긴 하지만요~

 

ajax를 잘 사용하기 위해서는 문서객체구조(DOM - Document Object Model)에 대해

잘 이해하고 사용할 수 있어야 세밀하게 콘트롤 하는것이 가능할것입니다.

 

그래서 이번에는 진화에 진화를 거듭해온 자바스크립트 DOM 에 대해서 정리해 볼려구요~

 


* 자바스크립트 DOM Script

    - HTML 또는 XHTML 문서에서 모든 엘리먼트는 객체입니다.

    - DOM 에서 제공하는 API 를 제어하여 이러한 객체들에 접근하는것이 가능하며,

      콘트롤 하는것이 가능합니다.

      

       ※ 네이티브객체 : 자바스크립트내에 미리 만들어진 객체

                               ex ) Date,Array,Math......

           호스트객체 : 자바스크립트 실행환경에서 만들어진 객체

                               ex ) 웹브라우저에서 제공하는 객체

                                      폼(form),이미지(Image),요소(element)

 

    1. node (노드) : 어떤 연결망에서 특정지점과 지점을 연결하는 것.

        (1) element node - <body>,<p>,<ul>......

        (2) text node - 웹문서에서 내용에 해당하는 부분

                            <p>이 부분이 텍스트노드 </p>

        (3) attribute node - <p title ="이 부분이 속성노드" >aaaaaaaaaaaaaaa</p>

 

* DOM 코어 API

    - getElementById

    - getElementsByTagName

    - getAttribute

    - setAttribute

    - ...등

    DOM을 지원하는 모든 프로그래밍 언어에서 사용가능함.

 

* HTML-DOM

    - (x)HTML 문서에 쓰인 DOM을 이용할때 사용할 수 있는 프로퍼티.

     ex) forms 객체 제공

          var forms = document.getElementsByTagName("form") ;

                        = document.forms ;

          var src = element.getAttribute("src");

                     = element.src ;

 

         element.setAttribute("src",url);

         = element.src = url ;

 

* getElementById ("_ID")

    - document 와 함께 사용한다.

    - 문서 구조에서 id 속성값이 _ID 인 엘리먼트객체를 리턴한다.

      ex) document.getElementBy("_ID"); 

* getElementsByTagName ("tag")

    - 해당 객체의 자식노드에서 특정 태그(tag)를 사용하는 element들을 배열로 리턴함

      ex) element.getElementsByTagName("tag");

  

* getAttribute ()

    - object.getAttribute("attribute");

      ※ Document객체를 사용할 수 없고, 각 요소객체에서만 동작함..

* setAttribute ()

    - object.setAttribute("attribute",value);

      ※ Document객체를 사용할 수 없고, 각 요소객체에서만 동작함..

 

      HTML DOM을 사용해서 아래와 같이 속성을 읽고 설정 할 수 있습니다.

          ex ) element.value ="new value";

      소스의 길이가 짧고 간단하다는 장점이 있지만, 폼,이미지등의 일부요소에서만 동작합니다.

      

      DOM 코어 API를 사용하길 추천합니다.    

 

* childNodes

    - 해당 요소의 모든 자식요소를 포함하는 배열 리턴함.

    - 요소노드뿐만 아니라 모든 형식의 노드를 포함하는 배열 리턴

    ex) <body> 태그를 가져오는 방법

          1. var body = document.getElementsByTagName("body")[0];

          2. document.body;

          

             body.childNodes

* nodeType;

    - node.nodeType;

      ex) var typeStr = body.nodeType ;

          

           # 요소노드의 nodeType 값 : 1

           # 속성노드의 nodeType 값 : 2

           # 텍스트노드의 nodeType 값 : 3

 

* nodeName;

   - 어떤 요소인지 확인가능함 (참고로 저는 디버깅 할때 주로 써요)

    - 대문자로 표시해야함.

    - if(element.nodeName == "IMG");

 

* nodeValue;

   - 텍스트노드의 값을 바꾸려면 nodeValue를 사용

    - node의 값을 가져오거나, 설정할 수 있다.

 

      ※ 주의

         1) 텍스트는 요소의 첫번째 자식요소이다.

             ex)

                var obj = document.getElementById("~~~~~");

                     alert ( obj.nodeValue);         //null 출력

                     alert( obj.childNodes[0].nodeValue);

 

* firstChild;

   - node.firstChild

        = node.childNodes[0] ;

* lastChild;

   - node.childNodes[node.childNodes.length-1];

 

* createElement;

   - 새 요소를 생성한다.

    - 노드트리에 새로운 요소를 추가한다.

 

          ex ) var newElement = document.createElement("p")   // <p></p>요소 생성

       

    - append 하기전이라도 nodeType, nodeValue 가 있다.

    - 그러나 아직은 브라우저에서 표시되지는 않는다.

 

* removeChild;

   - parent.removeChild(삭제객체);

      --> 리턴 : 삭제된 객체를 리턴한다.

 

      ex) var removeElement = 부모엘리먼트.removeChild(삭제할 객체);

 

* appendChild;

   - parent.appendChild(child)

 

      ex) var testDIV = document.getElementById("testDIV") ;

           var para = document.createElement("p");

           testDIV.appendChild(para);

 

* createTextNode;

   - 텍스트 노드를 생성

    ex )

       var txt = document.createTextNode("HELLO");

            para.appendChild(txt);

 

* InsertBefore;

   - parentElement.insertBefore( newElement , targetElement ) ;

 

* InsertAfter;

   - targetElement의 뒤에 newElement를 추가한다.

   - DOM API 가 아님.~~~~~

 

       (source)

          function insertAfter(newElement , targetElement){

               var parent = targetElement.parentNode;

               if (parent.lastChild == targetElement){

                   parent.appendChild(newElement) ;

               }else{

                   parent.insertBefore(newElement , targetElement.nextSibling ;

              }

         }

 

* parentNode;

   - element의 부모노드를 리턴한다.

     ex)

        var parentElement = element.parentNode ;


검색엔진을 뒤지면서 보다가 너무나 깔끔하게 정리된

자바스크립트가 있기에 퍼옴. GENERAL 님의 정리 감사합니다.


링크 : http://blog.naver.com/minis24/80094251902


* 생성자 체이닝

 

    정리 6의 마지막에서 처럼 서브클래스의 생성자 함수 내에서 상위클래스의 생성자를

    명시적으로 호출하는 것을 생성자 체이닝 이라고 한다.

 

    call() 함수를 써서 생성된 객체의 메서드인것 처럼 호출했었는데 다음처럼 간단하게 고칠 수 있다.

 

    //상위클래스에 대한 참고 저장

    subRectangle.prototype.superclass = Rectangle ;

 

   function subRectangle( x , y , w ,h ){

       // 프로토타입 객체의 프로퍼티인 superclass 에 Rectangle 참조를 저장하여

       // subRectangle 클래스의 메서드화 하여 실행함.

       this.superclass (w , h) ;

       this.x = x ;

       this.y = y ;

   }

 

   ※ 정리6 에서 자바스크립트 생성자,클래스,프로토타입 과 연결된 내용입니다.


검색엔진을 뒤지면서 보다가 너무나 깔끔하게 정리된

자바스크립트가 있기에 퍼옴. GENERAL 님의 정리 감사합니다.

댓글은 아래 링크에 달아주세요~


링크 : http://blog.naver.com/minis24/80094251902

* 자바스크립트 클래스의 서브클래스 정의하기 
 
   자바스크립트는 프로토타입 기반의 상속을 지원하므로 프로토타입 객체를 
    알맞게 조작하여 서브클래스를 흉내낼수 있다.아래는 그 방법이다.
 
   1. 서브클래스의 생성자에서 슈퍼클래스의 생성자를 호출한다.
      이때, 슈퍼클래스의 생성자가 새로만든 객체의 메서드인것처럼 호출해야 한다.
 
   2. 프로토타입 객체를 설정한다.
       * 프로토타입객체를 반드시 슈퍼클래스의 인스턴스로 만들어 줘야한다.
       * 프로토타입 객체의 constructor 프로퍼티를 명시적으로 설정해 줘야한다.  
      
 
  ex)
      //슈퍼클래스 정의
      //이 클래스의 서브클래스를 정의한다.
      function Rectangle(w,h){
          this.width = w ;
          this.height = h ;
      }
   
     //슈퍼클래스의 프로토타입 객체에 area 프로퍼티 정의 및 초기화
     Rectangle.prototype.area = function() {
         return this.width * this.height ;
     }
 
     //서브클래스의 생성자에서 슈퍼클래스의 생성자를 호출한다.
     //이 때, 슈퍼클래스의 생성자가 새로만든 객체의 메서드인것처럼 호출한다.  
     //생성자 체이닝            
     function subRectangle ( x , y , w , h ){
         Rectangle.call ( this , w , h ) ;
            //= subRectangle.Rectangle(w,h);
            //= subRectangle.width = w ;
            //= subRectangle.height = h ;
 
            //this 객체는 Rectangle 생성자함수가 소속되어 호출될 객체이다. (subRectangle 생성자)
            //Rectangle 생성자 함수를 this 객체의 메서드인것처럼 호출
 
                ※ call ()
                     첫번째 전달인자 : 함수가 소속되어 호출될 객체 지정
                     함수의 몸체 안에서 this 키워드의 값이 된다.
                   
                      나머지 전달인자 : 함수가 호출될때의 전달인자.
         this.x = x ;
         this.y = y ;
     }
    
     //서브클래스의 프로토타입 객체를 명시적으로 슈퍼클래스의 인스턴스로 설정한다.
     //기본 프로토 타입 객체를 사용하면 Objec 클래스의 서브클래스가 된다.
     //프로토타입 객체 역시 하나의 객체이므로 Object() 생성자를 사용하여 만들어지기 때문에.
 
     //new 연산자는 빈 객체를 생성한 후 생성된 객체의 프로토타입 객체를 설정한다.
     //이 때 생성된 객체는 자신을 만들어낸 생성자의 prototype 프로퍼티 값을
     //자신의 프로토타입객체로 설정한다.
    
     //subRectangle클래스의 프로토타입객체가 Rectangle 클래스의 인스탄스 이므로
     //subRectangle은 프로토타입 객체인 Rectangle 인스탄스의 프로퍼티를 상속받게 된다. 
    subRectangle.prototype = new Rectangle();
 
     //subRectangle.prototype 객체가 Rectangle 클래스의 인스턴스 이므로
     //subRectangle 클래스의 모든 인스턴스는 프로토타입 객체인 Rectangle 인스탄스의
     //모든 프로퍼티를 상속받게 될것이므로, 필요없는 프로퍼티는 삭제하여 준다.
    delete.subRectangle.prototype.width ;
    delete.subRectangle.prototype.height ;
    
    //subRectangle 클래스의 프로토타입 객체가 Rectangle() 생성자를 사용해서 만들어졌으므로
    //constructor 프로퍼티는 Rectangle()생성자를 참조한다.
    //constructor 프로퍼티를 수정하여 준다.
    subRectangle.prototype.constructor = subRectangle ;
   
    이제 subRectangle 클래스의 프로토타입 객체가 만들어 졌으며,
    여기에 새로운 메서드를 추가할 수 있다.
 
 
 

* 생성자 체이닝

 

    서브클래스의 생성자 함수 내에서 상위클래스의 생성자를 명시적으로 호출하는 것을

    생성자 체이닝 이라고 한다.

 

    call() 함수를 써서 생성된 객체의 메서드인것 처럼 호출했었는데 다음처럼 간단하게 고칠 수 있다.

 

    //상위클래스에 대한 참고 저장

    subRectangle.prototype.superclass = Rectangle ;

 

   function subRectangle( x , y , w ,h ){

       // 프로토타입 객체의 프로퍼티인 superclass 에 Rectangle 참조를 저장하여

       // subRectangle 클래스의 메서드화 하여 실행함.

       this.superclass (w , h) ;

       this.x = x ;

       this.y = y ;

   }

 

검색엔진을 뒤지면서 보다가 너무나 깔끔하게 정리된

자바스크립트가 있기에 퍼옴. GENERAL 님의 정리 감사합니다.


링크 : http://blog.naver.com/minis24/80094251902


* 자바스크립트는 자바와 같은 실제 클래스를 지원하지는 않는다.

    (자바스크립트 2.0에서는 지원한다고 합니다.

* 대신 자바스크립트는 프로토타입객체와 생성자 함수를 사용하여 모조클래스를 구현할 수 있다.

   (이하 클래스라 함)

 

 

* 자바스크립트 생성자

     - new 연산자와 함께 사용되도록 설계된 함수를 생성자라고 한다.

     - 생성자는 새로운 객체를 초기화 하고 객체에 있는 프로퍼티중에서 사용되기전에

          미리 값이 할당되어야 하는 프로퍼티들의 초기값을 할당 한다.

     

     - 생성자는 객체들의 클래스를 정의한다.

     

     - 생성자는 일반적으로 리턴 값이 없이 this 키워드가 가리키는 객체들을 초기화

          시키는 역할을 한다.

     - 생성자 함수에서 결과값으로 객체를 리턴하면, 리턴값을 가질 수 있으며, new 문장의

          결과 값이 된다. 이때, this가 가리키던 객체는 폐기 된다.

        

     - 아래 처럼 적절한 생성자 함수를 정의하는 방법으로 객체들의 클래스를 만들수 있다.

           

           function Rectangle( w , h ) {

                this.width = w ;

                this.height = h ;

 

           }

          

           var rect1 = new Rectangle( 2 , 4 ) ;

           var rect2 = new Rectangle( 5 , 3 ) ; 

 

           // rect1 = { width : 2 , height : 4 } ;

 

 
* 자바스크립트 메서드
    - 메서드는 객체의 프로퍼티 이자, 호출가능한 함수다.
    - 메서드 내의 this 키워드는 메서드가 속한 객체를 가리킨다.
 
      ## Rectangle 객체로 표현된 사각형의 넓이를 구하는 몇가지 방식       
         첫번째 비객체지향적인 방식
             function computeArea( rect1 ) {
                return rect1.width * rect1.height ;
             }
 
          두번째 메서드 사용 방식
             rect1.area = function () {
                                 return this.width * this.height ;
                              }
             var a = r.area() ;
 
          세번째  메서드 사용방식 개량
             function Rectangle( w , h ) {
                  this.whidth = w ;
                  this.height = h ;
                  this.area = function () {
                                      return this.width * this.height ;
                                  }
            }
            var rect1 = new Rectangle( 2 , 4 );
            var a = rect1.area();
 
         ※ 생성자 내부에서 메서드를 추가하는 방법은 실행하는데는 문제 없지만
             비효율적인 방식입니다. (메모리 활용 면에서..)
             왜냐면..위의 생성자로 생성된 인스탄스들은 모두 프로퍼티를 세개를 같습니다.
            
              width,height,area  ==> 3개
 
             모든 인스턴스가 공유해야하는 프로퍼티에 일반적인 프로퍼티를 사용하는것은
             비효율적입니다. 차라리 공통의 프로토타입이라는 공통의 객체의 프로퍼티를 상속받아서
             사용하는것이 메모리사용에 좀더 효율적입니다.  
            
 
   
* 자바스크립트 프로토타입 (prototype)
    - 모든 객체는 프로토 타입이라는 또다른 객체를 내부적으로 참조할 수 있다.
    - 모든 객체는 프로토타입의 프로퍼티들을 자신의 프로퍼티로 가져온다
       즉, 자바스크립트 객체는 자신의 프로토타입객체에 있는 프로퍼티를 상속 받는다.
 
    - 모든 함수에는 prototype 이라는 프로퍼티가 있는데 함수가 정의되는 순간부터 자동으로
       생성되고 초기화 된다.
    - prototype 프로퍼티의 초기값은 프로퍼티가 하나 있는 객체로서 설정된다.
                                                 = 생성자 함수를 가리키는 contrtuctor 프로퍼티를 가지는 객체
 
    - 프로토타입 객체에 추가한 프로퍼티들은 생성자를 사용하여 생성된 모든 객체의 프로퍼티로
      나타난다. 
 
     Rectangle.prototype.area =
        function () {
            return this.width * this.height ;         
        } ;
      
    ※ 중요 !!
        - 이 생성자 ,(Rectangle)를 사용해 생성되는 객체들은 모두 프로토타입 객체의
             프로퍼티들을 상속받는다.
 
          프로토타입객체에 새로운 프로퍼티가 추가되면, 이미 생성된 객체일지라도
              새로 추가된 프로퍼티를 상속받는다.
          - 기존의 클래스에 새로운 메서드를 추가할 수 있다는 의미가 됨
          - 각 객체가 프로토타입 객체를 상속받는다.
             각 객체로 프로토타입의 프로퍼티들이 복사되는 것이 아님!! (메모리 절약 !!)
              
        Object.hasOwnProperty() 를 통해서 상속받은 프로퍼티인지 확인하수 있다.
        
        var r = new Rectangle( 2 , 3 );
        r.hasOwnProperty("width") ;                  // true  width 는 r의 직접적인 프로퍼티 이다.
        r.hasOwnProperty("area") ;                   // false area 는 상속받는 프로퍼티 이다.
        "area" in r                                           // true   area 는 r 의 프로퍼티이다.
 
* 상속 받은 프로퍼티의 읽기와 쓰기
     - 클래스에는 프로퍼티의 집합과 더불어 한 개의 프로토타입 객체가 있다. 
     - 클래스의 인스턴스는 여러개가 있을 수 있는데 ,각 인스턴스들이 각각
        프로토타입의 프로퍼티들을 상속 받는다.
 
     ※ 한개의 프로토타입 객체의 프로퍼티를 여러개의 인스턴스들이 상속받기 때문에
         프로퍼티 값을 읽거나 쓸때 비대칭성을 의무적으로 지키도록 하고 있다.
          (읽고 쓸때 비대칭적이라는 의미임)
         ex)
          객체 obj 의 프로퍼티인 p를  읽을때 obj에 p라는 프로퍼티가 있는지 확인한다.
           만약 없다면 obj 의 프로토타입 객체에 p라는 프로퍼티가 있는지 검사한다.
 
          프로퍼티 값을 쓸때는 프로토타입 객체를 사용하지 않는다
          객체 obj가 프로토타입에서 상속받은 프로퍼티인 p를 설정하려 하면,
          obj 에는 새로운 프로퍼티 p 가 만들어 진다.
 
          ※ 상속은 읽을때만 일어난다 !! 
               자바스크립트는 p의 값을 찾으려 할때 먼저 obj 에서 있는지 확인한 후
               없을 경우에만 프로토타입 객체에서 검사한다.
 
              [ obj 에있는 프로퍼티 p 가 프로토타입 객체에 있는 프로퍼티 p를 가렸다 ]  
                     
       
* 자바스크립트 내장클래스의 슈퍼클래스 
    - 자바스크립트는 클래스 기반의 언어구조적인 상속대신 프로토타입의 상속을 지원한다.
        ※ 자바에서는 언어적으로 extends 라고 선언해주면 되지요...
     - Object 클래스는 모든 내장 클래스들의 슈퍼클래스이고, 따라서 모든 클래스는
        Object 클래스의 몇개의 기본적인 프로퍼티,메서드를 상속 받는다.
 
     - 객체는 생성자 함수의 프로토타입 객체에 있는 프로퍼티들을 상속받는다.
     - 프로토타입 객체 역시 하나의 객체이므로 Object() 생성자를 사용하여 만들어진다.
           --> 프로토타입 객체도 Object,prototype의 프로퍼티를 상속받는다.  
 
     - 프로토타입의 상속은 한개의 프로토타입에 국한되지 않는다. 대신 프로토타입 객체의
        체인을 사용한다. 즉, Complex 객체는 Complex.prototype과 Object.prototype 의 프로퍼티를
        상속받는다.
 
 
* 자바스크립트 일반클래스의 서브클래스 정의하기 
     ex)
      //슈퍼클래스 정의
      //이 클래스의 서브클래스를 정의한다.
      function Rectangle(w,h){
          this.width = w ;
          this.height = h ;
      }
   
     //슈퍼클래스의 프로토타입 객체에 area 프로퍼티 정의 및 초기화
     Rectangle.prototype.area = function() {
         return this.width * this.height ;
     }
 
     //서브클래스의 생성자에서 슈퍼클래스의 생성자를 호출한다.
     //이 때, 슈퍼클래스의 생성자가 새로만든 객체의 메서드인것처럼 호출한다.  
     //생성자 체이닝            
     function subRectangle ( x , y , w , h ){
         Rectangle.call ( this , w , h ) ;
            //= subRectangle.Rectangle(w,h);
            //= subRectangle.width = w ;
            //= subRectangle.height = h ;
 
            //this 객체는 Rectangle 생성자함수가 소속되어 호출될 객체이다. (subRectangle 생성자)
            //Rectangle 생성자 함수를 this 객체의 메서드인것처럼 호출
 
                ※ call ()
                     첫번째 전달인자 : 함수가 소속되어 호출될 객체 지정
                     함수의 몸체 안에서 this 키워드의 값이 된다.
                   
                      나머지 전달인자 : 함수가 호출될때의 전달인자.
         this.x = x ;
         this.y = y ;
     }
    
     //서브클래스의 프로토타입 객체를 명시적으로 슈퍼클래스의 인스턴스로 설정한다.
     //기본 프로토 타입 객체를 사용하면 Objec 클래스의 서브클래스가 된다.
     //프로토타입 객체 역시 하나의 객체이므로 Object() 생성자를 사용하여 만들어지기 때문에.
 
     //new 연산자는 빈 객체를 생성한 후 생성된 객체의 프로토타입 객체를 설정한다.
     //이 때 생성된 객체는 자신을 만들어낸 생성자의 prototype 프로퍼티 값을
     //자신의 프로토타입객체로 설정한다.
    
     //subRectangle클래스의 프로토타입객체가 Rectangle 클래스의 인스탄스 이므로
     //subRectangle은 프로토타입 객체인 Rectangle 인스탄스의 프로퍼티를 상속받게 된다. 
    subRectangle.prototype = new Rectangle();
 
     //subRectangle.prototype 객체가 Rectangle 클래스의 인스턴스 이므로
     //subRectangle 클래스의 모든 인스턴스는 프로토타입 객체인 Rectangle 인스탄스의
     //모든 프로퍼티를 상속받게 될것이므로, 필요없는 프로퍼티는 삭제하여 준다.
    delete.subRectangle.prototype.width ;
    delete.subRectangle.prototype.height ;
    
    //subRectangle 클래스의 프로토타입 객체가 Rectangle() 생성자를 사용해서 만들어졌으므로
    //constructor 프로퍼티는 Rectangle()생성자를 참조한다.
    //constructor 프로퍼티를 수정하여 준다.
    subRectangle.prototype.constructor = subRectangle ;
   
    이제 subRectangle 클래스의 프로토타입 객체가 만들어 졌으며,
    여기에 새로운 메서드를 추가할 수 있다.
 
 //호출할때~~
   var r = new subRectangle(2,2,2,2) ;
 
   참고로, new 가 빈객체를 생성한 후 생성자 함수의 프로토타입 객체를 설정하는데
   여기서 생성자 함수의 프로토타입객체가 Rectangle 이죠~~~
   그래서 Rectangle 이 프로토타입 기반의 수퍼클래스가 된다능~~~
 
 
 
 

* 생성자 체이닝

 

    서브클래스의 생성자 함수 내에서 상위클래스의 생성자를 명시적으로 호출하는 것을

    생성자 체이닝 이라고 한다.

 

    call() 함수를 써서 생성된 객체의 메서드인것 처럼 호출했었는데 다음처럼 간단하게 고칠 수 있다.

 

    //상위클래스에 대한 참고 저장

    subRectangle.prototype.superclass = Rectangle ;

 

   function subRectangle( x , y , w ,h ){

       // 프로토타입 객체의 프로퍼티인 superclass 에 Rectangle 참조를 저장하여

       // subRectangle 클래스의 메서드화 하여 실행함.

       this.superclass (w , h) ;

       this.x = x ;

       this.y = y ;

   }

 

검색엔진을 뒤지면서 보다가 너무나 깔끔하게 정리된

자바스크립트가 있기에 퍼옴. GENERAL 님의 정리 감사합니다.

댓글은 아래 링크에 달아주시기 바랍니다.


링크 : http://blog.naver.com/minis24/80094251902


* 자바스크립트를 공부하면서 노트에 정리해 놓은 내용을 보기 편하고, 효율적으로 검색하기 위해

  블로그에 올리고 있습니다.

* 괜찮게 생각했던 내용과 메서드나,프로퍼티등의 인덱스가 있었으면 해서 정리한 거라서

   아주 기초적인 내용은 없을지도 모르겠네요. ^^ 

* 오늘은 자바스크립트 연산자와 관련된 내용입니다.

 

 

* 자바스크립트 연산자

 

    1. in

        좌변 --> 문자열 

        우변 --> 객체 or 배열

 

        좌변의 값이 우변객체의 프로퍼티의 이름이면 true 리턴

 

    2. instanceof 

        좌변 --> 객체

        우변 --> 클래스 이름

 

        좌변의 객체가 우변 클래스의 인스탄스 이면 true 리턴

 

    3. typeof 

        피연산자 앞에 쓰임, 피연산자의 데이타 타입을 가리키는 다음과 같은 문자열 리턴

      

            - 숫자 : "number"

            - 문자 : "String"

            - 불리언 : "boolean"

            - 객체 ,배열 , null  : "object"

            - 함수 : "function"

            - 정의되지 않은 피연산자  : "undefined"

            - Numberm ,String ,Boolean 등의 Wrapper 객체  : "object"

         

        피연산자를 obj 라고 하면 다음처럼 두가지 방식으로 사용하는 것이 가능하다.

             typeof obj

             typeof (obj)

       

        ※ 모든 객체와 배열 타입에 대해서 "object" 를 리턴하므로 객체를 다른 기본타입과 구분하는

            용도로 사용할 수 있다.  

 

 

    4. || 연산자  (★★★중요)

         (1) || 연산자가 불리언 피연산자에 쓰일경우 OR 연산자로 수행함

               --> 둘다 true,둘중하나 true 이면 true 리턴

        

       (2) 첫번째 피연산자(좌측)를 평가하여 true 로 변환될 수 있으면, 변환되지 않은

              원래의 좌변을 리턴(좌변의 표현식을 리턴함)

            

              만약 그 외의 경우 두번째 피연산자(우변)을 평가하여 표현식의 값을 리턴한다.

 

 

          ※ 관용적인 용법

              이연산자의 반환값이 불리언타입이 아니라는 점을 사용하여 불리언 타입이 아닌

              피연산자를 || 연산자에 사용한다.

             

              여러값중 정의 되어 있으면서 null 이 아닌 최초로 나오는 값을 택하는 방법에 많이

              쓰인다.

             

              var max = max_width || preference.max_width || 500 ;

               // max_width 가 정의 되어 있으면 사용,

               // 그외의 경우 preference 객체에 속한 값을 사용한다.

               //그것도 없으면 하드코딩된 상수 500을 사용한다.

 

    

    5. new 연산자

        - 새로운 객체를 생성하고 이를 초기화 하기 위한 생성자 함수를 호출한다.

        - 객체 생성후 지정된 생성자 함수를 호출하여 명시된 전달인자를 전달하고, 

          방금 생성된 객체도 this 키워드로 전달한다. 

  

        ※부연설명

         아무 프로퍼티도 없는 새로운 객체를 생성 한 후 생성된 객체의 프로토타입을 설정한다.

         new 연산자 뒤에 있는 함수를 호출하고 this 키워드가 새로 생성된 객체를 가리키게 한다.

         이 때 생성된 객체는 자신이 만들어낸 생성자의 프로토타입객체의 프로퍼티 값을 

         자신의 프로퍼티로 설정한다.

         이 때문에 모든 함수에는 prototype 이라는 프로퍼티가 존재한다.     

 

        ※ 생성자

            - new 연산자와 함께 사용되도록 설계된 함수라고 한다.

            - 생성자는 새로운 객체를 초기화 하고 객체에 있는 프로퍼티중에서 사용되기전에

               미리 값이 할당되어야 하는 프로퍼티들의 초기값을 할당 한다.

            - 생성자는 객체들의 클래스를 정의한다.

            - 생성자는 일반적으로 리턴 값이 없이 this 키워드가 가리키는 객체들을 초기화

              시키는 역할을 한다.

            - 생성자 함수에서 결과값으로 객체를 리턴하면, 리턴값을 가질 수 있으며, new 문장의

              결과 값이 된다. 이때, this가 가리키던 객체는 폐기 된다.

        

            - 아래 처럼 적절한 생성자 함수를 정의하는 방법으로 객체들의 클래스를 만들수 있다.

           

           function Rectangle( w , h ) {

                this.width = w ;

                this.height = h ;

 

           }

          

           var rect1 = new Rectangle( 2 , 4 ) ;

           var rect2 = new Rectangle( 5 , 3 ) ; 

 

           // rect1 = { width : 2 , height : 4 } ; 

            

    6. delete 연산자

         - 암묵적으로 선언된 변수를 삭제할 수 있다.(삭제하려고 시도한다는 표현이 맞겠네요)

         - 피연산자로 지정된 객체의 프로퍼티,배열의 원소,변수(변수도 해당하는 객체의 프로퍼티임)

            의 삭제를 시도한다.

 

         - 성공적으로 삭제하면 true 리턴

            삭제될수 없는 경우 false 리턴

         - 존재하지 않는 프로퍼티를 삭제하려고 시도하면 true 리턴

 

         ex )

         var obj = { x : 1 , y : 2 };

         delete obj.x ;                         // true

         typeof obj.x ;                         // undefined

         delete obj.x ;                         // true  (존재하지 않는 프로퍼티 삭제니까...)

         delete obj ;                           // false (var 로 선언된 변수는 삭제못함..)

         delete 3 ;                              // false (정수도 삭제 못함)

 

    7. void 연산자

        피연산자의 값을 무시하고 무조건 undefined 리턴함.

   

    8. [] 연산자

        - 배열 원소에 접근할수 있게 해준다       

            --> 숫자일 경우

        - 객체의 프로퍼티에 접근할 수 있게 해준다   

            --> 객체의 프로퍼티 이름에 해당하는 문자열로 평가되는 표현식일 경우

검색엔진을 뒤지면서 보다가 너무나 깔끔하게 정리된

자바스크립트가 있기에 퍼옴. GENERAL 님의 정리 감사합니다.

댓글은 아래 링크에 달아주시기 바랍니다. 저도 고맙게 생각하는지라.^^;;


링크 : http://blog.naver.com/minis24/80094251902


* 자바스크립트를 공부하면서 노트에 정리해 놓은 내용을 보기 편하고, 효율적으로 검색하기 위해

  블로그에 올리고 있습니다.

* 괜찮게 생각했던 내용과 메서드나,프로퍼티등의 인덱스가 있었으면 해서 정리한 거라서

   아주 기초적인 내용은 없을지도 모르겠네요. ^^ 

* 오늘은 자바스크립트 함수와 관련된 내용입니다.

 

 

* function

   - 함수 정의는 프로그램의 정적인 구조를 나타낸다.

   - 자바스크립트에서 문장은 실행시간에 실행되는 반면

      함수는 실행되기 이전의 문서 파싱단계에서 정의된다.

 

   - 자바스크립트 파서가 함수정의를 만나면 함수정의 문장들을 파싱하고 저장만 해놓는다.

  

   ex )

     alert ( f( 4 ) ) ;   // 16 출력

     var f = 0 ;        // f를 덮어쓴다.

     

     function f( x ) { return x * x ; } ;        // 함수를 정의 (문서파싱단계에서 저장되므로)

                                                         // 정의보다 앞에서 호출할 수 있다. 

     alert ( f )        // 0을 출력한다.

 

 

* Function() 생성자 

   Function()생성자를 사용해서 함수를 정의할 수 있다.

   Function()생성자는 임의 갯수의 전달인자를 전달 받는다

   Function()생성자의 마지막 문자열은 함수의 몸체 이다.

 

      --> 이름 없는 함수를 생성한다.

      --> 생성된 함수는 어휘적 유효범위를 사용하지 않는다.

            최상위 레벨의 함수인것처럼 컴파일된다.

 

   ※ 어휘적 유효범위란..

        자바스크립트가 기술된 유효범위를 말한다.

        여기서의 의미는 함수의 내부에서 정의 되었을 지라도

        최상위 레벨의 함수인것처럼 컴파일 된다는 뜻이다..

     

        ex)      

   var f = new Function("x","y","return x*y ;") ;

   이것은 아래와 같다.

   function f( x , y ){

      return x * y ;

   }

 

 

* 함수의 리터럴

    

   함수를 데이터로서 아래와 같이 다양한 방식으로 사용하는것이 가능합니다.

 

    var f = function fact(){

        if ( x <= 1 ){

           return 1;

        }else { 

           return x * fact ( x-1 );

        }

    }

 

   # 변수 f 에는 함수의 참조값을 가지고 있습니다.^^

     이때 fact 에 함수에 대한 참조를 저장하지는 않지만..

     위의 예처럼 함수의 몸체에서 자신을 참조하기 위해 식별자를 사용하는것은 허용합니다.

 

 

   # 아래의 예처럼 이름없는 함수를 정의해서 배열에 저장할 수 있습니다.  

     f[0] = function(x) {

                return x * x ;

             }

 

   # 함수를 정의하여 다른 함수에 전달할 수도 있습니다.

     a.sort( function (a,b){ return a - b ;});

 

   # 함수를 정의하여 바로 호출 하기

     var fx = (function (x) { return x ; })(10) ;

 

* 함수의 전달인자

   - 자바스크립트는 타입제약이 느슨하므로, 자신이 받기를 기대하는 전달인자의 데이타

      타입을 미리 선언하는 것이 불가능하다.

 

    - 전달 받을 수 있는 갯수는 함수를 정의할때 이름붙은 전달인자의 갯수와는 상관이 없다.

      함수정의할때는 전달인자를 선언해 줘도 좋고 안해줘도 좋고..아무런 상관이 없습니다.

      하지만 항상 넣어주는것이 정확히 선언해 주는게 보기에는 좋겠죠...

 

    - BUT 첫번째 인수를 생략하고, 두번째 인수를 전달할 수는 없으므로, 첫번째에는 적당한 인자를

      넣어줘야한다..(null 등..)

 

    - 함수 정의시 선언된 전달인자의 갯수보다 적은 수의 전달인자와 함께 호출되면 ,지정되지 않은

      남은 전달인자는 undefined 가 된다.

 

    - 호출 당시 생략되거나, null 값인 전달인자에 대해 적당한 기본값을 할당해 줘야

       에러가 발생하는것을 방지할 수 있다.

 

function copyFx ( obj ,/* option */ a) {      //option 은 주석이고, a값은 옵션이라는것 표시

    if( !a) a=[] ;                                       // a 가 정의되지 않거나 null 이면 빈배열 

    for (var property in obj ) {

       a.push( property );

    }

   

    return a ;

}

 

var a = copyFx( obj ) ;                            // a를 전달하지 않으면, obj의 모든 프로퍼티를

                                                           // 새배열에 넣는다.

copyFx ( obj ,a );

 

* 전달인자 객체 ( Arguememts 객체 프로퍼티 arguements )

    - arguements : Arguements 객체를 참조하는 특별한 프로퍼티

   

      자바스크립트 함수는 고정된 전달인자들로 정의되지만, 호출시점에서는 고정된 갯수와는

      상관없이 임의 갯수의 전달인자를 전달받을 수 있다.

 

      이 때 Arguements 객체를 통해 전달인자에 접근할 수 있다.

     

           첫번째 전달인자   --> arguements[0] 

           두번째 전달인자   --> arguements[1]

           전체 전달인자의 갯수  --> arguements.length

 

 


검색엔진을 뒤지면서 보다가 너무나 깔끔하게 정리된

자바스크립트가 있기에 퍼옴. GENERAL 님의 정리 감사합니다.

댓글은 아래 링크에 달아주시기 바랍니다. 저도 고맙게 생각하는지라.^^;;


링크 : http://blog.naver.com/minis24/80094251902


* 자바스크립트를 공부하면서 노트에 정리해 놓은 내용을 보기 편하고, 효율적으로 검색하기 위해

  블로그에 올리고 있습니다.

* 괜찮게 생각했던 내용과 메서드나,프로퍼티등의 인덱스가 있었으면 해서 정리한 거라서

   아주 기초적인 내용은 없을지도 모르겠네요. ^^ 

* 오늘은 자바스크립트 객체와 관련된 내용입니다.

 

자바스크립트 객체에 대하여 알아봅시다.

 

* 초기화 하는 방법 두가지

   1. 객체의 리터럴 (값)

        var empty = {};                                      // 빈객체

        var point = {x : 0 , y : 0};                        //point.x = 0 , point.y = 0

        var human = { "name" : "Homer",

                             "age" : 34 ,

                             "married" : true};

        

        // 프로퍼티는 식별자나 "문자열" 이 올수 있다.        

        // 객체의 리터럴은 자바스크립트 표현식으로서, 평가될때 마다 새로운 객체를

        // 생성하고 초기화 시킨다.

 

   2. new 연산자 이용  

       var a = new Array()            // 빈배열 생성

       var o = new Object()          // 빈객체 생성  

               // var o = {}     

     

* 프로퍼티의 삭제

   - delete 연산자 사용

      실제로 객체에서 프로퍼티를 완전히 제거한다.

 

* 연관 배열로서의 객체

   - 배열에서 사용되는 [] 연산자를 사용해도 객체의 프로퍼티에 접근 할 수 있다.

     즉 , object.property  와 object["property"] 는 같다.

   - 이런 형태로 객체를 사용할 때 연관배열이라고 한다.

   ※ [] 연산자안의 프로퍼티가 문자열 형태이기 때문에 런타임시에 동적으로 컨트롤 할 수 있다.

 

* 객체의 공통 메서드 및 프로퍼티

   - 모든 객체는 Object 클래스를 상속하며, 각자의 고유한 프로퍼티와 메서드가 있으며,

      Object 클래스에서 상속 받은 공통의 메서드와 프로퍼티가 있다.

     

      1. constructor 프로퍼티

           # 모든 객체는 생성자 함수를 가치키는 constructor 프로퍼티를 가지고 있다.

              ex ) Date() 생성자로 생성된 d 객체는 d.constructor 프로퍼티가 있다.

                  d.constructor 은 Date 를 가리킨다.

            

                  var d = new Date() ;

                  d.constructor == Date ;                     // true

 

           # instanceof  연산자는 constructor 프로퍼티 값을 사용한다.

                 d.constructor == Date ;                     //true

                 d instanceof Date ;                           //true

 

       2. valueOf() 메서드

            # 자바스크립트가 객체를 문자열이 아니라 숫자 같은 다른 기본타입으로 변환하려 할때

               호출된다.

            # Object 클래스가 기본제공하는 valueOf() 는 이런 변환을 수행하지 않는다.

               각 객체의 클래스에서 오버라이드 하여 사용한다.

            # 몇몇 내장 객체는 자신만의 valueOf()메서드를 정의하고 있다.

               ex) Date.valueOf();

      

        3. toString() 메서드  

          # 메서드를 호출한 객체의 값을 어떠한 방식으로든 표현하는 문자열을 만들어 리턴한다.

            # 기본 제공하는 toString() 메서드는 "[Object object]"

      

      4.hasOwnProperty() 메서드

          # 프로퍼티의 이름을 담는 한개의 문자열 인자를 받는다 객체가 이 프로퍼티를 소유하고

               있는지 검사

            ※ 프로퍼티가 지역적으로 정의되어있으면 true 리턴

            ※ 상속받은 프로퍼티 이거나, 존재하지 않으면 false 리턴         

             

             var o = {} ;

             o.hasOwnProperty("undef");                   // false(존재하지 않는 프로퍼티)

             o.hasOwnProperty("toString");                // false(상속 받은 프로퍼티)

             Math.hasOwnProperty("cos");                // true

 

       5. isPrototypeOf() 메서드

            # 이 메서드의 객체가 전달인자로 주어진 객체의 프로토 타입 객체이면 true 리턴

              그렇지 않으면 false 리턴

 

         var o = {} ;

           Object.prototype.isPrototypeOf(o)             // true

             // o.constructor == Object ;  이값이 true 이고,

             // o의 클래스는 Object 이다  new Object() == {}

       

         Function.prototype.isPrototypeOf(Object)         //true

          // Object.prototype == Function  (외우세요)

검색엔진을 뒤지면서 보다가 너무나 깔끔하게 정리된

자바스크립트가 있기에 퍼옴. GENERAL 님의 정리 감사합니다.

댓글은 아래 링크(블로그)에 달아주시기 바랍니다. 저도 고맙게 생각하는 지라


링크 : http://blog.naver.com/minis24/80094251902


* 자바스크립트를 공부하면서 노트에 정리해 놓은 내용을 보기 편하고, 효율적으로 검색하기 위해

  블로그에 올리고 있습니다.

* 괜찮게 생각했던 내용과 메서드나,프로퍼티등의 인덱스가 있었으면 해서 정리한 거라서

   아주 기초적인 내용은 없을지도 모르겠네요. ^^ 

* 오늘은 자바스크립트 변수와 관련된 내용입니다.

 

 

 

자바스크립트의 변수는 자바에서의 변수와 상당히 다르죠. 첨엔 무척 혼동이 되었는데요.

한번에 정리를 해서 보니 이해가 가더군요.

아래의 내용만 이해하면 스크립팅 할 때나, 디버깅 할때 에러의 발생지점을 아마도 잘 찾을수 있을꺼에요.....

 

 

* var 문장

   - 함수 내부에서 사용되면 해당 함수의 호출객체에 프로퍼티를 생성함으로서 변수를 정의한다.

   - 만일 함수의 몸체 내부가 아니라면 전역 객체에 프로퍼티를 생성한다.

   - var 문으로 명시적으로 생성되는 변수(프로퍼티)는 delete 연산자로 삭제할 수 없다.

      false 리턴

 

* 변수 선언의 반복과 생략

   - 선언되지 않은 변수의 값을 읽으려 하면 에러 발생

   - var 로 선언하지 않은 변수에 값을 할당하려 하면 자바스크립트가 암묵적으로 변수를 선언한다.

      이 때, 전역변수로 생성된다.(함수내에서도 마찬가지임).

 

* 함수내에서는 지역변수가 같은이름의 전역변수보다 우선한다.

     (유효범위 체인의 앞단계에 해당 변수가 없을경우, 전역객체에서 검색한다.)

 

* 변수의 값이 undefined 가 되는 두가지 경우

    - 아직 선언되지 않은 변수

        이때 변수를 읽으려 하면 런타임 에러가 발생한다.

        하지면 선언되지 않는 변수에 값을 집어넣으려 할땐 암묵적으로 전역변수로 선언된후

        값이 입력된다.

    - 선언은 되었으나 , 아직 값이 할당되지 않은 경우

         이때 변수를 읽으려 하면 변수의 초기값인 "undefined" 가 출력된다.

 

* 블록단위의 유효범위는 없다.

     for(var i = 0 ;....... ;......){

         ....

     }

     이때 i 는 for 문 밖에서도 이미 정의 되어 있다.

    

    

    - 함수에서 선언된 변수는 모두 해당 함수 전체에 걸쳐 정의되어 있다.

    

    var scope = "global"; 

    function f(){

        alert(scope) ;          // undefined  출력     

            // scope 는 함수내에서 지역변수로 선언되었다. 이경우 전역객체보다 우선하므로

            // 선언되었으나 값이 할당되지는 않았으므로 이러한 결과 출력됨.

        var scope = "local";

        alert(scope);          // "local" 출력 

   }

   f();                            // 함수 실행

 

* 전역변수와 지역변수

   - 전역 변수 :

       자바스크립트 인터프리터가 구동되면, 자바스크립트 코드를 실행하기전, 전역객체를 생성한다.

       이 전역객체의 프로퍼티는 자바스크립트 프로그램의 전역변수 들이다.

       전역변수를 선언하면 실제로는 전역객체의 프로퍼티가 된다.

     

       ※ 클라이언트측 자바스크립트에서는 Window 객체가 전역객체가 된다.

           Document 객체 --> HTML 문서

           Window 객체    --> 브라우저창 or 프레임 

 

       최상위 코드(어떤 함수에도 속하지 않는 코드)에서는 자바스크립트의 this 키워드로 전역객체를

       참조할 수 있다.

       즉 전역객체인 Window객체는 this 키워드 또는 window 프로퍼티로 접근한다.

 

  - 지역변수 :

        지역변수도 어떤 객체의 프로퍼티에 해당하며, 이 어떤 객체를 호출객체라 한다.

        자바스크립트에서는 지역변수용으로 전혀 별개의 객체를 사용하기 때문에 지역변수가

        같은 이름의 전역변수를 덮어 버리는 것을 방지한다.

 

* 자바스크립트 실행 컨텍스트

   - 자바스크립트 인터프리터는 어떤 함수를 실행할때마다, 그 함수에 대한 새로운 실행 컨텍스트를

      생성한다.

  

   - 모든 자바스크립트 함수는 각기 자신만의 고유한 컨텍스트에서 실행되며,

     이 컨텍스트에 지역변수가 정의되어 있는 호출 객체가 있다.

   

   - 최상위 코드를 실행하는 컨텍스트에서는 전역객체를 사용해서 변수를 정의한다.

  

   - 복수의 전역객체,복수의 실행컨텍스트를 허락하기도 한다.

      ex) 각각의 브라우저창,창 내부의 프레임들 마다 개별적인 전역 실행 컨텍스트가 있다.

            각각의 프레임들은 자신만의 실행 컨텍스트에서 코드를 실행하며, 자신만의 전역객체를

            가지고 있다.

   - 클라이언트측 전역객체에는 다른 전역객체를 연결하는 프로퍼티가 있다.

      ex) parent.frames[i]

           한 프레임의 자바스크립트 코드에서 다른 프레임을 참조하는 것이 가능하며,

           단일 자바스크립트 인터프리터로 서로 다른 전역 실행 컨텍스트의 스크립트를 실행하는것도

           가능하다. (동일출처정책에 위배되지 않는 범위에서 가능함)

 

   - 여러개의 창(또는 프레임) 사용하는 애플리케이션을 만들수 있으며 각창(또는 프레임)은 고유한

      window 객체를 갖는다.

      window 객체는 고유한 실행컨텍스트를 정의한다. 즉, 한 창의 전역변수는 다른창에서는

      전역변수가 아니다.

  

* 변수의 유효범위

   - 모든 자바스크립트 실행 컨텍스트에는 유효 범위 체인이란 것이 있는데 이는 객체들의 나열이다.

      자바스크립트 코드에서 scope 라는 변수의 값을 찾으려면, 우선 첫번째 객체의 프로퍼티부터

      검색한다. 첫번째 객체에 scope 라는 프로퍼티가 있으면 이 값이 쓰이게 된다.

      이 객체에 scope 라는 프로퍼티가 없으면 다음 객체로 검색이 계속된다. 

      마지막으로 전역객체에도 이 프로퍼티가 없으면, 이 변수의 값은 undefined 이다.  

 

   - 중첩되지 않은 함수라면, 유효범위 체인은 호출객체와 전역객체로 이루어지며, 호출객체에서

     프로퍼티를 검색한 후 없다면 전역객체를 검색한다.

 

   - 중첩된 함수인 경우 유효범위 체인은 여러개로 구성되며, 맨 안쪽의 중첩된 함수부터 검색하기

     시작한다.

보통 자바스크립트에서 공개적으로 노출됨으로 보안에 우려가 간다.

그래서 오픈소스 난독화를 뒤지다가 괜찮은 곳을 발견했다.



URL : http://dean.edwards.name/packer/

출처 : http://seobangnim.com/zbxe/?mid=JavaScript&page=24&document_srl=2755

자바스크립트 코드를 변태적으로 만들어주는 프로그램입니다. -_-a
파일을 바로 변환해주는 기능도 포함되어있습니다. ^^;

그럼 변태적이라는게 뭐냐….
주석제거, 불필요한 공백제거, 한줄로 만들기 와 같은 작업을 수행합니다.

/*
* HTML Element Converter 2006.09.06
*/
var Checkbox = Class({
__const : function(id) {
this._source = $(id);
this.options = Class.extend({
skinFormat  : './images/check_%s.gif' // on, off
}, arguments[1]);

이런 코드를…

var Checkbox=Class({__const:function(id){this._source=$(id);this.options=Class.extend({skinFormat:'./images/check_%s.gif'},arguments[1]);

이렇게 만드는 겁니다.
코드가 짧아서 느낌이 안오시는 분들은 필히 긴 코드로 해보시기 바랍니다.

부수적인 효과로는 “코드 판독 짜증나게 만들기”와 “소스코드 용량 줄이기”가 있습니다.
7690 bytes 의 소스를 btcode 로 변환하고 나서 5832 bytes 가 되었으니, 꽤 높은 압축률인 것 같습니다.

P.S// 필요하진 않겠지만, 같은 문법을 가진 ActionScript 에도 사용가능합니다. ^-^


http://www.crockford.com/javascript/jsmin.html

http://hometown.aol.de/_ht_a/memtronic/MemTronic_CruncherCompressor.html

http://www.phpclasses.org/browse/package/3158.html


기존에 잘 작동하던 LightBox 가 IE9 에서 오류가 발생하기 시작했다.
근데 서둘러 처리하는 바램에.. 오류화면을 캡쳐뜨지를 못했다..
검색을 해서 찾아오시는 분들께는 죄송합니다. ㅡㅡa
어쨌건..

LightBox 를 배포하는 웹사이트 에서 IE9 에 릴리즈 된 매뉴얼및 파일을 볼수 있다.



http://www.lokeshdhakar.com/projects/lightbox2/ 

이에 파일을 다운로드 받고 버전이.. 2.05 인가?
해당 디렉토리에 자바스크립트 파일을 덮어쓰면 됩니다. 대신 기존 설정은 따로 메모를 해두고
덮어쓰시길.. ^^; 
출처 : http://loudon23.blog.me/30098930034


+ Recent posts