구조 함수 원형의 계승 방식 분석

8629 단어

1. 원형 체인을 통해 계승

function ExpOne(age) {
    this.age = age || 20;
    this.nameArr = [ 'Tom', 'Cat' ];
}
ExpOne.prototype.say = function() {
    console.log(this.age);
    console.log(this.nameArr);
};
let expOne = new ExpOne(18);
expOne.say(); //18, [ 'Tom', 'Cat' ]

function ExpOne_exp() {}
ExpOne_exp.prototype = new ExpOne();
ExpOne_exp.prototype.eat = function() {
    console.log('eat');
};

//  ExpOne_expOne
let ExpOne_expOne = new ExpOne_exp(30); // 
ExpOne_expOne.say(); //20, [ 'Tom', 'Cat' ]
ExpOne_expOne.eat(); //eat

ExpOne_expOne.age = 100;
// ExpOne_expOne 
ExpOne_expOne.nameArr.push('Jolin');
ExpOne_expOne.say(); //100, [ 'Tom', 'Cat','jolin' ]

// ExpOne_expTwo
let ExpOne_expTwo = new ExpOne_exp();
ExpOne_expTwo.say(); // 20, [ 'Tom', 'Cat','jolin' ] // ExpOne_expTwo 

expOne.nameArr.push('Jolin2');
expOne.say(); //18, [ 'Tom', 'Cat','Jolin2' ]

ExpOne_expTwo.say(); // 20, [ 'Tom', 'Cat','jolin' ]
ExpOne_exp.prototype.say = function() {
    console.log(' ExpOne say');
};
ExpOne_expTwo.say(); // ExpOne say
ExpOne_expOne.say(); // ExpOne say
console.log(ExpOne_exp.prototype.constructor === ExpOne); //true   ExpOne_exp.prototype.constructor = ExpOne_exp

원형 체인을 통해 계승을 실현하는 원리와 단점: 원형 체인 계승 방안에서 원형은 실제로 다른 유형의 실례로 변한다. ExpOne_exp.prototype는 ExpOne의 실례가 되었기 때문에 ExpOne의 실례 속성nameArr는 ExpOne_exp.prototype의 속성, 원형 속성의 인용 형식 값은 ExpOne_exp는 모든 실례를 공유하기 때문에 여러 실례가 인용 형식에 대한 조작을 변경합니다.단점: 1.하위 형식 실례를 만들 때 부모 형식의 구조 함수에 전달할 수 없습니다.2. 하위 유형 여러 개의 실례는 인용 유형의 조작이 왜곡될 위험이 있다.3. 하위 형식의 원형에 있는constructor 속성이 다시 작성되었습니다.원형 체인 계승을 바탕으로 하는 문제를 바로잡아야 한다. 원형 체인 계승은 일반적으로 추천되지 않는 계승 방식이다.

2. 구조 함수를 빌려 이루어진 계승(경전 계승)


원형 체인의 계승을 바탕으로 존재하는 전참 불가와 원형의 인용 유형 데이터는 여러 실례를 공유하고 사용할 때 왜곡되는 문제가 발생하고 구조 함수를 빌려 실현하는 계승 방안이 생겼다.
// 
function Anmail(age) {
    this.age = age || 2;
    this.nameArr = [ 'tom', 'cat' ];
}
// 
Anmail.prototype.run = function() {
    console.log('i am running');
};

let AnmailOne = new Anmail();
AnmailOne.run();

//  Cat  
function Cat(age) {
    Anmail.call(this, age);
}
let catOne = new Cat(3);
catOne.nameArr.push('linlin');
console.log(catOne); //{ age: 3, nameArr: [ 'tom', 'cat','linlin' ] }

let catTwo = new Cat(4);
console.log(catTwo); //{ age: 4, nameArr: [ 'tom', 'cat' ] }
//catOne.run(); //   TypeError: catOne.run is not a function

Cat.prototype.run = function() {
    console.log(' Cat ');
};
catTwo.run(); // Cat 

경전 계승의 원리와 한계성은 부류의 함수를 자류의 구조 함수에서 호출하여 모든 실례에서 집행한다. 이렇게 하면 모든 실례에 Anmail의 속성 방법의 사본이 있고 Anmail을 계승할 수 있다.이런 방식의 장점은 하위 유형 구조 함수에서 부 유형 구조 함수에 파라미터를 전달할 수 있고 원형 체인이 여러 실례를 계승하여 구조 함수 인용 유형 데이터의 변경 문제를 해결할 수 있다는 것이다.문제는 부모 유형의 원형에서 정의된 방법은 하위 유형과 하위 클래스가 만든 실례에 대해 보이지 않기 때문에 방법을 구조 함수에서만 정의할 수 있고 방법은 구조 함수에서 정의되며 매번 실례를 만들 때마다 방법을 한 번 만들 수 있다.이런 고전적인 상속 방안도 통상적으로 추천되지 않는 상속 방식이다.

3. js가 계승한 그룹 계승

// 
function Person(age, name) {
    this.age = age;
    this.name = name;
    this.arr = [ 1, 2 ];
}
Person.prototype.say = function() {
    console.log(this.age, this.name, this.arr);
};
let p1 = new Person(18, 'tom');
console.log(p1); //{ age: 18, name: 'tom', arr: [ 1, 2 ] }

//   Person 

function Man(age, name, sex) {
    Person.call(this, age, name);
    this.sex = sex;
}
// prototype 
Man.prototype = new Person();
// Man constructor
console.log(Man.prototype.constructor === Person);
Man.prototype.constructor = Man;

let man1 = new Man(10, 'Tom', 'male');
console.log(man1);
man1.say();

이를 통해 알 수 있듯이 조합 계승은 원형 체인 계승과 구조 함수 계승의 최적화를 조합한 계승 방안이자 추천하는 계승 방안이다. 그 단점은 부류 구조 함수를 두 번 호출하면 효율 문제가 있다는 것이다.

4. 원형 계승

function create(o) {
    function F() {}
    F.prototype = o;
    //console.log(new F());
    return new F();
}

let obj = {
    arr: [ 1, 2 ],
    say: function() {
        console.log(this.arr);
    }
};
let F1 = create(obj);
console.log(F1); //{}
console.log(F1.arr); //[1,2]
F1.arr.push(3);
console.log(F1.arr); //[1,2,3]
let F2 = create(obj);
console.log(F2.arr); //[1,2,3]

원형식 계승의 원리: 구조 함수를 만들고 구조 함수의 원형이 대상을 가리키는 다음에 new 조작부호를 호출하여 실례를 만들고 이 실례를 되돌려줍니다. 본질은 전송된 대상에 대한 얕은 복사 단점입니다. 원형의 인용 유형 속성은 각 실례 사이에서 공유됩니다.

5. 기생상속

function Person(obj) {
    let newObj = Object.create(obj);
    newObj.sayHi = function() {
        console.log('Hi');
    };
    return newObj;
}
let objP1 = {
    name: 'tom',
    age: 20,
    hobby: [ 'singing', 'swimming' ],
    say: function() {
        console.log('hello');
    }
};
let newObjP1 = Person(objP1);
newObjP1.hobby.push('running');

console.log(newObjP1);
console.log(newObjP1.hobby); //[ 'singing', 'swimming', 'running' ]
console.log(newObjP1.name, newObjP1.age);
newObjP1.sayHi();

let newObjP2 = Person(objP1); //[ 'singing', 'swimming', 'running' ]
console.log(newObjP2.hobby);

본질적으로 기생 계승은 원형 계승에 대한 두 번째 봉인이다. 그리고 이 두 번째 봉인 과정에서 계승된 대상을 확대했다. 이 새로 창설된 대상은 부류의 속성과 방법이 있을 뿐만 아니라 새로 추가된 속성과 방법도 같다. 기생 계승에서 인용된 유형 속성은 각 실례 간에 공유되고 기생 계승도 추천하지 않는 계승 방안이다.

6. 기생조합 계승

function Create(obj) {
    function P() {}
    P.prototype = obj;
    return new P();
}
function Person(name) {
    this.name = name;
    this.hobby = [ 'reading', 'fishing' ];
}
Person.prototype.say = function() {
    console.log('hi');
};
function P(name, age) {
    Person.call(this, name);
    this.age = age;
}
P.prototype = Create(Person.prototype);
P.prototype.constructor = P; // 
let p1 = new P('tom', 19);
p1.hobby.push('traveling');
console.log(p1); //{ name: 'tom', hobby: [ 'reading', 'fishing','traveling' ], age: 19 }
p1.say(); //hi
let p2 = new P('cat', 10);
console.log(p2); //{ name: 'tom', hobby: [ 'reading', 'fishing' ], age: 10 }

다음은 상기 기생 조합 계승 방안에 대해 한층 더 봉인하는 것이다
function Create(obj) {
    function F() {}
    F.prototype = obj;
    return new F();
}
function inheritPrototype(child, parent) {
    let prototype_inherit = Create(parent.prototype);
    prototype_inherit.constructor = child;
    child.prototype = prototype_inherit;
}
// inheritPrototype :1.  2. constructor 
function Parent(name) {
    this.name = name;
    this.hobby = [ 'reading', 'fishing' ];
}
Parent.prototype.say = function() {
    console.log('hello');
};
function Child(name, age) {
    Parent.call(this, name);
    this.age = age;
}
inheritPrototype(Child, Parent);
let p1 = new Child('tom', 10);
console.log(p1); //{ name: 'tom', hobby: [ 'reading', 'fishing' ], age: 10 }
console.log(Child.prototype.constructor); //Child

단순화
function Parent(name) {
    this.name = name;
    this.hobby = [ 'reading', 'fishing' ];
}
Parent.prototype.say = function() {
    console.log('hello');
};
function Child(name, age) {
    Parent.call(this, name);
    this.age = age;
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;

let p1 = new Child('tom', 10);
p1.hobby.push('he');
console.log(p1); //{ name: 'tom', hobby: [ 'reading', 'fishing' ], age: 10 }
let p2 = new Child('cat', 20);
console.log(p2); //{ name: 'cat', hobby: [ 'reading', 'fishing' ], age: 20 }
console.log(Child.prototype.constructor); //Child

기생 조합 계승은 조합 계승에 비해 높은 효율로 Parent 구조 함수를 한 번만 호출했기 때문에 Parent를 피할 수 있다.prototype에서 불필요한 속성을 만듭니다.이와 동시에 원형 체인은 변하지 않을 수 있다.기생 조합식 계승은 가장 이상적인 계승 모델이다.

7. 최상의 계승 방안es6의 extends

class Person {
    constructor(name) {
        this.name = name;
        this.hobby = [ 1, 2 ];
    }
    sayHi() {
        console.log('hello');
    }
    play() {
        console.log('basketball');
    }
}
class Man extends Person {
    constructor(name, age) {
        super(name);
        this.age = age;
    }
    sayHi() {
        console.log('I am from Man');
    }
}
let man1 = new Man('tom', 20);
console.log(man1);
man1.sayHi(); //I am from Man
man1.play(); //basketball

장점: 간단명료하고 원형을 수동으로 설정하지 않아도 된다.단점: 새 구문, 일부 브라우저 지원, ES5 코드로 전환해야 합니다.

좋은 웹페이지 즐겨찾기