>  기사  >  웹 프론트엔드  >  자바스크립트 프로토타입 체인에서 주의할 점 정리

자바스크립트 프로토타입 체인에서 주의할 점 정리

不言
不言앞으로
2018-10-20 15:59:551601검색

이 글은 자바스크립트 프로토타입 체인에서 주의해야 할 사항을 요약한 것입니다. 참고할 만한 가치가 있으니 도움이 필요한 분들에게 도움이 되길 바랍니다.

서문: 최근 Javascript Advanced 프로그래밍을 주의 깊게 읽고 있는데, 중국어 버전의 번역이 여러 곳에 있어서 만족스럽지 못한 부분이 있어서 제가 이해하는 대로 해석하려고 노력합니다. 혹시 틀린 부분이나 누락된 부분이 있으면 지적해 주시면 정말 감사하겠습니다. 이 기사의 내용 대부분은 "JavaScript Advanced 프로그래밍, 제3판"에서 인용되었습니다. 예제에 표시된 프로토타입 체인에는 링크 하나가 누락되어 있습니다.

우리 모두는 모든 참조 유형이 기본적으로 Object를 상속한다는 것을 알고 있으며, 이 상속도 프로토타입 체인을 통해 구현됩니다. 모든 함수의 기본 프로토타입은 Object의 인스턴스입니다. 함수의 프로토타입 객체도 객체이기 때문이죠! 객체는 물론 객체의 인스턴스입니다!

따라서 함수의 프로토타입에는 Object.prototype을 가리키는 내부 포인터(__proto__)가 포함됩니다.

이것은 모든 사용자 정의 유형이 toString() 및 valueOf()와 같은 기본 메소드를 상속하는 근본적인 이유이기도 합니다.

따라서 이전 예제에 표시된 프로토타입의 프로토타입 체인에는 또 다른 상속 수준도 포함되어야 합니다.

다음 코드는 이 완전한 프로토타입 체인을 보여줍니다.

//完整原型链的伪代码
function Object() {
}
Object.prototype = {
    constructor: f Object(),
    hasOwnProperty: f hasOwnProperty(),
    isPrototypeOf: f isPrototypeOf(),
    propertyIsEnumerable: f propertyIsEnumerable(),
    toLocaleString: f toLocaleString(),
    toString: f toString(),
    valueOf: f valueOf()
}
//SuperType 父类型
function SuperType(){
    this.property = true;
}
SuperType.prototype.getSuperProperty = function() {
    console.log(this.property);
    return this.property;
}
/*
SuperType.prototype = {
    constructor: f SuperType(),
    getSuperProperty: function() {
    console.log(this.property);
    return this.property;
    }, 
    __proto__ : {
        constructor: f Object(),
        hasOwnProperty: f hasOwnProperty(),
        isPrototypeOf: f isPrototypeOf(),
        propertyIsEnumerable: f propertyIsEnumerable(),
        toLocaleString: f toLocaleString(),
        toString: f toString(),
        valueOf: f valueOf()
    }
}
*/
//SubType 子类型
function SubType() {
    this.subproperty = false;
}
//子类型 继承 父类型
SubType.prototype = new SuperType();
//实际上子类型的原型是这样的。
/*SubType.prototype = {
    property: true,
    __proto__:  {
        constructor : SuperType,
        getSuperProperty:function() {
            console.log(this.property);
            return this.property;
        }
    }
}
*/
SubType.prototype.getSubProperty = function(){
    console.log(this.subproperty);
    return this.subproperty;
}
//那么现在子类型的原型对象是这样的
/*SubType.prototype = {
    property: true,
    getSubProperty: function()  {
    console.log(this.subproperty);
    return this.subproperty;
    },
    __proto__:  {
        constructor : SuperType,
        getSuperProperty:function() {
            console.log(this.property);
            return this.property;
        }
    }
}
*/

var subInstanceObject = new SubType();
console.log(subInstanceObject.getSuperProperty()); // true

한마디로 SubType(하위 유형)은 SuperType(상위 유형)을 상속하고

SuperType(상위 유형)은 Object(상위 유형)를 상속합니다.

subInstanceObject.toString()을 호출할 때 실제로 호출되는 것은 Object.prototype에 저장된 메소드입니다.

2. 프로토타입과 인스턴스 객체 간의 관계 결정

프로토타입과 인스턴스 간의 관계는 두 가지 방법으로 결정할 수 있습니다.

첫 번째 방법은 감지된 인스턴스 객체의 프로토타입 체인에 나타난 생성자가 포함되어 있는 한, 결과가 true를 반환하는 것입니다. 이는 인스턴스 객체 생성에 모두 참여하고 있음을 보여주기 때문입니다.

console.log(subInstanceObject instanceof Object); // true
console.log(subInstanceObject instanceof SuperType); // true
console.log(subInstanceObject instanceof SubType); // true
프로토타입 체인으로 인해 subIntanceObject는 Object, SuperType 또는 SubType 중 모든 유형의 인스턴스라고 말할 수 있습니다.

두 번째 방법은 isPrototypeOf() 메서드를 사용하는 것입니다. 마찬가지로 프로토타입 체인에 나타나는 프로토타입이라면 프로토타입 체인에서 파생된 인스턴스 객체의 프로토타입이라고 할 수 있습니다.

console.log(Object.prototype.isPrototypeOf(subInstanceObject)); //true
console.log(SuperType.prototype.isPrototypeOf(subIntanceObject)); // true
console.log(SubType.prototype.isPrototypeOf(subIntanceObject)); //true

3. 메서드를 신중하게 정의하세요

하위 유형은 때때로 상위 유형의 메소드를 재정의해야 하거나 상위 유형에 추가되어야 합니다. type 존재하지 않는 메소드입니다.

하지만 무슨 일이 있어도 프로토타입에 메서드를 추가하는 코드는 프로토타입을 대체하는 명령문 뒤에 위치해야 합니다.

function SuperType() {
    this.property = true;
}

SuperType.prototype.getSuperValue = function() {
    return this.property;
}

function SubType() {
    this.subproperty = false;
}

//继承了SuperType
SubType.prototype = new SuperType();

//给原型添加方法的代码一定要放在替换原型的语句之后
//添加新方法
SubType.prototype.getSubValue = function() {
    return this.subproperty;
}

//重写 超类型中 的 方法
SubType.prototype.getSuperValue = function() {
    return false;
}

var instance = new SubType();
console.log(instance.getSuperValue())
위 코드에서는 SubType에 첫 번째 메소드 getSubValue()가 추가되었습니다.

두 번째 메소드 getSuperValue()는 프로토타입에 이미 존재하는 메소드입니다.

이 메서드를 재정의하면 하위 클래스의 프로토타입이 자체 getSuperValue() 메서드를 찾게 됩니다.

SuperType 인스턴스 객체를 통해 getSuperValue()를 호출하면 원래 메서드가 계속 호출됩니다.

이번에도 프로토타입을 SuperType의 인스턴스 객체로 교체한 후 두 가지 메서드를 정의해야 합니다.



한 가지 더 주의할 점은 프로토타입 체인을 통해 상속을 구현할 때 객체 리터럴을 사용하여 프로토타입 메서드를 생성할 수 없다는 점입니다. 그러면 프로토타입 체인이 다시 작성됩니다.

function SuperType(){
    this.property = true;
}

SuperType.prototype.getSuperValue = function(){
    return this.property;
}

function SubType(){
    this.subproperty = false;
}

//继承SuperType
SubType.prototype = new SuperType();

/* 
现在的原型
SubType.prototype = {

    property: true,
    __proto__: {
        constructor: SuperType,
        getSuperValue: function() {
            return this.property;
        }
    }
}
*/

//使用对象字面量语法会改写原型,导致上一行代码无效
// SubType.prototype = new Object();
SubType.prototype = {

    getSubValue: function() {
        return this.subproperty;
    },

    someOtherMethod: function () {
        return false;
    }

    /*,
    __proto__ : {
        constructor: fn Object(),
        .......
    }
    */

}

var instance =  new SubType();
console.log(instance.getSuperValue()); // error: instance.getSuperValue is not a function

위 코드는 SuperType 인스턴스 객체를 프로토타입에 할당한 다음 프로토타입을 객체 리터럴로 대체함으로써 발생하는 문제를 보여줍니다.

SubType의 프로토타입은 실제로 SuperType의 인스턴스 개체 대신 Object의 인스턴스를 저장하기 때문에 이 체인이 끊어졌습니다.

4. 프로토타입 체인의 문제점

프로토타입 체인은 매우 강력하고 상속을 구현하는 데 사용할 수 있지만 항상 단점이 있습니다. 모든 경우에 적용할 수 있는 단일 접근 방식은 없습니다.

주요 문제는 참조 유형 값을 포함하는 프로토타입에서 발생합니다. 참조 유형 값을 포함하는 프로토타입 속성은 모든 인스턴스 객체에서 공유됩니다.

그리고 이것이 바로 프로토타입 패턴과 생성자 패턴을 조합하여 사용하는 이유입니다.

생성자 패턴에서 속성을 정의하고 프로토타입 패턴에서 공유 메서드를 정의합니다.

프로토타입을 통해 프로토타입 상속을 구현할 때 프로토타입은 실제로 다른 유형의 인스턴스 객체가 됩니다.

원래 인스턴스 객체 속성이 현재 프로토타입 속성이 되었습니다.

function SuperType() {
    this.colors = ['red', 'green', 'blue'];
}

function SubType() {
}

// 子类型继承父类型
SubType.prototype = new SuperType();

/*
SubType.prototype = {
    colors: ['red', 'green', 'blue'],
    __proto__: {
        constructor: fn SuperType(),
        .....
    }
}
*/

var instance1 = new SubType();

instance1.colors.push('black');

console.log(instance1.colors); // ['red', 'green', 'blue', 'black']

var instance2 = new SubType();

console.log(instance2.colors); // ['red', 'green', 'blue', 'black']

프로토타입 체인의 두 번째 문제는 모든 인스턴스 객체에 영향을 주지 않고 상위 유형의 생성자에 매개변수를 전달할 방법이 없다는 것입니다.

위 두 가지 문제의 존재로 인해 프로토타입 체인은 이벤트에서 단독으로 사용되는 경우가 거의 없습니다.

위 내용은 자바스크립트 프로토타입 체인에서 주의할 점 정리의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 segmentfault.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제