>  기사  >  웹 프론트엔드  >  JavaScript 시리즈에 대한 심층적 이해 (6) 강력한 프로토타입 및 프로토타입 chain_javascript 기술

JavaScript 시리즈에 대한 심층적 이해 (6) 강력한 프로토타입 및 프로토타입 chain_javascript 기술

WBOY
WBOY원래의
2016-05-16 17:57:07830검색

서문
JavaScript는 전통적인 클래스 상속 모델을 포함하지 않고 프로토타입 프로토타입 모델을 사용합니다.

이것이 JavaScript의 단점으로 자주 언급되지만 실제로는 프로토타입 기반 상속 모델이 기존 클래스 상속보다 더 강력합니다. 전통적인 클래스 상속 모델을 구현하는 것은 쉽지만 JavaScript에서 프로토타입 상속을 구현하는 것은 훨씬 더 어렵습니다.

자바스크립트는 프로토타입 상속을 기반으로 널리 사용되는 유일한 언어이므로 두 상속 모델의 차이점을 이해하는 데는 시간이 좀 걸립니다. 오늘은 프로토타입과 프로토타입 체인에 대해 알아 보겠습니다.

프로토타입
10년 전 처음 JavaScript를 배울 때 저는 주로 다음과 같은 방식으로 코드를 작성했습니다.

코드 복사 코드는 다음과 같습니다:

vardecimalDigits = 2,
tax = 5

function add(x, y) {
return x y
}

function subtract(x, y) {
return x - y
}

//alert(add(1, 3));

각 함수를 실행하여 결과를 얻으면, 프로토타입을 학습한 후 다음과 같은 방법을 사용하여 코드를 아름답게 만들 수 있습니다.

프로토타입 사용 방법 1:
프로토타입을 사용하기 전에 코드를 약간 수정해야 합니다.
코드 복사 코드는 다음과 같습니다.

var Calculator = function (decimalDigits, Tax) {
this.decimalDigits =decimalDigits;
this.tax = Tax; >};

그런 다음 Calculator 객체의 프로토타입 속성에 객체 리터럴을 할당하여 Calculator 객체의 프로토타입을 설정합니다.

코드 복사 코드는 다음과 같습니다.
Calculator.prototype = {
add : 함수 ( x, y) {
return x y;
},

빼기: 함수 (x, y) {
return x - y; ;
//alert((new Calculator()).add(1, 3));


이런 방식으로 새 Calculator 객체 다음에 add 메서드를 호출하여 결과를 계산할 수 있습니다. .
프로토타입 사용법 2:
두 번째 방법은 프로토타입 프로토타입을 할당할 때 함수가 즉시 실행되는 표현식을 사용하는 것인데, 형식은 다음과 같습니다.

Calculator.prototype = function () { } ();
장점은 이전 게시물에서 이미 알려져 있습니다. 즉, 비공개 함수를 캡슐화하고 간단한 사용 이름을 반환 형식으로 노출하여 공개/비공개 효과를 얻을 수 있다는 것입니다.



코드 복사 코드는 다음과 같습니다. Calculator.prototype = function () {
추가 = 함수(x, y) {
x y 반환
},

빼기 = 함수(x, y) {
x - y 반환; 🎜> }
return {
더하기: 더하기,
빼기: 빼기
}
} ()

//alert((new Calculator()).add (11 , 3));


같은 방식으로 새 Calculator 개체를 만들고 나중에 add 메서드를 호출하여 결과를 계산할 수 있습니다.

한 가지 더
단계별 설명:
위의 프로토타입을 사용할 때 프로토타입 개체를 한 번에 설정하는 데 한계가 있습니다. 프로토타입은 별도로.




코드 복사
코드는 다음과 같습니다. var BaseCalculator = function () { // 각 인스턴스에 대해 10진수 선언
this.decimalDigits = 2;
};

//프로토타입을 사용하여 BaseCalculator에 대한 2개의 객체 메서드 확장
BaseCalculator.prototype.add = 함수(x, y) {
return x y;
};

BaseCalculator.prototype.subtract = 함수(x, y) {
return x - y; ;


먼저 생성자에서 BaseCalculator 객체를 선언합니다. 십진수 속성인decimalDigits가 초기화되고 프로토타입 속성을 통해 add(x,y)와 뺄셈이라는 두 함수가 설정됩니다. (x, y) 물론 위에서 언급한 두 가지 방법 중 하나를 사용할 수도 있습니다. 우리의 주요 목적은 BaseCalculator 개체를 실제 계산기의 프로토타입으로 설정하는 방법을 확인하는 것입니다.



코드 복사
코드는 다음과 같습니다. var BaseCalculator = function() { this.decimalDigits = 2; };
BaseCalculator.prototype = {
add: function(x, y) {
return x y; : 함수( x, y) {
return x - y
}
};
위 코드를 생성한 후 시작해 보겠습니다.
코드 복사 코드는 다음과 같습니다.

var Calculator = function () {
//각 인스턴스에 대한 세금 번호 선언
this.tax = 5
}

Calculator.prototype = new BaseCalculator( ) ;

Calculator가 두 가지 기능인 add(x,y)와 subtract(x,y)를 통합할 수 있도록 Calculator의 프로토타입이 BaseCalculator의 인스턴스를 가리키는 것을 볼 수 있습니다. , 그리고 한 가지 더 말해야 할 점은 프로토타입이 BaseCalculator의 인스턴스이기 때문에 얼마나 많은 Calculator 객체 인스턴스를 생성하더라도 해당 프로토타입은 동일한 인스턴스를 가리킨다는 것입니다.
코드 복사 코드는 다음과 같습니다.

var calc = new Calculator()
alert(calc.add(1, 1));
//BaseCalculator에 선언된 maximumDigits 속성은 계산기
alert(calc.decimalDigits)

에서 액세스할 수 있습니다. 위 코드를 실행하면 Calculator의 프로토타입이 BaseCalculator의 인스턴스를 가리키기 때문에 Calculator가 BaseCalculator의 생성자에 선언된 속성 값에 액세스하는 것을 원하지 않는 경우에는 해당 DecimalDigits 속성 값에 액세스할 수 있음을 알 수 있습니다. 할? 이렇게 하세요:
코드를 복사하세요 코드는 다음과 같습니다:

var Calculator = function ( ) {
this.tax= 5;
};

Calculator.prototype = BaseCalculator.prototype;

Calculator의 프로토타입에 할당 , 계산기에 있으므로 인스턴스에서 소수점 값에 액세스할 수 없습니다. 다음 코드에 액세스하면 오류가 발생합니다.
코드 복사 코드는 다음과 같습니다.

var calc = new Calculator()
alert (calc.add(1, 1));
alert(calc.decimalDigits);

프로토타입 다시 작성:
타사 JS 라이브러리를 사용할 때 그들이 정의한 프로토타입 메서드는 우리의 요구 사항을 충족할 수 없지만 이 클래스 라이브러리와 분리될 수 없으므로 현재 프로토타입에서 하나 이상의 속성이나 함수를 다시 작성해야 합니다. 추가 코드의 형식은 다음과 같습니다. 이전 추가 기능을 덮어쓰고 다시 작성합니다.
코드를 복사합니다. 코드는 다음과 같습니다.

//이전 계산기의 add() 함수 재정의
Calculator.prototype.add = function (x, y) {
return x y this.tax
}; 🎜 >var calc = new Calculator();
alert(calc.add(1, 1))


이런 식으로 계산한 결과에는 원래 값보다 세금이 하나 더 추가됩니다. 하나의 값이지만 주의할 점이 하나 있습니다. 다시 작성한 코드는 이전 코드를 덮어쓸 수 있도록 마지막에 배치해야 합니다.

프로토타입 체인
프로토타입을 연결하기 전에 먼저 코드 조각을 삽입합니다.


function Foo() {
this.value = 42
}
Foo.prototype = {
method: function() {}
};

function Bar() {}

// Bar의 프로토타입 속성을 Foo의 인스턴스 객체로 설정합니다.
Bar.prototype = new Foo(); >Bar.prototype .foo = 'Hello World';

// Bar.prototype.constructor를 Bar 자체로 수정
Bar.prototype.constructor = Bar;

var test = new Bar() / / Bar의 새 인스턴스 생성

// 프로토타입 체인
test [Bar 인스턴스]
Bar.prototype [Foo 인스턴스]
{ foo: 'Hello World ' }
Foo.prototype
{method: ...};
Object.prototype
{toString: ... /* 등 */};
위의 예에서 테스트 개체는 Bar.prototype 및 Foo.prototype에서 상속되므로 Foo의 프로토타입 메서드 메서드에 액세스할 수 있습니다. 동시에 프로토타입에 정의된 Foo 인스턴스 속성 값에 액세스할 수도 있습니다. new Bar()는 새로운 Foo 인스턴스를 생성하지 않지만 프로토타입에서 이를 재사용하므로 모든 Bar 인스턴스는 동일한 value 속성을 공유합니다.

속성 조회:
객체의 속성을 찾을 때 JavaScript는 지정된 이름의 속성을 찾을 때까지, 검색이 프로토타입 체인의 맨 위에 도달할 때까지 프로토타입 체인을 위쪽으로 순회합니다. is, Object.prototype - 그러나 지정된 속성을 여전히 찾을 수 없으면 정의되지 않음이 반환됩니다. 예를 살펴보겠습니다.
코드 복사 코드는 다음과 같습니다.

function foo() {
this.add = function (x, y) {
return x y; }

foo.prototype.add = 함수(x, y) {
return x y 10;
}

Object.prototype.subtract = 함수(x, y)
return x - y;
}

var f = new foo();
alert(f.add(1, 2)) //결과는 13이 아니라 3입니다.
alert(f.subtract(1, 2)); //결과는 -1입니다.


코드를 실행하면 뺄셈이 결과를 얻기 위해 상향 검색을 설치한다는 것을 알 수 있습니다. , 하지만 add 방법이 조금 다른 것 같아요. 제가 강조하는 점은 속성을 검색할 때 먼저 자신의 속성을 검색한다는 것입니다. 프로토타입이 없으면 프로토타입을 검색합니다. 를 사용하여 Object의 프로토타입에 삽입합니다. 따라서 특정 수준에서는 속성을 순회할 때 효율성도 문제가 됩니다.

또 한 가지 주의해야 할 점은 프로토타입에 모든 유형의 객체를 할당할 수 있지만 원자 유형 값을 할당할 수는 없다는 것입니다. 예를 들어 다음 코드는 유효하지 않습니다.


function Foo() {}
Foo.prototype = 1; 잘못된


hasOwnProperty 함수:
hasOwnProperty는 Object.prototype의 메서드입니다. hasOwnProperty가 있기 때문에 객체에 프로토타입 체인의 속성 대신 사용자 지정 속성이 포함되어 있는지 확인할 수 있습니다. 프로토타입 체인을 조회하지 않고 속성을 처리하는 유일한 함수입니다.


// Object.prototype 수정
Object.prototype .bar = 1;
var foo = {goo: 정의되지 않음};

foo.bar; // 1
'bar' // true

foo.hasOwnProperty('bar'); // false
foo.hasOwnProperty('goo'); // true


객체를 탐색할 때 hasOwnProperty만이 정확하고 예상되는 결과를 제공할 수 있습니다. 속성이 유용할 수 있습니다. 객체 자체에 정의된 속성 외에 프로토타입 체인의 속성을 제외할 수 있는 다른 방법은 없습니다.

하지만 역겨운 점이 있습니다. JavaScript는 hasOwnProperty가 불법적으로 점유되는 것을 방지하지 않으므로 객체에 이 속성이 있는 경우 올바른 결과를 얻으려면 외부 hasOwnProperty 함수를 사용해야 합니다.


var foo = {
hasOwnProperty: function() {
return false;
},
bar: 'Here be Dragons'
};

foo.hasOwnProperty('bar'); // 항상 false를 반환합니다.

// {} 객체의 hasOwnProperty를 사용하고 상단과 하단을 foo로 설정합니다
{}.hasOwnProperty.call(foo, 'bar') // true


hasOwnProperty는 객체에 속성이 존재하는지 확인할 때 사용할 수 있는 유일한 방법입니다. 동시에 for in 루프를 사용하여 객체를 탐색할 때 항상 hasOwnProperty 메서드를 사용하는 것이 좋습니다. 이렇게 하면 프로토타입 객체 확장으로 인한 간섭을 피할 수 있습니다.


// Object.prototype 수정
Object.prototype.bar = 1 ;

var foo = { moo: 2};
for(var i in foo) {
console.log(i); // bar 및 moo
}


us for in 문의 동작을 변경할 수 있는 방법이 없으므로 결과를 필터링하려면 hasOwnProperty 메소드만 사용할 수 있습니다.


코드 복사 코드는 다음과 같습니다.

// foo 변수는 위 예의 변수입니다.
for(var i in foo) {
if (foo.hasOwnProperty(i)) {
console.log(i );
}
}

이 버전의 코드가 코드를 작성하는 유일한 올바른 방법입니다. hasOwnProperty를 사용했기 때문에 이번에는 moo만 출력됩니다. hasOwnProperty를 사용하지 않으면 기본 객체 프로토타입(예: Object.prototype)이 확장될 때 이 코드가 중단될 수 있습니다.

요약: hasOwnProperty를 사용하는 것이 좋습니다. 코드가 실행되는 환경에 대해 어떠한 가정도 하지 않으며, 네이티브 객체가 확장되었는지 여부도 가정하지 않습니다.

요약
프로토타입은 개발 코드를 크게 풍부하게 해주었지만, 일상적인 사용 중에 위에서 언급한 몇 가지 주의 사항에 주의를 기울여야 합니다.
성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.