이 글에서는 JS 상속(프로토타입 체인, 생성자, 조합, 프로토타입, 기생, 기생 조합, 클래스 확장)에 대한 자세한 소개를 공유합니다. 이는 특정 참조 값을 갖고 있으며 도움이 필요한 친구들이 한 번 참조할 수 있습니다.
솔직히 예전에는 "기생 조합 상속"이 최고라는 것만 알면 됐고, 그것을 사용하려면 조상 코드 템플릿만 필요했습니다. 최근 몇 주 동안 몇 가지 사항을 정리하려고 생각하고 있었습니다. 이 글은 "JavaScript Advanced 프로그래밍"의 내용을 뼈대로 하고, ES6 클래스의 관련 내용을 보완하며, 누구나 쉽게 이해할 수 있는 관점에서 상속을 설명하고 있습니다.
먼저 전체적인 인상을 말씀드리겠습니다. 그림과 같이 JS에서의 상속은 객체 함수의 사용 여부에 따라 두 부분으로 나눌 수 있습니다(아래에서 언급). (Object.create는 이 함수를 표준화하기 위한 ES5의 새로운 메소드입니다.)
그 중에서 프로토타입 체인 상속과 프로토타입 상속은 장점과 단점이 동일하며, 생성자 상속과 기생 상속도 서로 대응됩니다. 기생 조합 상속은 Object.create를 기반으로 함과 동시에 조합 상속을 최적화하여 완벽한 상속 방법이 됩니다. ES6 클래스 확장의 결과는 기본적으로 기생 조합 상속과 동일하지만 구현이 약간 다릅니다.
바로 본론으로 들어가겠습니다.
위 그림 상단의 프로토타입 체인 상속, 생성자 상속, 조합 상속은 인터넷에 내용이 많아서 자세히 설명하지는 않습니다. 핵심만 지적합니다. 가장 이해하기 쉬운 글은 "JS에서의 상속(1부)"입니다. 전반부의 내용이 익숙하지 않은 경우 먼저 이 기사를 읽고 다시 돌아와서 계속 읽으면 됩니다. 이미 익숙하다면 이 부분을 빠르게 건너뛰어도 됩니다. 또한 섹션의 전반부는 yq 프런트 엔드의 상속된 기사에서 많은 부분을 차용했습니다[1].
핵심: 상위 클래스의 인스턴스를 하위 클래스의 프로토타입으로 사용
SubType.prototype = new SuperType() // 所有涉及到原型链继承的继承方式都要修改子类构造函数的指向,否则子类实例的构造函数会指向SuperType。 SubType.prototype.constructor = SubType;
장점: 상위 클래스 메소드를 재사용할 수 있음
단점:
상위 클래스의 참조 속성이 공유됩니다. 모든 하위 클래스 인스턴스에 따라
하위 클래스는 인스턴스를 생성할 때 상위 클래스에 매개 변수를 전달할 수 없습니다
Core: 상위 클래스 생성자의 내용이 하위 클래스 생성자에 복사됩니다. 이는 프로토타입을 포함하지 않는 모든 상속 중에서 유일한 상속입니다.
SuperType.call(SubType);
장점: 프로토타입 체인 상속과 완전히 반대입니다.
부모 클래스의 참조 속성은 공유되지 않습니다
하위 클래스는 인스턴스를 빌드할 때 부모 클래스에 매개 변수를 전달할 수 있습니다.
단점: 부모 클래스의 메서드는 재사용할 수 없으며 서브클래스 인스턴스의 메소드는 별도로 생성될 때마다 변경됩니다.
Core: 프로토타입 상속과 생성자 상속의 조합은 두 가지의 장점을 결합합니다.
function SuperType() { this.name = 'parent'; this.arr = [1, 2, 3]; } SuperType.prototype.say = function() { console.log('this is parent') } function SubType() { SuperType.call(this) // 第二次调用SuperType } SubType.prototype = new SuperType() // 第一次调用SuperType
장점:
부모 클래스의 메서드를 재사용할 수 있습니다.
부모 클래스의 참조 속성은 공유되지 않습니다.
하위 클래스는 인스턴스를 빌드할 때 부모 클래스에 매개 변수를 전달할 수 있습니다.
단점:
부모 클래스의 생성자는 처음으로 부모 클래스의 name 및 arr 속성을 하위 클래스의 프로토타입에 추가합니다. 따라서 하위 클래스 프로토타입에서 동일한 이름을 가진 매개변수를 재정의합니다. 이러한 덮어쓰기 상황은 성능 낭비를 초래합니다.
Core: 프로토타입 상속의 객체 방법은 본질적으로 매개변수 객체의 얕은 복사본입니다.
장점: 상위 클래스 메서드를 재사용할 수 있음
단점:
상위 클래스의 참조 속성은 모든 하위 클래스 인스턴스에서 공유됩니다.
하위 클래스는 인스턴스를 빌드할 때 상위 클래스에 매개 변수를 전달할 수 없습니다
function object(o){ function F(){} F.prototype = o; return new F(); } var person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"] }; var anotherPerson = object(person); anotherPerson.name = "Greg"; anotherPerson.friends.push("Rob"); var yetAnotherPerson = object(person); yetAnotherPerson.name = "Linda"; yetAnotherPerson.friends.push("Barbie"); alert(person.friends); //"Shelby,Court,Van,Rob,Barbie"
ECMAScript 5 프로토타입 상속이 새로운 Object.create() 메서드로 표준화되었습니다. 이 메서드는 두 가지 매개 변수, 즉 새 개체의 프로토타입으로 사용할 개체와 (선택적으로) 새 개체에 대한 추가 속성을 정의하는 개체를 허용합니다. Object.create() 메서드는 하나의 매개 변수가 전달될 때 object() 메서드와 동일하게 동작합니다. ——"JAVASCript 고급 프로그래밍"
그래서 위의 코드는 다음과 같이 변환될 수 있습니다.
var yetAnotherPerson = object(person); => var yetAnotherPerson = Object.create(person);
핵심: 프로토타입 상속을 사용하여 대상 개체의 얕은 복사본을 얻은 다음 이 얕은 복사본의 기능을 향상시킵니다.
장점과 단점: 단 하나의 아이디어만 제공하고 장점은 없습니다
function createAnother(original){ var clone=object(original); //通过调用函数创建一个新对象 clone.sayHi = function(){ //以某种方式来增强这个对象 alert("hi"); }; return clone; //返回这个对象 } var person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"] }; var anotherPerson = createAnother(person); anotherPerson.sayHi(); //"hi"
조합 상속에는 부모 클래스의 생성자를 두 번 호출해야 하는 단점이 있으므로 기생 조합 상속이 이 문제를 해결할 수 있다고 방금 언급했습니다. .
function inheritPrototype(subType, superType){ var prototype = object(superType.prototype); // 创建了父类原型的浅复制 prototype.constructor = subType; // 修正原型的构造函数 subType.prototype = prototype; // 将子类的原型替换为这个原型 } function SuperType(name){ this.name = name; this.colors = ["red", "blue", "green"]; } SuperType.prototype.sayName = function(){ alert(this.name); }; function SubType(name, age){ SuperType.call(this, name); this.age = age; } // 核心:因为是对父类原型的复制,所以不包含父类的构造函数,也就不会调用两次父类的构造函数造成浪费 inheritPrototype(SubType, SuperType); SubType.prototype.sayAge = function(){ alert(this.age); }
장점과 단점: 이것은 완벽한 상속 방법입니다.
Core: ES6 상속의 결과는 본질적으로 기생 조합 상속과 유사합니다. 그러나 기생 결합 상속은 먼저 하위 클래스 인스턴스의 this 객체를 생성한 다음 이를 향상시키는 반면 ES6은 먼저 부모 클래스 인스턴스 객체의 속성과 메서드를 this에 추가한 다음(그래서 super 메서드를 먼저 호출해야 함) 하위 클래스 인스턴스 객체를 클래스의 생성자가 수정합니다.
class A {} class B extends A { constructor() { super(); } }
ES6의 구체적인 상속 원칙:
class A { } class B { } Object.setPrototypeOf = function (obj, proto) { obj.__proto__ = proto; return obj; } // B 的实例继承 A 的实例 Object.setPrototypeOf(B.prototype, A.prototype); // B 继承 A 的静态属性 Object.setPrototypeOf(B, A);
ES6继承与ES5继承的异同:
相同点:本质上ES6继承是ES5继承的语法糖
不同点:
ES6继承中子类的构造函数的原型链指向父类的构造函数,ES5中使用的是构造函数复制,没有原型链指向。
ES6子类实例的构建,基于父类实例,ES5中不是。
ES6 Class extends是ES5继承的语法糖
JS的继承除了构造函数继承之外都基于原型链构建的
可以用寄生组合继承实现ES6 Class extends,但是还是会有细微的差别
相关推荐:
AngularJs自定义指令可以如何来设置以及自定义指令的命名规范
위 내용은 JS 상속에 대한 자세한 소개(프로토타입 체인, 생성자, 조합, 프로토타입, 기생, 기생 조합, 클래스 확장)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!