소개
프로그래밍 세계에는 두 가지 기본 요소만 있습니다. 하나는 데이터이고 다른 하나는 코드입니다. 프로그래밍의 세계는 데이터와 코드의 뗄 수 없는 얽힘 속에서 무한한 생명력과 생명력을 보여줍니다.
데이터는 본질적으로 조용하고 항상 고유한 특성을 유지하려고 하는 반면, 코드는 본질적으로 활발하며 항상 세상을 바꾸고 싶어합니다.
아시다시피 데이터 코드의 관계는 놀랍게도 물질과 에너지의 관계와 유사합니다. 데이터에도 관성이 있습니다. 외력을 가하는 코드가 없으면 항상 원래 상태를 유지합니다. 코드는 에너지와 같습니다. 코드의 유일한 존재 목적은 데이터의 원래 상태를 변경하기 위해 열심히 노력하는 것입니다. 코드가 데이터를 변경하면 데이터의 저항으로 인해 코드의 원래 추세에도 영향을 미치거나 변경됩니다. 어떤 경우에도 데이터는 코드로 변환될 수 있고, 코드는 데이터로 변환될 수 있으며, E=MC2와 유사한 디지털 변환 방정식이 있을 수 있습니다. 그러나 컴퓨터 세계의 법칙이 항상 반영될 수 있는 것은 데이터와 코드 사이의 모순적이면서도 통일된 작동입니다. 이러한 법칙이 바로 우리가 작성하는 프로그램 논리입니다.
하지만 프로그래머마다 세계관이 다르기 때문에 이러한 데이터와 코드도 다르게 보입니다. 결과적으로, 서로 다른 세계관을 가진 프로그래머들은 자신만의 방법론을 사용하여 프로그래밍 세계의 진화와 발전을 촉진합니다.
우리 모두 알고 있듯이 오늘날 가장 인기 있는 프로그래밍 아이디어는 객체 지향 프로그래밍입니다. 객체 지향 아이디어가 프로그래밍 세계에서 빠르게 인기를 얻을 수 있는 이유는 무엇입니까? 객체지향 사고는 최초로 데이터와 코드를 하나로 묶어 프로그래머에게 단순한 객체 개념으로 제시하기 때문입니다. 이는 원래의 지저분한 알고리즘과 서브루틴, 얽혀 있던 복잡한 데이터 구조를 갑자기 명확하고 질서정연한 객체 구조로 나누어 우리 마음속의 지저분한 데이터와 코드의 매듭을 명료하게 만듭니다. 우리는 다시 한 번 더 명확한 사고를 갖고 또 다른 사고 수준에서 더 넓은 프로그래밍 세계를 탐험할 수 있습니다.
어느 날, 오조 홍인께서 '대상진경'을 설법하신 후 모든 제자들에게 말씀하셨습니다. . 장수 신수(沈秀)는 가장 높은 이해력을 지닌 형으로 인정받는다. 그의 시는 다음과 같다. 무미 건조한!" 이 구절이 나오자마자 형제들 사이에서 모두가 이 구절이 너무 잘 쓰여졌다고 말했습니다. 불머리 승려인 혜능만이 그것을 보고 조용히 한숨을 쉬며 벽에 이렇게 썼다. "물체에는 뿌리가 없고 글자도 보이지 않는다. 애초에 아무것도 없는데 어디에 먼지가 생길 수 있는가?" 그러다가 그는 고개를 저으며 걸어갔다. 혜능 게타를 읽은 사람들은 모두 “너무 엉망으로 쓰여 있어서 이해할 수 없다”고 말했다. 홍인 선사는 신수의 시를 읽고 고개를 끄덕이며 칭찬한 다음, 혜능의 시를 보고 조용히 고개를 저었습니다. 그날 밤, 홍인은 조용히 혜능을 자신의 명상실로 불러 그가 오랫동안 소중히 간직해 온 소프트웨어 경전을 가르친 뒤 달빛 아래서 하룻밤을 보내달라고 부탁했는데...
나중에 혜능은 정말 그렇지 않았다. t 스승님의 높은 기대에 부응하여 그는 남쪽에 선불교를 위한 또 하나의 광활한 하늘을 창조했습니다. Huineng이 가져간 소프트웨어 경전 중 하나는 "JavaScript Bible"이었습니다!
단순함으로 돌아가기
자바스크립트를 이해하려면 먼저 객체와 클래스의 개념을 버리고 데이터와 코드의 근원으로 돌아가야 합니다. 앞서 언급했듯이 프로그래밍 세계에는 데이터와 코드라는 두 가지 기본 요소만 있으며 이 두 요소는 서로 얽혀 있습니다. JavaScript는 데이터와 코드를 가장 원시적인 수준으로 단순화합니다.
JavaScript의 데이터는 매우 간단합니다. 단순 데이터에는 정의되지 않음, null, 부울, 숫자, 문자열의 다섯 가지 유형만 있고, 복합 데이터에는 객체라는 한 가지 유형만 있습니다. 이는 세상의 가장 기본적인 원소를 금속, 나무, 물, 불, 흙으로 분류하고, 기타 복합물질은 이 다섯 가지 기본원소로 구성되어 있다는 중국의 단순유물론과 같다.
JavaScript의 코드는 함수라는 한 가지 형태로만 반영됩니다.
참고: 위 단어는 모두 소문자이므로 숫자, 문자열, 개체, 함수 등과 같은 JavaScript 내장 함수와 혼동하지 마세요. 아시다시피 JavaScript 언어는 대소문자를 구분합니다.
모든 JavaScript 식별자, 상수, 변수 및 매개변수는 unfined, null, bool, number, string, object 및 function 유형 중 하나일 뿐입니다. typeof의 반환 값으로 표시됩니다. 이 외에 다른 유형은 없습니다.
먼저 단순 데이터 유형에 대해 이야기해 보겠습니다.
정의되지 않음: 알려지지 않은 것, 아무것도 없는 것, 상상할 수 없는 모든 것을 나타내며 코드가 이를 처리할 수 없습니다.
참고: Typeof(정의되지 않음) 반환도 정의되지 않았습니다.
어떤 변수나 속성에나 정의되지 않음을 할당할 수 있지만 이는 변수가 지워진다는 의미가 아니라 추가 속성이 추가된다는 의미입니다.
null: 개념은 있지만 아무것도 없습니다. 무 속에 유가 있는 듯하고 유 속에 무도 있는 듯하다. 상상하기 어렵지만 이미 코드로 처리할 수 있습니다.
~ 참고: typeof(null)는 객체를 반환하지만 null은 객체가 아니며 null 값을 가진 변수는 객체가 아닙니다.
부울: 예, 아니오, 의심의 여지가 없습니다. 옳은 것은 옳고, 그른 것은 그르다. 절대적으로 분명하다. 코드로 처리할 수 있고 코드의 흐름을 제어할 수도 있습니다.
수: 선형적인 것, 크기와 순서가 명확하고 수가 많지만 혼란스럽지 않습니다. 이는 코드의 일괄 처리를 용이하게 하고 코드의 반복 및 반복을 제어합니다.
참고: Typeof(nan) 및 Typeof(Infinity)는 모두 숫자를 반환합니다.
NaN이 수치 계산에 참여하는 구조는 NaN이며, NaN != NaN입니다.
무한대 / 무한대 = NaN.
문자열: 기계 신호가 아닌 인간을 위한 합리적인 것입니다. 인간-컴퓨터 정보 통신, 인간 의도에 대한 코드 이해 등이 모두 여기에 의존합니다.
단순 유형은 객체가 아니며 JavaScript는 이러한 단순 유형에 객체화 기능을 제공하지 않습니다. 단순형의 상수값이 직접 할당된 식별자, 변수, 매개변수는 객체가 아닙니다.
소위 "객관화"란 데이터와 코드를 복잡한 구조로 구성하는 능력입니다. JavaScript에서는 객체 유형과 함수 유형만 객체화 기능을 제공합니다.
수업 없음
Object는 객체의 종류입니다. JavaScript에서는 데이터와 코드가 아무리 복잡하더라도 객체 형태로 객체로 정리할 수 있습니다.
하지만 JavaScript에는 "클래스"라는 개념이 없습니다!
많은 객체 지향 프로그래머에게 이것은 아마도 JavaScript에서 가장 이해하기 어려운 것일 것입니다. 네, 거의 모든 객체지향 책에서 가장 먼저 이야기하는 것은 객체지향의 기둥인 '클래스' 개념입니다. 갑자기 "범주"가 사라지고, 우리는 영적 지원을 잃은 것처럼 느끼고 주인이 없다고 느낍니다. 객체와 클래스를 놔두고 '객체에 뿌리가 없고 유형도 보이지 않는' 상태에 도달하는 것은 쉽지 않은 것 같습니다.
먼저 JavaScript 프로그램을 살펴보겠습니다.
var life = {};
for(life.age = 1; life.age <= 3; life.age++)
{
스위치(life.age)
{
사례 1: life.body = "egg cell";
life.say = function(){alert(this.age+this.body)};
蚪";
life.say = function() {alert(this.age+this.body+"-"+this.tail+","+this.gill)};
;
life.legs = "네 다리"; Life.say = function(){alert(this.age+this.body+"-"+this.legs+","+this.lung)};
break 🎜> 이 JavaScript 프로그램은 처음에 생명 개체인 life를 생성했습니다. 생명이 탄생했을 때 그것은 어떤 속성이나 메서드도 없는 단순한 개체였습니다. 첫 번째 생명 과정에서는 "계란 세포"처럼 보이는 body 속성과 say 메서드를 갖습니다. 두 번째 생애 동안에는 "꼬리"와 "아가미"가 자랐으며, 꼬리와 아가미 특성을 보아 분명히 "올챙이"였습니다. 세 번째 생애에는 꼬리와 아가미 속성이 사라졌으나 '네 다리'와 '폐'가 자라나 다리와 폐 속성을 획득해 마침내 '개구리'가 됐다. 상상력이 풍부하다면, 그것을 잘생긴 '왕자'로 만들어 아름다운 '공주'와 결혼할 수도 있을지도 모른다. 하지만 이 프로그램을 읽은 후 다음 질문에 대해 생각해 보세요.
꼭 수업이 필요한가요?
아직도 어린 시절 동화 '엄마를 찾는 올챙이'를 기억하시나요? 아마도 어젯밤에 여러분의 아이는 우연히 이 아름다운 동화 속에서 잠이 들었을 것입니다. 귀엽고 작은 올챙이는 자신의 유형이 계속해서 진화하는 과정에서 점차 어미와 같은 '종류'가 되어 어미를 찾았습니다. 이 동화에 담긴 프로그래밍 철학은 사물의 '클래스'가 처음부터 시작되고, 계속해서 진화하고, 결국 사라지게 된다는 것입니다...
'클래스'는 실제로 우리가 복잡한 현실 세계를 이해하는 데 도움이 될 수 있습니다 , 이 혼란스러운 현실 세계는 분류될 필요가 있습니다. 하지만 우리의 생각이 '범주'에 얽매이면 '범주'는 '피곤'해집니다. 살아있는 물체에 처음부터 고정된 "클래스"가 할당되어도 여전히 진화할 수 있다고 상상해 보세요. 올챙이가 개구리로 변할 수 있나요? 또한 아이들에게 엄마를 찾는 올챙이의 이야기를 들려줄 수 있나요?
따라서 JavaScript에는 "클래스"가 없습니다. 클래스는 보이지 않고 객체와 통합되었습니다. 자바스크립트 객체가 다른 프로그래밍 언어에는 없는 생명력을 갖게 된 것은 바로 '클래스'라는 개념을 버린 덕분이다.
이 때 마음 속 깊은 곳에서 무엇인가를 느끼기 시작했다면 점차적으로 JavaScript의 Zen을 이해하기 시작한 것입니다.
JavaScript 코드에는 함수라는 한 가지 형식만 있으며, 함수는 함수 유형입니다. 어쩌면 다른 프로그래밍 언어에는 프로시저나 메소드 같은 코드 개념이 있을 수도 있지만, 자바스크립트에는 함수의 형태가 한 가지뿐입니다. 함수를 작성할 때 함수 유형의 엔터티를 만듭니다. 다음 프로그램을 살펴보세요:
function myfunc()
{
Alert("hello");
};
Alert(typeof(myfunc));
이 코드를 실행하면 typeof(myfunc)가 함수를 반환하는 것을 볼 수 있습니다. 위의 함수 작성 방법을 "정의식"이라고 합니다. 다음의 "변수식"으로 다시 작성하면 이해가 더 쉬울 것입니다.
var myfunc = function ()
{
Alert(" hello");
};
Alert(typeof(myfunc));
여기서 변수 myfunc는 명확하게 정의되고 해당 초기 값은 함수 엔터티에 할당됩니다. 따라서 typeof(myfunc)도 함수를 반환합니다. 실제로 이 두 함수의 작성 방법은 동일하며 몇 가지 사소한 차이점을 제외하면 내부 구현은 완전히 동일합니다. 즉, 우리가 작성하는 자바스크립트 함수는 그냥 변수라고 합니다. 변수 유형은 함수이고, 변수의 값은 우리가 작성한 함수 코드 본문입니다.
똑똑하다면 즉시 추가 질문을 할 수도 있습니다. 함수는 변수일 뿐이므로 변수에 값을 임의로 할당하고 어디에서나 사용할 수 있습니다???/p>
다음 코드를 살펴보세요.
var myfunc = function ()
{
Alert("hello");
};
myfunc() //처음으로 myfunc가 호출됩니다. , 출력 hello
myfunc = function ()
{
Alert("yeah");
}
myfunc(); //myfunc에 대한 두 번째 호출은 yes를 출력합니다.
이 프로그램을 실행한 결과는 다음과 같습니다. 대답은 '예'입니다! 함수가 처음 호출된 후 함수 변수에 새로운 함수 코드 본문이 할당되므로 함수가 두 번째 호출되면 다른 출력이 나타납니다.
좋습니다. 위 코드를 처음 정의된 함수 형식으로 변경해 보겠습니다.
function myfunc ()
{
Alert("hello");
};
myfunc (); //여기서 myfunc를 호출하고 hello 대신 yes를 출력합니다
function myfunc ()
{
Alert("yeah");
myfunc(); //Myfunc이 여기에서 호출되고 물론 출력도 그렇습니다.
정확히 동일한 서명을 가진 두 함수가 다른 프로그래밍 언어에서는 불법이어야 한다는 것은 당연한 일입니다. 하지만 JavaScript에서는 이것이 사실입니다. 그런데 프로그램을 실행한 후 이상한 현상이 발견되었습니다. 두 번의 호출은 마지막 함수에서 출력된 값들뿐이었습니다! 분명히 첫 번째 함수는 아무 것도 수행하지 않습니다. 왜 이런가요?
JavaScript 실행 엔진은 프로그램을 한 줄씩 분석하고 실행하는 것이 아니라, 한 줄씩 분석하고 실행하는 것으로 나타났습니다. 또한, 동일한 프로그램을 분석하고 실행하는 동안 정의하는 함수문이 먼저 추출되어 실행됩니다. 함수 정의가 실행된 후 다른 명령문 코드가 순차적으로 실행됩니다. 즉, myfunc이 처음으로 호출되기 전에 첫 번째 함수 문으로 정의된 코드 논리가 두 번째 함수 정의 문으로 덮어쓰여졌습니다. 따라서 두 호출 모두 마지막 함수 논리를 실행합니다.
예를 들어 이 JavaScript 코드를 두 부분으로 나눈다면 HTML로 작성하고 태그를 사용하여 다음과 같이 두 부분으로 나눕니다.
<script> ;<br> function myfunc ()<br> {<br> Alert("hello");<br> };<br> myfunc() //여기에서 Myfunc가 호출되고 hello가 출력됩니다<br></ script></p>
<p><script><br> function myfunc()<br> {<br> Alert("yeah");<br> }; //Myfunc가 호출됩니다. 여기에 출력 yes<br> </script>
이때 순서대로 출력이 나오는데, 이는 자바스크립트가 실제로 조각조각 실행된다는 것을 증명하기도 합니다.
코드에 정의된 함수 문이 먼저 실행됩니다. 이는 정적 언어 컴파일의 개념과 약간 비슷해 보입니다. 따라서 일부 사람들은 이 기능을 JavaScript "사전 컴파일"이라고 부르기도 합니다.
대부분의 경우 이러한 세부 사항에 얽힐 필요는 없습니다. 한 가지만 기억하면 JavaScript의 코드도 일종의 데이터이며 임의로 할당하고 수정할 수 있으며 그 값은 코드의 논리입니다. 그러나 일반 데이터와는 달리 함수를 호출하고 실행할 수 있다.
하지만 JavaScript 함수가 이 시점에서만 좋다면 C++의 함수 포인터, DELPHI의 메소드 포인터, C#의 대리자와 비교하면 얼마나 이상합니까! 그러나 JavaScript 함수의 마법은 다른 두 가지 측면에도 반영됩니다. 첫째, 함수 유형 자체도 객체화할 수 있는 능력이 있고, 둘째, 함수와 객체를 초월적으로 결합할 수 있는 능력이 있습니다.
멋진 객체
먼저 함수의 객체화 능력에 대해 이야기해 보겠습니다.
모든 함수는 해당 속성을 동적으로 추가하거나 제거할 수 있습니다. 이러한 속성은 단순 유형, 객체 또는 기타 함수일 수 있습니다. 즉, 함수는 객체의 특성을 모두 갖고 있어 함수를 객체로 사용할 수 있습니다. 실제로 함수는 객체이지만 일반 객체보다 대괄호 "()" 연산자가 하나 더 있습니다. 이 연산자는 함수의 논리를 실행하는 데 사용됩니다. 즉, 함수 자체는 계속 호출할 수 있지만 일반 객체는 완전히 동일하다는 점을 제외하면 호출할 수 없습니다. 아래 코드를 보세요:
function Sing()
{
with(arguments.callee)
Alert(author + ":" + poem);
};
Sing . 저자 = "이백";
Sing.poem = "한나라 진나라의 달은 흐르는 그림자로 첩을 비춘다. 옥관로에 가면 다시는 돌아오지 않는다. the world";
Sing();
Sing.author = "리잔";
Sing.poem = "한씨 하늘에 해가 뜨고 음산 앞에 달이 진다" . 내 딸 피파는 3천년 동안 노래를 불렀습니다.";
Sing();
이 단락에서는 Sing 함수를 정의한 후 작성자 및 시 속성을 동적으로 추가합니다. 노래 기능에. 작성자 및 시 속성을 다른 작성자 및 시로 설정하면 Sing()을 호출할 때 다른 결과가 표시됩니다. 이 예는 JavaScript 함수가 객체의 본질임을 이해하고 JavaScript 언어의 아름다움을 느낄 수 있도록 시적인 방법을 사용합니다.
위의 설명을 보면 함수 유형과 객체 유형이 동일하다는 점을 이해해야 합니다. 실제로 이러한 "객체"는 "속성"과 "메서드"를 모두 갖고 있기 때문에 이러한 방식으로 볼 수 있습니다. 그러나 다음 코드는 우리에게 새로운 의심을 줍니다.
var anObject = {}; //An object
anObject.aProperty = "Property of object"; //A property of the object
aMethod = function(){alert("Method of object")}; //객체의 메소드
//주로 다음을 살펴보세요:
Alert(anObject["aProperty"]) //처리할 수 있습니다. the object as 배열은 속성에 액세스하기 위해 속성 이름을 첨자로 사용합니다.
anObject["aMethod"]() // 객체를 배열로 사용하고 메서드 이름을 첨자로 사용하여 메서드를 호출할 수 있습니다. 🎜> for( var s in anObject) // 반복 처리를 위해 객체의 모든 속성과 메서드를 탐색합니다
Alert(s + " is a " + typeof(anObject[s]));
var aFunction = function() {}; //A 함수
aFunction.aProperty = "함수의 속성"
aFunction.aMethod = function(){alert("함수 메서드" )}; //함수 메서드
//주로 다음을 살펴보세요.
Alert(aFunction["aProperty"]) //사용할 수 있습니다. 함수를 배열로 사용하고 속성 이름을 첨자로 사용하여 속성에 액세스합니다
aFunction["aMethod"]() //함수를 배열로 사용하고 메서드 이름을 첨자로 사용하여 method
for( var s in aFunction) //반복 처리를 위해 함수의 모든 속성과 메서드를 탐색합니다.
Alert(s + " is a " + typeof(aFunction[s]));
예, 객체와 함수는 속성 이름이나 메서드 이름을 첨자로 사용하여 배열처럼 액세스하고 처리할 수 있습니다. 그렇다면 배열로 간주해야 할까요, 아니면 객체로 간주해야 할까요?
우리는 배열이 선형 데이터 구조로 간주되어야 한다는 것을 알고 있습니다. 선형 데이터 구조는 일반적으로 특정 규칙을 가지며 통합 배치 반복 작업에 적합합니다. 객체는 개별 데이터 구조로, 마치 입자처럼 분산되고 개인화된 사물을 설명하는 데 적합합니다. 그러므로 우리는 다음과 같이 질문할 수도 있습니다. JavaScript의 객체는 파동인가 입자인가?
물체양자론이 있다면 답은 파동-입자 이중성임에 틀림없습니다!
따라서 JavaScript의 함수와 객체는 객체와 배열의 특성을 모두 갖습니다. 여기서 배열은 임의로 확장할 수 있는 이름-값 쌍의 모음인 "사전"이라고 합니다. 실제로 객체와 함수의 내부 구현은 사전 구조인데, 이 사전 구조는 엄격하고 절묘한 구문을 통해 풍부한 모습을 보여줍니다. 양자 역학이 입자를 사용하여 어떤 곳에서는 문제를 설명하고 처리하고 다른 곳에서는 파동을 사용하는 것과 같습니다. 필요할 때 문제를 설명하고 처리하기 위해 객체나 배열을 자유롭게 선택할 수도 있습니다. JavaScript의 이러한 놀라운 기능을 잘 이해하는 한 간결하고 강력한 코드를 많이 작성할 수 있습니다.
오브제를 내려놓다
기능과 오브제의 초월적인 결합을 살펴보자.
객체지향 프로그래밍의 세계에서는 데이터와 코드의 유기적인 결합이 객체의 개념을 구성합니다. 객체가 생성된 이후 프로그래밍 세계는 두 부분으로 나누어졌습니다. 하나는 객체 내부 세계이고 다른 하나는 객체 외부 세계입니다. 객체는 본질적으로 이기적이며 외부 세계는 허락 없이 객체 내부에 접근할 수 없습니다. 객체는 또한 외부 세계에 속성과 메서드를 제공하고 다른 사람에게 서비스를 제공하는 측면도 있습니다. 그러나 여기서 우리는 "대상에 대한 자기 인식"이라는 흥미로운 문제에 대해 이야기해야 합니다.
뭐? 그거 들었지? 주제가 자기 인식인가?
아마도 많은 프로그래머들이 이 사실을 처음 들어보게 될 것입니다. 하지만 C++, C# 및 Java에서는 이것을 살펴보고 DELPHI에서는 self를, VB에서는 나를 살펴보세요. 아마도 갑자기 깨닫게 될 것입니다! 물론 "그 이상은 아니다"라고만 말할 수도 있다.
그러나 사물이 세계를 내부와 외부로 나눌 때 사물의 '자기'도 드러난다. "자기 인식"은 삶의 가장 기본적인 특성입니다! 프로그래밍 세계가 무한한 생명력과 생명력으로 가득 차 있는 것은 바로 객체의 강력한 생명력 때문입니다.
하지만 사물의 '자기 인식'은 우리에게 행복을 가져다줄 뿐만 아니라 고통과 고민을 안겨주기도 합니다. 우리는 사물에 너무 많은 욕망을 부여하며 항상 사물이 더 많은 일을 할 수 있기를 바랍니다. 그러나 객체의 이기심은 시스템 리소스를 놓고 서로 경쟁하게 만들고, 객체의 이기주의는 객체를 복잡하고 비대하게 만들고, 객체의 자기기만은 종종 지속적인 오류와 예외를 가져옵니다. 우리는 왜 그토록 많은 고통과 어려움을 겪고 있습니까?
그렇기 때문에 사물나무 아래에서 81일 동안 고민한 사람이 있었는데, 마침내 삶의 고통은 욕망에서 비롯되지만 욕망의 뿌리는 자각에서 나온다는 것을 깨달았다. . 그래서 그는 자신의 '자기'를 내려놓고 부처님이 되셨고, 그때부터 모든 중생을 제도하고 참된 경전을 전파하기 시작하셨습니다. 그의 이름은 석가모니이고, "자바스크립트 경"은 그가 설한 경전 중 하나입니다.
자바스크립트에도 이것이 있는데 C++, C#, Java 등의 언어에서는 이것이 다릅니다. 일반 프로그래밍 언어에서는 객체 자체이지만 JavaScript에서는 반드시 그런 것은 아닙니다! 이것은 나일 수도 있고, 당신일 수도 있고, 그 사람일 수도 있습니다. 어쨌든 당신은 내 안에 있고 나는 당신 안에 있습니다. 따라서 JavaScript에서 이 의미를 이해하기 위해 원래의 "자기"를 사용할 수는 없습니다. 그러기 위해서는 먼저 원본 대상의 '자아'를 놓아야 합니다.
다음 코드를 살펴보겠습니다.
function WhoAmI() //WhoAmI 함수 정의
{
Alert("I'm " + this.name + " of " + typeof (this));
};
WhoAmI(); //브라우저의 window 객체인 현재 코드의 전역 객체이며, name 속성은 빈 문자열입니다. 출력: 나는 반대합니다
var BillGates = {name: "Bill Gates"};
BillGates.WhoAmI = WhoAmI; //BillGates의 메서드로 WhoAmI 함수를 사용합니다.
BillGates.WhoAmI(); //지금은 빌게이츠입니다. 출력: 저는 object
의 Bill Gates입니다. var SteveJobs = {name: "Steve Jobs"};
SteveJobs.WhoAmI = WhoAmI; // SteveJobs의 메서드로 WhoAmI 함수를 사용합니다.
SteveJobs.WhoAmI(); //지금은 스티브잡스입니다. 출력: 저는 object
WhoAmI.call(BillGates)의 Steve Jobs입니다. // BillGates를 직접 사용하여 WhoAmI를 호출합니다. 출력: 저는 object
WhoAmI.call(SteveJobs)의 Bill Gates입니다. // SteveJobs를 직접 사용하여 WhoAmI를 호출합니다. 출력: 저는 object
BillGates.WhoAmI.call(SteveJobs)의 Steve Jobs입니다. //SteveJobs를 이렇게 사용하되 BillGates의 WhoAmI 메서드를 호출합니다. 출력: 저는 object
SteveJobs.WhoAmI.call(BillGates)의 Steve Jobs입니다. //BillGates를 이렇게 사용하되 SteveJobs의 WhoAmI 메서드를 호출합니다. 출력: 저는 object
WhoAmI.WhoAmI = WhoAmI의 Bill Gates입니다. //WhoAmI 함수를 자체 메서드로 설정합니다.
WhoAmI.name = "WhoAmI";
WhoAmI.WhoAmI() //이때 WhoAmI 함수 그 자체입니다. 출력: 저는 function
({name: "nobody", WhoAmI: WhoAmI}).WhoAmI()의 WhoAmI입니다. //WhoAmI 메서드를 호출하기 전에 임시로 익명 개체를 만들고 속성을 설정합니다. 출력: I'm none of object
위의 코드에서 볼 수 있듯이 동일한 함수를 다른 각도에서 호출할 수 있으며 이것이 반드시 함수 자체가 속한 객체는 아닙니다. 이것은 어떤 객체를 함수 요소와 결합할 때의 개념일 뿐입니다. 이 조합은 일반적인 객체 언어의 기본 조합보다 더 유연하고 더 분리되고 자유롭게 나타납니다.
JavaScript 함수에서는 this를 현재 제공되는 "this" 개체로만 간주할 수 있습니다. 이것은 특별한 내장 매개변수입니다. 이 매개변수에 따라 "이" 개체의 속성과 메서드에 액세스할 수 있지만 이 매개변수에 값을 할당할 수는 없습니다. 일반 객체 언어에서는 메소드 본문 코드에서 이것을 생략할 수 있으며, 기본적으로 멤버는 "self"가 먼저입니다. 하지만 자바스크립트는 "self"가 없기 때문에 "this" 객체에 접근할 때 this는 생략할 수 없습니다!
객체 스케치
우리는 많은 주제에 대해 이야기했지만 논의하지 않은 매우 기본적인 질문이 있습니다. 즉, 객체를 만드는 방법은 무엇입니까?
이전 예에서는 이미 객체 생성을 포함했습니다. 우리는 JavaScript Object Notation(약칭 JSON)이라는 형식을 사용하는데, 이는 중국어로 "JavaScript Object Notation"으로 번역됩니다.
JSON은 객체를 생성하는 매우 간단한 방법을 제공합니다. 예를 들어,
속성 없이 객체를 생성합니다.var o = {};
객체를 생성하고 속성과 초기 값을 설정합니다.
개체를 만들고 속성과 메서드를 설정합니다.
다른 개체 및 개체 배열 등을 중첩하여 더 복잡한 개체를 만듭니다.
{
name: "Microsoft",
product: "softwares",
회장: {이름: "Bill Gates", 나이: 53, 기혼: true},
직원: [{이름: "Angel", 나이: 26, 기혼: false}, {name : "Hanson", 나이: 32, Marred: true}],
readme: function() {document.write(this.name + " product " + this.product);}
};
JSON 형식은 중괄호 "{}"로 묶인 항목 목록이며, 각 항목은 쉼표 ","로 구분되며, 항목은 콜론 ":"으로 구분된 속성 이름과 속성 값입니다. 이는 전형적인 사전 표현이며 JavaScript의 객체가 사전 구조임을 다시 한 번 보여줍니다. 아무리 복잡한 객체라도 JSON 코드로 생성하고 할당할 수 있습니다.
사실 JSON은 XML보다 더 간결하고 공간을 절약하는 최고의 JavaScript 객체 형식입니다. 객체를 JSON 형태의 문자열로 활용하여 네트워크 간 정보를 자유롭게 전송하고 교환할 수 있습니다. 이 JSON 문자열을 JavaScript 개체로 변환해야 하는 경우 eval 함수의 강력한 디지털 변환 엔진만 사용하면 JavaScript 메모리 개체를 즉시 얻을 수 있습니다. 그녀가 AJAX 무대에서 눈부신 스타가 된 것은 바로 JSON의 소박하고 소박한 자연미 때문이다.
자바스크립트는 이처럼 복잡해 보이는 객체지향적인 것들을 극도로 간결한 형태로 표현하는 것이 특징입니다. 파트너의 화려하고 무거운 메이크업을 벗고, 파트너에게 맑은 눈매를 선사해보세요!
객체 생성
자, 객체를 생성하는 또 다른 방법에 대해 논의해 보겠습니다.
JSON 외에도 JavaScript에서는 함수와 결합된 new 연산자를 사용하여 객체를 생성할 수 있습니다. 예:
function MyFunc() {}; //빈 함수 정의
var anObj = new MyFunc() //new 연산자를 사용하고 MyFun 함수를 사용하여 객체 생성
JavaScript에서 객체를 생성하는 이 방법은 정말 흥미롭습니다. 이 작성 방법을 어떻게 이해해야 할까요?
실제로 위 코드는 다음과 같은 형식으로 다시 작성할 수 있습니다.
function MyFunc(){};
var anObj = {}; //객체 만들기
MyFunc 호출. (anObj); //anObj 객체를 this 포인터로 사용하여 MyFunc 함수 호출
JavaScript는 먼저 new 연산자를 사용하여 객체를 생성한 다음 이 객체를 this 매개변수로 호출합니다. 뒤에 기능. 사실 이것이 자바스크립트가 내부적으로 하는 일이고, 어떤 함수라도 이렇게 호출할 수 있습니다! 그런데 "anObj = new MyFunc()"라는 형태를 보면 또 익숙한 그림이 보입니다. 이것이 C++과 C#이 객체를 생성하는 방식이 아닐까요? 모든 길은 영산으로 통하고, 같은 목적지로 통한다는 것이 밝혀졌습니다!
이것을 보면 '왜 이 MyFunc를 생성자로 사용할 수 없지?'라고 생각할 수도 있습니다. 축하합니다. 정답을 맞췄습니다! 자바스크립트도 그렇게 생각해요! 아래 코드를 보세요:
1 function Person(name) // 매개변수가 있는 생성자
2 {
3 this.name = name; // 이 객체의 속성에 매개변수 값을 할당합니다.
4 this.SayHello = function() {alert("안녕하세요, 저는 " + this.name);}; //이 객체에 대한 SayHello 메소드를 정의합니다.
5 };
6
7 function Employee(이름, 급여) //하위 생성자
8 {
9 Person.call(this, 이름) //이를 부모 생성자에 전달합니다.
10 This.salary = 급여; //이 급여 속성을 설정합니다.
11 this.ShowMeTheMoney = function() {alert(this.name + " $" + this.salary);} //추가 ShowMeTheMoney 방법.
12 };
13
14 var BillGates = new Person("Bill Gates"); //Person 생성자를 사용하여 BillGates 객체 생성
15 var SteveJobs = new Employee("Steve Jobs ", 1234); //Empolyee 생성자를 사용하여 SteveJobs 객체를 생성합니다
16
17 BillGates.SayHello(); //표시: 저는 Bill Gates입니다
18 SteveJobs.SayHello(); / /디스플레이: 저는 Steve Jobs입니다
19 SteveJobs.ShowMeTheMoney(); //디스플레이: Steve Jobs $1234
20
21 Alert(BillGates.constructor == Person); //디스플레이: true
22 경고( SteveJobs.constructor == 직원); //표시: true
23
24 경고(BillGates.SayHello == SteveJobs.SayHello) //표시: false
이 코드는 함수가 생성자로 사용될 수 있을 뿐만 아니라 매개변수를 취할 수도 있고 객체에 멤버와 메소드를 추가할 수도 있음을 보여줍니다. 9행에서 Employee 생성자는 매개변수로 받은 this를 사용하여 Person 생성자를 호출합니다. 이는 기본 클래스 생성자를 호출하는 것과 동일합니다. 21행과 22행은 다음을 나타냅니다. BillGates는 Person에서 생성되고 SteveJobs는 Employee에서 생성됩니다. 객체의 내장 생성자 속성은 객체를 생성하는 데 사용되는 특정 함수도 지정합니다!
사실 함수를 "클래스"라고 생각한다면, 이미 "클래스"의 특성을 갖고 있기 때문에 "클래스"입니다. 그렇지 않나요? 그녀가 낳은 아들들은 모두 같은 특성을 가지고 있고 생성자도 클래스와 같은 이름을 가지고 있습니다!
하지만 이 객체를 조작하기 위해 생성자를 사용하여 생성된 각 객체에는 자체 멤버 데이터뿐만 아니라 자체 메소드 데이터도 있다는 점에 유의해야 합니다. 즉, 메서드의 코드 본문(함수 논리를 구현하는 데이터)에는 각 개체에 복사본이 있습니다. 각 코드 복사본의 논리는 동일하지만 개체는 각각 코드 본문의 복사본을 저장합니다. 위 예의 마지막 문장은 이 사실을 설명하며 JavaScript의 함수 개념을 객체로 설명합니다.
같은 클래스의 객체에 각각 메소드 코드를 갖는 것은 분명히 낭비입니다. 전통적인 객체 언어에서 메소드 함수는 JavaScript와 같은 객체 개념이 아닙니다. 함수 포인터, 메서드 포인터 또는 대리자와 같은 변형이 있더라도 본질적으로 동일한 코드에 대한 참조입니다. 일반적인 목적어 언어에서는 이런 상황이 발생하기 어렵습니다.
그러나 JavaScript 언어는 유연성이 뛰어납니다. 먼저 고유한 메소드 함수 본문을 정의하고 이 객체를 생성할 때 이 고유한 함수 객체를 메소드로 사용하여 메소드 논리를 공유할 수 있습니다. 예:
function SayHello() // 먼저 SayHello 함수 코드를 정의합니다.
{
Alert("안녕하세요, 저는 " + this.name);
};
function Person(name) //매개변수가 포함된 생성자
{
this.name = name; //이 개체의 속성에 매개변수 값 할당 www.2cto.com
this.SayHello = SayHello ; //이 개체의 SayHello 메서드에 값을 이전 SayHello 코드에 할당합니다.
};
var BillGates = new Person("Bill Gates"); //BillGates 객체 생성
var SteveJobs = new Person("Steve Jobs") //SteveJobs 객체 생성
Alert(BillGates.SayHello == SteveJobs.SayHello); //Display: true
그 중 마지막 줄의 출력은 두 객체가 함수 객체를 공유한다는 것을 보여줍니다. 이 프로그램은 메소드 코드를 공유한다는 목적을 달성했지만 그다지 우아하지는 않습니다. SayHello 메서드의 정의는 Person 클래스와의 관계를 반영하지 않기 때문입니다. "우아함"이라는 단어는 코드를 설명하는 데 사용되는데, 누가 처음 제안했는지는 알 수 없습니다. 그러나 이 단어는 프로그래머가 코드의 정확성, 효율성, 신뢰성, 가독성을 추구하는 것에서 코드의 미적 감각과 예술적 영역을 추구하는 것으로 발전했다는 것을 반영합니다.
분명히 JavaScript는 이 문제를 오랫동안 생각해 왔으며 디자이너는 이에 대한 흥미로운 프로토타입 개념을 제공했습니다.
프로토타입 살펴보기
프로토타입은 프랑스어에서 유래되었습니다. 소프트웨어 업계의 표준 번역은 "프로토타입"인데, 이는 사물의 초기 형태를 의미하며 모델과 템플릿의 의미도 포함합니다. . JavaScript의 프로토타입 개념은 이 단어의 의미를 적절하게 반영합니다. C++에서 미리 선언된 프로토타입 개념으로는 이해할 수 없습니다.
JavaScript의 모든 함수 유형 객체에는 프로토타입 속성이 있습니다. 프로토타입 속성 자체는 객체 유형의 객체이므로 이 프로토타입 객체에 임의의 속성과 메서드를 추가할 수도 있습니다. 프로토타입은 객체의 "프로토타입"이므로 이 함수로 생성된 객체는 이러한 "프로토타입" 특성을 가져야 합니다. 실제로 생성자의 프로토타입에 정의된 모든 속성과 메서드는 생성된 개체를 통해 직접 액세스하고 호출할 수 있습니다. 또한 프로토타입은 유사한 객체 그룹이 속성과 메서드를 공유할 수 있는 메커니즘을 제공한다고 말할 수도 있습니다.
먼저 다음 코드를 살펴보겠습니다.
function Person(name)
{
this.name = name; //객체 속성을 설정합니다. 각 객체에는 고유한 속성 데이터가 있습니다.
};
Person.prototype.SayHello = function() //Person 함수의 프로토타입에 SayHello 메서드를 추가합니다.
{
Alert("안녕하세요, 저는 " + this.name);
}
var BillGates = new Person("Bill Gates") //BillGates 객체 생성
var SteveJobs = new Person("Steve Jobs"); //SteveJobs 객체 생성
BillGates.SayHello(); //BillGates 객체를 통해 직접 SayHello 메서드 호출
SteveJobs.SayHello( ); //SteveJobs 객체를 통해 SayHello 메서드를 직접 호출합니다.
Alert(BillGates.SayHello == SteveJobs.SayHello) //두 객체가 프로토타입을 공유하는 SayHello이므로 다음과 같이 표시됩니다.
프로그램을 실행해본 결과, 생성자의 프로토타입에 정의된 메소드가 실제로 객체를 통해 직접 호출될 수 있고, 코드가 공유되는 것을 알 수 있습니다. 물론 메소드를 프로토타입으로 설정하는 방식이 훨씬 더 우아합니다. 호출 형식은 변경되지 않았지만 메소드와 클래스 간의 관계를 논리적으로 반영하므로 이전 작성 방식에 비해 이해하기 쉽고 정리하기 쉽습니다. 코드.
그렇다면 다중 레벨 유형의 생성자는 어떻습니까?
다음 코드를 살펴보겠습니다.
1 function Person(name) // 기본 클래스 생성자
2 {
3 this.name = name;
4 };
5
6 Person.prototype.SayHello = function() //기본 클래스 생성자의 프로토타입에 메서드 추가
7 {
8 Alert("안녕하세요, 저는 " + this.name ) ;
9 };
10 클래스 생성자
14 this.salary = 급여;
15 };
16
17 Employee.prototype = new Person(); //생성 서브클래스 프로토타입의 프로토타입인 기본 클래스 객체, 이것은 매우 흥미롭습니다
18
19 Employee.prototype.ShowMeTheMoney = function() //서브클래스에 생성자를 추가하는 프로토타입에 메소드를 추가합니다
20 {
21 alert(this.name + " $ " + this.salary);
22 };
23
24 var BillGates = new Person("Bill Gates"); 기본 클래스 Person
25의 BillGates 객체 생성 var SteveJobs = new Employee("Steve Jobs", 1234) //하위 클래스 Employee의 SteveJobs 객체 생성
26
27 BillGates.SayHello() ; //객체를 통해 직접 프로토타입 메소드 호출
28 SteveJobs.SayHello(); //하위 클래스 객체를 통해 기본 클래스의 메소드를 직접 호출, 주목하세요!
29 SteveJobs.ShowMeTheMoney(); //하위 클래스 객체를 통해 하위 클래스 프로토타입의 메서드를 직접 호출
30
31 Alert(BillGates.SayHello == SteveJobs.SayHello); 프로토타입 메서드가 공유됨을 나타냅니다.
이 코드의 17행에서는 기본 클래스 객체를 생성하고 이를 하위 클래스 생성자의 프로토타입으로 설정하는데, 이는 매우 흥미롭습니다. 28행에 대한 목적입니다. 기본 클래스 프로토타입의 메서드는 하위 클래스 개체를 통해 직접 호출할 수도 있습니다. 이것이 가능한 이유는 무엇입니까?
JavaScript 내에서 객체의 속성 및 메소드 추적 메커니즘은 소위 프로토타입 체인을 통해 구현됩니다. new 연산자를 사용하여 객체를 생성하면 생성자의 프로토타입 객체도 새로 생성된 객체에 할당되어 해당 객체의 내장 프로토타입 객체가 됩니다. 객체의 내장 프로토타입 객체는 외부 세계에 보이지 않아야 합니다. 일부 브라우저(예: Firefox)에서는 이 내장 프로토타입 객체에 액세스할 수 있지만 이는 권장되지 않습니다. 내장된 프로토타입 객체 자체도 객체이며 자신과 연관된 프로토타입 객체를 가지므로 소위 프로토타입 체인을 형성합니다.
프로토타입 체인의 마지막에는 Object 생성자의 프로토타입 속성이 가리키는 프로토타입 객체입니다. 이 프로토타입 객체는 모든 객체 중 가장 오래된 조상입니다. 이 조상은 모든 객체가 본질적으로 가지고 있어야 하는 toString과 같은 메서드를 구현합니다. Function, Boolean, String, Date 및 RegExp와 같은 다른 내장 생성자의 프로토타입은 모두 이 조상으로부터 상속되지만 각각 고유한 속성과 메서드를 정의하므로 자손이 해당 클랜의 특성을 표시합니다. 그 특성.
이게 바로 '상속'이 아닐까요? 예, 이것은 JavaScript 고유의 "프로토타입 상속"인 "상속"입니다.
'프로토타입 상속'은 친절하고 엄격합니다. 프로토타입 객체는 자신의 속성과 메서드를 어린이에게 사심 없이 제공하고 어린이가 따르도록 강요하지 않으므로 일부 장난꾸러기 어린이가 자신의 관심과 취미에 따라 독립적으로 행동할 수 있습니다. 그런 점에서 원형적 주체는 사랑하는 어머니이다. 그러나 어떤 어린이라도 자신의 길을 갈 수는 있지만 프로토타입 개체의 기존 속성을 건드릴 수는 없습니다. 왜냐하면 다른 어린이의 이익에 영향을 미칠 수 있기 때문입니다. 이런 관점에서 프로토타입 객체는 엄격한 아버지와 같습니다. 이를 이해하기 위해 다음 코드를 살펴보겠습니다.
function Person(name)
{
this.name = name;
};
Person.prototype company = "Microsoft"; //프로토타입 속성
Person.prototype.SayHello = function() //프로토타입 메서드
{
Alert("안녕하세요, 저는 " + this. name + " of " + this.company);
};
var BillGates = new Person("Bill Gates");
BillGates.SayHello(); //Things 프로토타입을 상속받기 때문에 다음으로 출력합니다. 일반적인 방식: 안녕하세요, 저는 Bill Gates입니다
var SteveJobs = new Person("Steve Jobs");
SteveJobs.company = "Apple" //자신의 회사 속성을 설정하고 프로토타입의 회사 속성
SteveJobs.SayHello = function() //나만의 SayHello 메소드 구현, 프로토타입의 SayHello 메소드 마스킹
{
Alert("Hi, " + this.name + " like " + this.company + ", 하하하 ");
};
SteveJobs.SayHello(); // 그들은 모두 자체적으로 다루는 속성과 메서드입니다. 출력: 안녕하세요, Steve Jobs like Apple, 하하하
BillGates.SayHello(); // SteveJobs의 재정의는 프로토타입 객체에 영향을 미치지 않으며 BillGates는 여전히 평소와 동일하게 출력합니다.
객체는 프로토타입 객체의 해당 속성과 메서드를 가릴 수 있습니다. 프로토타입 객체, 생성자 프로토타입 객체는 상위 수준 생성자 프로토타입 객체의 기존 속성과 메서드를 마스킹할 수도 있습니다. 이 마스킹은 실제로 객체 자체에 새로운 속성과 메서드를 생성하지만 이러한 속성과 메서드는 프로토타입 객체의 이름과 동일합니다. JavaScript는 이 간단한 마스킹 메커니즘을 사용하여 객체의 "다형성"을 달성합니다. 이는 가상 함수의 개념과 일치하며 정적 객체 언어의 재정의입니다.
하지만 정적 객체 언어보다 더 놀라운 점은 언제든지 프로토타입 객체에 새로운 속성과 메서드를 동적으로 추가할 수 있어 기본 클래스의 기능적 특징을 동적으로 확장할 수 있다는 것입니다. 이는 정적 객체 언어에서는 상상하기 어렵습니다. 다음 코드를 살펴보겠습니다.
function Person(name)
{
this.name = name;
};
Person.prototype.SayHello = function() // 객체를 생성하기 전에 정의된 메서드
{
Alert("Hello, I'm " + this.name);
};
var BillGates = new Person("Bill Gates") ; //객체 생성
BillGates.SayHello();
Person.prototype.Retire = function() //객체 생성 후 프로토타입을 동적으로 확장하는 방법
{
Alert("Poor " + this.name + ", bye bye!");
};
BillGates.Retire(); //동적으로 확장된 메소드는 이전에 즉시 호출될 수 있습니다. 생성된 객체
아미타여래, 프로토타입 상속이 실제로 이런 주문을 만들어 낼 수 있습니다!
Prototype Extension
매우 높은 수준의 이해가 있어야 합니다. 다음과 같이 생각할 수도 있습니다. Object와 같은 JavaScript 내장 함수의 프로토타입에 몇 가지 새로운 메서드와 속성을 추가하면 다음과 같습니다. 그리고 Function, JavaScript의 기능을 확장하는 것이 가능합니까?
당첨되신 것을 축하드립니다!
오늘날 AJAX 기술의 급속한 발전으로 인해 성공적인 AJAX 프로젝트의 JavaScript 런타임 라이브러리는 내장 기능의 프로토타입 기능을 크게 확장했습니다. 예를 들어, Microsoft의 ASP.NET AJAX는 이러한 내장 함수와 해당 프로토타입에 수많은 새로운 기능을 추가하여 JavaScript의 기능을 향상시킵니다.
MicrosoftAjax.debug.js에서 발췌한 코드를 살펴보겠습니다.
String.prototype.trim = function String$trim() {
if (arguments.length !== 0) throw Error.parameterCount();
return this.replace(/^s+|s+$/g, '');
}
이 코드는 내장 함수의 프로토타입을 확장합니다. String 함수 다듬기 방법이므로 모든 String 클래스 객체에는 다듬기 방법이 있습니다. 이 확장을 사용하면 나중에 문자열의 두 섹션 사이의 공백을 제거하려는 경우 더 이상 별도로 처리할 필요가 없습니다. 모든 문자열에 이 확장 함수가 있고 호출하기만 하면 되기 때문입니다. 편리한.
물론, Object의 프로토타입에 메소드를 추가하는 사람은 거의 없습니다. 아키텍처의 모든 객체에 실제로 이 메소드가 필요한 경우를 제외하고는 모든 객체에 영향을 미치기 때문입니다.
2년 전, AJAX 클래스 라이브러리 설계 초기에 마이크로소프트는 '클래스'를 시뮬레이션하기 위해 '클로저'라는 기술을 사용했습니다. 대략적인 모델은 다음과 같습니다.
function Person(firstName, lastName, age)
{
//개인 변수:
var _firstName = firstName;
var _lastName =lastName;
//공용 변수:
this.age = age; );
this.SayHello = function()
{
Alert("안녕하세요, 저는 " + firstName + " " + lastName); };
var BillGates = new Person("Bill", "Gates", 53);
var SteveJobs = new Person("Steve", "Jobs" , 53);
BillGates.SayHello();
SteveJobs.SayHello();
경보(BillGates.getName() + " " + BillGates.age);
경보(BillGates .firstName); //여기서 액세스할 수 없습니다. 프라이빗 변수로 이동
분명히 이 모델의 클래스 설명은 특히 C# 언어의 설명 형식과 유사하며, 공용 속성 및 사용 가능한 메서드는 a에 정의되어 있습니다. 순서대로 생성자를 생성하는데 이는 매우 우아합니다. 특히, "폐쇄" 메커니즘은 개인 구성원의 보호 메커니즘을 시뮬레이션할 수 있는데 이는 매우 아름답습니다.
소위 "클로저"란 생성자 본문에 다른 함수를 대상 개체의 메서드 함수로 정의하고, 이 개체의 메서드 함수는 차례로 외부 외부 함수 본문에 있는 임시 변수를 참조하는 것입니다. 이를 통해 대상 개체가 수명 동안 항상 메서드를 유지할 수 있는 한 원래 생성자 본문에서 사용된 임시 변수 값을 간접적으로 유지할 수 있습니다. 초기 생성자 호출이 종료되고 임시변수의 이름은 사라졌지만, 변수의 값은 항상 대상 객체의 메소드에서 참조할 수 있으며, 이 메소드를 통해서만 값에 접근할 수 있다. 동일한 생성자를 다시 호출하더라도 새 개체와 메서드만 생성되며 새 임시 변수는 마지막 호출과 독립적인 새 값에만 해당합니다. 정말 영리해요!
하지만 앞서 말했듯이 객체별로 메서드를 설정하는 것은 큰 낭비입니다. 또한 변수 값을 간접적으로 유지하는 메커니즘인 "클로저"는 JavaScript의 가비지 수집기에 문제를 일으키는 경우가 많습니다. 특히 객체 간에 복잡한 순환 참조가 발생할 경우 가비지 수집의 판단 논리가 매우 복잡해집니다. 공교롭게도 초기 버전의 IE 브라우저에는 JavaScript 가비지 수집 시 메모리 누수 문제가 있었습니다. 성능 테스트에서 "폐쇄" 모델의 열악한 성능과 함께 Microsoft는 결국 "폐쇄" 모델을 포기하고 "프로토타입" 모델로 전환했습니다. "얻은 것은 반드시 손실이 따른다"는 말이 있습니다.
프로토타입 모델은 객체의 멤버를 정의하기 위해 생성자가 필요하며 메서드는 생성자의 프로토타입에 첨부됩니다. 대략적인 작성은 다음과 같습니다.
//생성자 정의
function Person(name)
{
this.name = name; //생성자에서 멤버 정의
};
//메서드는 생성자의 프로토타입에 정의됩니다.
Person.prototype.SayHello = function()
{
Alert("안녕하세요, 저는 " + this.name);
} ;
//하위 클래스 생성자
function Employee(이름, 급여)
{
Person.call(this, 이름) //상위 생성자 호출
this.salary = 급여; //확장 멤버
};
//우선 하위 클래스 생성자를 사용하여 프로토타입 객체를 생성하고 상속 개념을 구현해야 합니다.
Employee .prototype = new Person () //프로토타입의 메소드만 필요하며 이 객체의 멤버는 의미가 없습니다!
//하위 클래스 메서드도 생성자에 정의됩니다.
Employee.prototype.ShowMeTheMoney = function()
{
Alert(this.name + " $" + this.salary );
};
var BillGates = new Person("Bill Gates");
BillGates.SayHello();
var SteveJobs = new Employee("Steve Jobs" , 1234 );
SteveJobs.SayHello();
SteveJobs.ShowMeTheMoney();
프로토타입 클래스 모델은 실제 개인 변수를 시뮬레이션할 수 없지만 클래스를 정의하려면 두 부분으로 나누어야 합니다. 그다지 "은혜"는 아닌 것 같습니다. 그러나 메소드는 객체 간에 공유되고 가비지 수집 문제가 발생하지 않으며 "클로저" 모델보다 더 나은 성능을 발휘합니다. "잃어버린 모든 것에는 반드시 이득이 있다"는 말이 있습니다.
프로토타입 모델에서 클래스 상속을 구현하려면 먼저 하위 클래스 생성자의 프로토타입을 상위 클래스의 객체 인스턴스로 설정해야 합니다. 이 부모 클래스 객체 인스턴스를 생성하는 목적은 상위 프로토타입 메소드를 공유하기 위한 프로토타입 체인을 형성하는 것입니다. 그러나 이 인스턴스 개체가 생성되면 상위 수준 생성자도 개체 멤버를 설정합니다. 이러한 개체 멤버는 상속에 의미가 없습니다. 생성자에 매개변수를 전달하지 않았음에도 불구하고, 값이 정의되지 않았음에도 불구하고 쓸모없는 멤버를 여럿 생성했는데, 이는 역시 낭비입니다.
아아! 세상에 완벽한 것은 없습니다!
원형의 진상
우리가 감동에 휩싸이던 그 순간, 하늘에서 붉은 빛이 번쩍였고, 상서로운 구름 속에서 관음보살이 나타났다. 나는 그녀가 옥 정화병을 들고, 녹색 버드나무 가지를 휘두르고, 꿀 몇 방울을 뿌리는 것을 보았고, 이는 즉시 JavaScript에 새로운 기운을 불어넣었습니다.
관음이 뿌린 과즙은 자바스크립트 세계에서 블록으로 응축되어 '문법 과즙'이라는 것이 되었습니다. 이 구문적 꿀은 우리가 작성하는 코드를 객체 언어처럼 보이게 만들 수 있습니다.
이 "문법적인 꿀"이 무엇인지 알고 싶다면 잘 들어보세요.
이러한 문법적 꿀팁을 이해하기 전에 JavaScript에서 객체를 구성하는 과정을 검토해야 합니다.
우리는 var anObject = new aFunction() 형식으로 객체를 생성하는 과정이 실제로 세 단계로 나눌 수 있다는 것을 이미 알고 있습니다. 첫 번째 단계는 새 객체를 생성하는 것이고, 두 번째 단계는 다음과 같습니다. 객체의 내장 프로토타입 객체를 사용합니다. 생성자 프로토타입이 참조하는 프로토타입 객체로 설정합니다. 세 번째 단계는 객체를 이 매개변수로 사용하여 생성자를 호출하여 멤버 설정과 같은 초기화 작업을 완료하는 것입니다. 객체가 생성된 후 객체에 대한 모든 액세스 및 작업은 객체 자체 및 프로토타입 체인의 객체 문자열에만 관련되며 생성자와는 아무 관련이 없습니다. 즉, 생성자는 객체 생성 시 프로토타입 객체를 도입하고 객체를 초기화하는 역할만 합니다.
그러면 우리가 직접 객체를 프로토타입으로 정의하고, 이 프로토타입에 클래스를 기술한 후, 새로 생성된 객체에 이 프로토타입을 설정하고 객체의 클래스로 취급할 수 있을까요? 새로 생성된 객체를 초기화하기 위해 이 프로토타입의 메서드를 생성자로 사용할 수 있습니까? 예를 들어, 다음과 같은 프로토타입 객체를 정의합니다:
var Person = //객체를 프로토타입 클래스로 정의
{
Create: function(name, age) //생성자로 사용됨 function
{
this.name = name;
this.age = age;
},
SayHello: function() //메소드 정의
Alert("안녕하세요, 저는 "입니다. + this.name);
},
HowOld: function() //Define method
;
}
};
이 JSON 형식은 C# 클래스처럼 작성되었습니다! 생성자와 다양한 메서드가 모두 있습니다. 어떤 형태로든 객체를 생성하고 그 객체의 내장 프로토타입을 위의 "클래스" 객체로 설정할 수 있다면, 그 클래스의 객체를 생성하는 것과 같지 않나요?
하지만 안타깝게도 객체에 내장된 프로토타입 속성에 거의 액세스할 수 없습니다! 일부 브라우저는 객체의 내장 프로토타입에 액세스할 수 있지만 그렇게 하면 사용자가 사용해야 하는 브라우저만 제한됩니다. 이것도 거의 불가능합니다.
그럼 함수 객체를 매개로 함수 객체의 프로토타입 속성을 사용해 프로토타입을 전달하고, new 연산자를 사용해 새로 생성된 객체에 전달할 수 있을까요?
실제로 다음과 같은 코드로 이 목표를 달성할 수 있습니다.
function anyfunc(){}; //함수 셸 정의 anyfunc.prototype = Person; 환승역 프로토타입
var BillGates = new anyfunc(); //새 객체의 내장 프로토타입은 우리가 기대하는 프로토타입 객체가 됩니다