프로토 타입은 무엇입니까?
기능 유형에는 속성 프로토 타입이 있으며 프로토 타입으로 직접 변환됩니다. 이 속성은 포인터로, 일부 특성과 방법을 포함하는 객체를 가리키며 현재 함수에 의해 생성 된 모든 인스턴스 (객체)가 공유합니다.
이전에 말한 내용에 따라 다음 코드를 얻을 수 있습니다.
function person () {...} person.prototype = {Country : 'China', SayName : function () {...}}먼저, 기능 유형의 인스턴스 인자가 생성되고, 그 사람의 방법 프로토 타입은 객체이며, 선언은 객체를 가리 킵니다. 이 객체의 속성과 방법은 현재 개인 함수에 의해 생성 된 인스턴스에 의해 공유됩니다. 즉, 다음과 같습니다.
person1 = 새로운 사람 (); person2 = 새로운 사람 ();
Person1과 Person2는 개인 기능 유형 인스턴스를 통해 다시 생성됩니다. 둘 다 공통 속성 국가와 메소드 SayName을 가지고 있습니다. 모두 person.prototype가 가리키는 물체를 직접 가리키는 포인터 (__proto__)가 있기 때문입니다. 그러나 __proto__ 포인터는 표준이 아닙니다. Chrome 및 Firefox와 같은 브라우저에서만 정의됩니다. 실제로이 속성은 사용되지 않지만 프로토 타입에 대한 이해로만 사용됩니다.
프로토 타입 및 기타 방법의 사용과 관련하여 나중에 더 구체적으로 이야기 할 것입니다.
객체 패턴을 만듭니다
다음으로 객체를 만드는 방법과 일반적인 패턴과 장점과 단점을 살펴 보겠습니다.
1. 공장 모델
공장과 마찬가지로 콘크리트 객체를 만드는 과정은 추상화되며 기능은 특정 인터페이스로 객체를 만드는 세부 사항을 캡슐화하는 데 사용됩니다. 부분 반복 작업 대신 기능을 사용하면 코드는 다음과 같습니다.
함수 CreatePerson (이름, 나이, 직업) {var o = new Object (); o.name = 이름; O.age = 연령; o.job = 직업; o.sayname = function () {alert (this.name); }; return o;} var person1 = CreatePerson ( "Jiangshui", "22", "Engineer");이것은 사람을 만들고 공장 패턴은 여러 유사한 객체의 반복적 인 생성 문제를 해결하지만 객체 인식 문제를 해결하지는 않습니다. 그것은 단지 객체가 단순히 생성되는 것이며,이 객체가 사람 템플릿이나 동물 템플릿에서 생성 되든이 객체의 유형을 구별하는 것은 불가능합니다.
2. 생성자 모드
사용자 정의 객체 유형의 속성 및 메소드를 정의하기 위해 사용자 정의 생성자를 만듭니다.
기능인 (이름, 나이, 직업) {this.name = 이름; this.age = age; this.job = jpb; this.sayname = function () {alert (this.name); };}; var person1 = 새로운 사람 (...);3. 생성자 모드와 공장 모드의 차이 :
사람은 기능 유형의 대상입니다. 새로운 후에는 객체가 계속 생성됩니다. 그러나 새로 생성 된이 객체는 함수에 전달 되어이 포인터에 할당되므로 전달 된 내용은 새로 생성 된 객체의 속성 또는 방법이됩니다.
생성자의 기본 습관은 첫 번째 문자에서 자본화됩니다. 위의 코드 실행은 다음 단계를 거칩니다.
이러한 방식으로 생성 된 인스턴스에서는 모두 생성자 함수를 가리키는 기본적으로 생성자 속성을 포함합니다.
경고 (person1.constructor == person);
따라서 생성자 패턴을 사용하여 유형 구분이 있으며 인스턴스는 특정 유형으로 식별 할 수 있습니다.
또한 생성자는 일반적인 기능입니다. 새로운 객체를 얻기 위해 피드백을 원하기 때문에 새로운 객체를 사용하여 호출합니다. 그렇지 않다면 직접 실행하는 것은 정상적인 기능과 같습니다. 예를 들어, 위의 person.sayName ()을 실행하면 Window.Name이 Window에서 실행되므로 Window.Name이 나타납니다.
생성자 모드도 결함이 있습니다. 생성자 모드의 메소드는 각 인스턴스에서 재현하므로 다른 인스턴스에서 동일한 이름의 함수가 같지 않습니다. 예를 들어:
person1.sayname == person2.sayname; //거짓
즉, 각 객체 인스턴스, 생성자에 의해 생성 된 속성 및 메소드는 고유하고 복사됩니다. 객체의 차이이기 때문에 속성은 고유하지만 많은 방법이 동일한 기능과 코드를 갖습니다. 여러 번 반복적으로 복사하면 분명히 자원을 낭비 할 것입니다.
따라서 함수를 외부로 놓은 다음 생성자의 포인터로 함수를 가리킬 수 있습니다. 생성 된 인스턴스 에서이 방법은 특정 함수에 대한 포인터를 저장합니다. 이는 공유 함수를 의미합니다.
기능인 (이름, 나이) {this.name = 이름; this.age = age; this.sayname = sayname;} 함수 sayname () {alert (this.name);}그러나 이러한 방식으로,이 기능은 글로벌 기능이되며, 사람 생성자와 상관 관계가 없으며 캡슐화가 없습니다.
다음으로 프로토 타입 모드로 오십시오.
프로토 타입 모드
프로토 타입에 대한 기본의 일부가 앞서 소개되었습니다. 간단히 말해서, 각 함수에는 프로토 타입 속성이있는 객체 (프로토 타입 객체)를 가리키며이 객체에 일부 속성이나 메소드를 배치 할 수 있습니다. 그런 다음이 함수에 의해 생성 된 인스턴스는 프로토 타입을 가리키는 불규칙한 속성 (__proto__)을 갖습니다.
이 관점에서 프로토 타입으로 생성 된 속성과 방법이 모든 인스턴스에서 공유된다는 것을 이해할 수 있어야합니다.
이것은 위의 생성자 모드와 예제에서 함수를 공유하는 문제를 해결합니다. 예를 들어 다음 코드 :
function person () {....} person.prototype.name = "jiangshui"; person.prototype.sayname = function () {alert (this.name); var person1 = new person (); person1.sayname (); // Jiangshui또는
person.prototype = {생성자 : 사람, 이름 : "jiangshui", sayname : function () {alert (this.name); }};두 번째 방법은 전체 프로토 타입 객체를 다루므로 생성자 특성을 수동으로 지정하고 생성자 함수를 가리키면 객체를 가리 킵니다.
그들의 관계를 정리합시다 :
isprototype ()를 사용하여 객체 간의 관계를 결정하십시오. 예를 들어:
person.prototype.isprototype (person1);
코드가 객체의 특정 속성을 읽으면 검색이 수행됩니다. 현재 객체부터 시작하여 그렇지 않은 경우 생성자를 검색하지 않고 포인터가 가리키는 프로토 타입 객체를 검색하십시오. 객체 인스턴스에 액세스 할 수 있지만 프로토 타입 객체의 값을 대체 할 수는 없습니다. 프로토 타입 객체와 동일한 이름을 가진 속성이 인스턴스에 설정된 경우 검색 프로세스는 프로토 타입 객체에 액세스하지 않고 인스턴스에서 끝나므로 덮어 쓰기의 목적이 달성됩니다. 따라서이 속성이 NULL로 설정 되더라도 재산이 이미 인스턴스에 존재하고 속성이 취소되지 않으므로 프로토 타입의 해당 속성에 액세스 할 수 있습니다.
따라서 프로토 타입을 다시 방문 할 수 있도록 인스턴스 속성을 완전히 삭제하려면 삭제 연산자를 사용해야합니다.
프로토 타입은 동적이며 프로토 타입 객체에 대한 모든 수정은 인스턴스에서 즉시 반영 될 수 있습니다. 그 이유는 인스턴스와 프로토 타입 사이의 느슨한 링크 관계 때문입니다. 인스턴스의 속성 메소드가 호출 될 때마다 쿼리가 수행됩니다. 프로토 타입이 변경되면 쿼리 결과도 변경됩니다.
프로토 타입을 이해 한 후에는 기본 객체에 새로운 방법이나 속성을 추가 할 수도 있습니다. 객체, 배열, 문자열 등과 같은 기본 참조 유형은 위의 생성자와 유사합니다. 프로토 타입을 사용하여 방법을 확장 할 수 있습니다. 예를 들어:
String.prototype.startSwith = function (text) {return this.indexof (text) == 0;}; var msg = "hello world"; msg.startswith ( "Hello");이 코드는 기본 참조 유형 문자열에 startSwith 메소드를 추가합니다. 테스트 할 문자열이 매개 변수로 시작하는지 확인하기 위해 매개 변수로 전달됩니다. 프로토 타입의 동적 특성으로 인해 문자열 유형의 모든 변수는이 방법을 실행 하여이 메소드를 얻습니다.
그러나이 방법은 권장되지 않습니다. 코드가 너무 많고 너무 많은 코드를 사용하는 경우 유지 보수 어려움, 코드 혼란 등이 발생합니다. 일반적으로 기본 참조 유형이 먼저 상속 된 다음 새로 사용자 정의 된 유형에서 생성됩니다. 상속과 관련하여 나중에 요약 할 것입니다.
프로토 타입 패턴도 전능하지 않습니다. 프로토 타입의 모든 속성과 방법은 모든 인스턴스에서 공유되므로 함수 및 기타 기능에 매우 적합하지만 참조 유형을 포함하는 속성에는 일부 충돌이 발생합니다. 예를 들어:
function person () {} person.prototype = {생성자 : 사람, 친구 : [ "greg", "jack"]}; var person1 = new person (); var person2 = new person (); person1.friends.push ( "tom"); console.log (person2.friends);콘솔에는 Person2 친구를위한 여분의 Tom이 있다는 것을 알 수 있습니다.
따라서 프로토 타입 패턴 및 생성자 패턴과 함께 사용해야합니다.
생성자 모드와 프로토 타입 모드를 조합하여 사용하십시오
이것은 가장 일반적으로 사용되는 패턴입니다. 생성자는 인스턴스 속성을 정의하고 매개 변수를 전달하여 사용자 정의하는 데 사용됩니다. 프로토 타입은 모든 인스턴스간에 공유가 필요한 방법이나 속성을 정의하는 데 사용됩니다. 이런 식으로, 사용자 정의가 이루어지고 공유가 보장되며 문제는 피합니다.
기능인 (이름, 나이, 직업) {this.name = 이름; this.age = age; this.job = job; this.friends = [ "greg", "jack"];} person.prototype = {생성자 : person, sayname : function () {alert (this.name); }}; var jiangshui = 새로운 사람 ( "jiangshui", "22", "엔지니어");실용적인 응용 프로그램 예
좋아, 여기서 당신은 프로토 타입의 것이 무엇인지, 그리고 객체를 만드는 방법을 이해할 수 있지만, 이것들의 사용은 무엇입니까? 실제로, 이전의 작업은 jQuery를 사용하여 일부 코드를 작성하는 것이었고, 캡슐화를 사용할 수 없었고 기능을 구현하기 위해 객체를 생성 할 수 없었습니다. 그러면 이들의 사용은 무엇입니까?
이 개발 방법은 주로 모듈 식 및 어셈블리 개발에 사용됩니다. 예를 들어, 자주 사용하는 팝업 기능은 물론 팝업 코드를 매번 붙여 넣고 복사 한 다음 프로젝트에서 수정하고 사용할 수 있습니다. 더 나은 선택은 팝업 기능 코드를 이러한 구성 요소로 추상적으로 캡슐화하여 팝업을 사용해야 할 때 팝업 인스턴스를 생성하기 위해 매개 변수 만 전달하면 호출 할 수 있도록하는 것입니다.
프로토 타입 객체 및 프로토 타입 체인
JavaScript에서는 모든 것이 객체이지만 객체에도 차이가 있습니다. 일반 객체 (객체)와 기능 객체 (함수)의 두 가지 범주로 대략적으로 나눌 수 있습니다.
일반적으로, 새로운 함수를 통해 생성 된 객체는 함수 객체이며 다른 객체는 일반적인 객체입니다.
예를 들어 :
함수 f1 () {// todo} var f2 = function () {// todo}; var f3 = new 함수 ( 'x', 'console.log (x)'); var o1 = {}; var o2 = new Object (); var o3 = new f1 (); console.log (f1, // 함수 유형 f2, // 함수 유형 f3, // 함수 유형 O1, // 객체 유형 O2, // 객체 유형 o3 // 객체); >> 함수 기능 객체 개체F1은 함수 선언에 속합니다. 함수를 정의하는 가장 일반적인 방법은 F2가 실제로 익명 함수라는 것입니다. 이 익명 함수를 F2에 할당하는데, 이는 함수 표현식에 속합니다. F3은 일반적이지 않지만 기능 객체이기도합니다.
기능은 JS와 함께 제공되는 객체입니다. F1과 F2가 생성되면 JS는 새로운 기능 ()을 통해 이러한 객체를 자동으로 빌드합니다. 따라서이 세 객체는 새로운 함수 ()를 통해 생성됩니다.
JavaScript에서 객체를 만들 수있는 두 가지 방법이 있습니다 : 물체 리터럴과 새로운 표현. O1과 O2의 생성은이 두 가지 방법에 해당합니다. O3에 집중합시다. Java와 C#의 아이디어를 사용하여 이해하는 경우 O3은 F1의 인스턴스 객체이고 O3 및 F1은 동일한 유형입니다. 적어도 나는 전에 그렇게 생각했지만 ...
그래서 어떻게 이해합니까? 매우 간단합니다. 새로운 기능을 통해 O3가 생성되는지 확인하십시오. 분명히. 함수 객체가 아니기 때문에 일반적인 객체입니다.
기능 객체와 일반 객체에 대한 간단한 이해를 한 후 JavaScript의 프로토 타입 및 프로토 타입 체인에 대해 알아 보겠습니다.
JS에서는 기능 객체 F1이 생성 될 때마다 프로토 타입 및 __proto__를 포함한 일부 특성이 객체에 내장되어 있으며 프로토 타입은 프로토 타입 객체이며 F1의 속성과 방법을 기록합니다.
프로토 타입은 F1에게는 보이지 않습니다. 즉, F1은 프로토 타입의 속성과 방법을 찾지 못할 것입니다.
함수 f () {} f.prototype.foo = "abc"; console.log (f.foo); //한정되지 않은그렇다면 프로토 타입의 사용은 무엇입니까? 실제로 프로토 타입의 주요 기능은 상속입니다. 평신도의 관점에서, 프로토 타입에 정의 된 특성과 방법은 모두 "후손"에 남아 있으므로 서브 클래스는 프로토 타입의 특성과 방법에 완전히 액세스 할 수 있습니다.
F1이 "후손"을위한 프로토 타입을 어떻게 남겨 두려면, 우리는 JS의 프로토 타입 체인을 이해해야합니다. 현재 JS의 __proto__가 시장에 진출했습니다. 이 사람은 매우 이상하고 숨겨져 있으므로 종종 보지 못하지만 일반적인 객체와 기능 객체 모두에 존재합니다. 그 기능은 부모 클래스의 프로토 타입 객체를 저장하는 것입니다. JS는 새로운 표현식을 통해 객체를 생성 할 때, 일반적으로 부모 클래스의 프로토 타입을 새 개체의 __proto__ 속성에 할당하여 상속의 세대를 형성합니다 ...
함수 f () {} f.prototype.foo = "abc"; var obj = new f (); console.log (obj.foo); //알파벳이제 우리는 obj의 __proto__가 f의 프로토 타입을 저장한다는 것을 알고 있습니다. 그렇다면 f의 프로토 타입의 __proto__에 무엇이 저장됩니까? 다음 그림을 참조하십시오.
그림과 같이, 객체. prototype는 f. prototype의 __proto__에 저장되며, object.prototyp 객체에 __proto__가 있습니다. 그리고 출력 결과에서 object.prototype .__ proto__는 null이며 OBJ Object Prototype 체인의 끝을 나타냅니다. 아래 그림과 같이 :
OBJ 객체에 그러한 프로토 타입 체인이 있으면 OBJ.foo가 실행될 때 OBJ는 먼저 속성이 있는지 여부를 찾을 수 있지만 자체 프로토 타입을 찾지 못할 것입니다. FOO를 찾을 수 없으면 OBJ는 프로토 타입 체인을 따라 검색합니다 ...
위의 예에서는 F의 프로토 타입에서 FOO 속성을 정의한 다음 OBJ는 프로토 타입 체인 에서이 속성을 찾아 실행합니다.