>  기사  >  웹 프론트엔드  >  Javascript 상속 메커니즘과 단순 상속 소스 코드 분석을 얕은 기술부터 deep_javascript 기술까지 설명합니다.

Javascript 상속 메커니즘과 단순 상속 소스 코드 분석을 얕은 기술부터 deep_javascript 기술까지 설명합니다.

WBOY
WBOY원래의
2016-05-16 15:25:511221검색

대부분의 사람들은 이 문제를 체계적으로 이해하지 못할 수도 있습니다. Javascript 언어는 상속을 잘 구현하지 못하므로 엔지니어는 완전한 상속 메커니즘을 스스로 구현해야 합니다. 아래에서는 더 얕은 시스템에서 더 깊은 시스템으로 JavaScript 상속을 사용하는 기술을 마스터합니다.

1. 프로토타입 체인을 직접 사용

가장 간단하고 조잡한 방법이므로 특정 프로젝트에서는 사용할 수 없습니다. 간단한 데모는 다음과 같습니다:

function SuperType(){
  this.property = true;
}
SuperType.prototype.getSuperValue = function(){
  return this.property;
}
function SubType(){
  this.subproperty = false;
}
//继承
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function(){
  return this.subproperty;
}
var instance = new SubType();

이 접근 방식의 문제점은 프로토타입의 속성이 모든 인스턴스에서 공유된다는 것입니다. 한 인스턴스를 통해 상속된 속성을 변경하면 다른 인스턴스에 영향을 미칩니다. ,이것은 분명히 전통적인 의미의 상속이 아닙니다.

2. 생성자 사용

생성자는 기본적으로 모든 범위에서 호출할 수 있는 함수일 뿐입니다. 하위 생성자에서 상위 생성자를 호출하면 간단한 상속이 가능합니다.

function SuperType(){
  this.colors = {"red","blue","green"}
}
function SubType(){
  SuperType.call(this);  
}
var instance = new SubType();

이 구현은 여러 인스턴스가 속성을 공유하는 문제를 방지하지만 기능을 공유할 수 없고 SuperType의 인스턴스 인스턴스가 false인 등의 새로운 문제가 발생합니다.

3. 프로토타입과 생성자를 함께 사용하세요

function SuperType(name){
  this.name = name;
  this.colors = {"red","blue","green"}
}
SuperType.prototype.sayName = function(){
  //code
}
function SubType(name,age){
  SuperType.call(this,name); 
  this.age = age;
}
SubType.prototype = new SuperType();
var instance = new SubType();

프로토타입과 생성자를 결합하여 사용하는 것은 JavaScript에서 가장 일반적으로 사용되는 상속 패턴입니다. 이 접근 방식을 사용하면 각 인스턴스가 고유한 속성을 가지며 프로토타입의 메서드를 공유할 수 있습니다. 그러나 이 접근 방식의 단점은 상황에 관계없이 슈퍼클래스 생성자가 두 번 호출된다는 것입니다. 한 번은 서브클래스 프로토타입을 생성할 때이고 다른 한 번은 서브클래스 생성자 내부에서입니다. 이 문제를 해결하는 방법?

4. 기생 결합 상속

SubType의 프로토타입은 SuperType의 인스턴스일 필요는 없으며 생성자 프로토타입이 SuperType의 프로토타입인 일반 개체이면 됩니다. Douglas Crockford가 수행하는 방법은 다음과 같습니다.

function obejct(o){
  function F(){};
  F.prototype = o;
  return new F();
}

사실 이는 ES5의 Object.create 구현입니다. 그런 다음 이 문서의 세 번째 옵션을 수정할 수 있습니다.

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(){
  //code
}
function SubType(name,age){
  SuperType.call(this,name); 
  this.age = age;
}
inheritPrototype(SubType,SuperType);
var instance = new SubTYpe();

사실 기생 결합 상속은 이미 아주 좋은 상속 구현 메커니즘이므로 매일 사용하기에 충분합니다. 더 높은 요구 사항을 제시하면 어떻게 될까요? 예를 들어 하위 클래스에서 상위 클래스의 메서드를 호출하는 방법은 무엇입니까?

5.단순 상속 라이브러리 구현

이렇게 이해하기 어려운 코드를 보며 처음에는 거부했지만, 더 깊이 들어가고 나니 훌륭한 사람은 훌륭한 사람이고, 미묘한 아이디어는 어디에나 있다는 것을 깨달았습니다. 모든 코드 줄에 대해 자세한 설명이 있습니다. 세부 사항을 알고 싶다면 자세히 연구하고 모든 줄을 읽으십시오. 이 구현에서 가장 절묘한 부분은 요청에 따라 부모 클래스 메서드를 다시 작성한다는 점이라고 생각합니다. 인스턴스 객체에서는 Java 구현과 마찬가지로 _super를 통해 부모 클래스와 동일한 이름의 메서드를 호출할 수 있습니다.

(function(){
  //initializing用于控制类的初始化,非常巧妙,请留意下文中使用技巧
  //fnTest返回一个正则比表达式,用于检测函数中是否含有_super,这样就可以按需重写,提高效率。当然浏览器如果不支持的话就返回一个通用正则表达式
  var initializing = false,fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
  //所有类的基类Class,这里的this一般是window对象
  this.Class = function(){};
  //对基类添加extend方法,用于从基类继承
  Class.extend = function(prop){
    //保存当前类的原型
    var _super = this.prototype;
    //创建当前类的对象,用于赋值给子类的prototype,这里非常巧妙的使用父类实例作为子类的原型,而且避免了父类的初始化(通过闭包作用域的initializing控制)
    initializing = true;
    var prototype = new this();   
    initializing = false;
    //将参数prop中赋值到prototype中,这里的prop中一般是包括init函数和其他函数的对象
    for(var name in prop){
      //对应重名函数,需要特殊处理,处理后可以在子函数中使用this._super()调用父类同名构造函数, 这里的fnTest很巧妙:只有子类中含有_super字样时才处理从写以提高效率
      prototype[name] = typeof prop[name] == "function" && typeof _super[name] == "function" && fnTest.test(prop[name])?
       (function(name,fn){
        return function(){
          //_super在这里是我们的关键字,需要暂时存储一下
          var tmp = this._super; 
          //这里就可以通过this._super调用父类的构造函数了       
          this._super = _super[name];
          //调用子类函数 
          fn.apply(this,arguments);
          //复原_super,如果tmp为空就不需要复原了
          tmp && (this._super = tmp);
        }
       })(name,prop[name]) : prop[name];
    }
    //当new一个对象时,实际上是调用该类原型上的init方法,注意通过new调用时传递的参数必须和init函数的参数一一对应
    function Class(){
      if(!initializing && this.init){
        this.init.apply(this,arguments);  
      }
    }    
    //给子类设置原型
    Class.prototype = prototype;
    //给子类设置构造函数
    Class.prototype.constructor = Class;
    //设置子类的extend方法,使得子类也可以通过extend方法被继承
    Class.extend = arguments.callee;
    return Class;
  }
})();

단순 상속 라이브러리를 사용하면 매우 간단한 방법으로 상속을 구현할 수 있습니다. 특히 강력한 형식의 언어 상속과 비슷하다고 생각하시나요?

var Human = Class.extend({
 init: function(age,name){
  this.age = age;
  this.name = name;
 },
 say: function(){
  console.log("I am a human");
 }
});
var Man = Human.extend({
  init: function(age,name,height){
    this._super(age,name);
    this.height = height;
  }, 
  say: function(){
    this._super();
    console.log("I am a man"); 
  }
});
var man = new Man(21,'bob','191');
man.say();

Javascript 상속 메커니즘과 단순 상속 소스 코드 분석을 얕은 것부터 더 깊은 것까지 설명합니다. 이 글을 공유하는 것이 모든 사람에게 도움이 되기를 바랍니다.

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.