Heim  >  Artikel  >  Web-Frontend  >  Erklären Sie den Javascript-Vererbungsmechanismus und die Analyse des Quellcodes mit einfacher Vererbung von flachen bis hin zu tiefen Javascript-Kenntnissen

Erklären Sie den Javascript-Vererbungsmechanismus und die Analyse des Quellcodes mit einfacher Vererbung von flachen bis hin zu tiefen Javascript-Kenntnissen

WBOY
WBOYOriginal
2016-05-16 15:25:511221Durchsuche

Die meisten Menschen sind möglicherweise nicht in der Lage, dieses Problem systematisch zu verstehen. Die Javascript-Sprache implementiert die Vererbung nicht gut, und Ingenieure müssen selbst einen vollständigen Vererbungsmechanismus implementieren. Im Folgenden werden wir die Techniken der Verwendung der JavaScript-Vererbung vom flacheren zum tieferen System beherrschen.

1. Nutzen Sie die Prototypenkette direkt

Dies ist die einfachste und gröbste Methode und kann nicht in bestimmten Projekten verwendet werden. Eine einfache Demo lautet wie folgt:

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();

Das Problem bei diesem Ansatz besteht darin, dass die Eigenschaften im Prototyp von allen Instanzen gemeinsam genutzt werden. Das Ändern einer geerbten Eigenschaft durch eine Instanz hat Auswirkungen auf andere Instanzen. ,Dies ist offensichtlich keine Vererbung im herkömmlichen Sinne.

2. Verwenden Sie den Konstruktor

Der Konstruktor ist im Wesentlichen nur eine Funktion, die in jedem Bereich aufgerufen werden kann. Durch Aufrufen des übergeordneten Konstruktors im untergeordneten Konstruktor kann eine einfache Vererbung erreicht werden.

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

Diese Implementierung vermeidet das Problem, dass mehrere Instanzen Attribute gemeinsam nutzen, es treten jedoch neue Probleme auf, z. B. können Funktionen nicht gemeinsam genutzt werden und die Instanzinstanz von SuperType ist falsch.

3. Verwenden Sie Prototypen und Konstrukteure in Kombination

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();

Die kombinierte Verwendung von Prototypen und Konstruktoren ist das am häufigsten verwendete Vererbungsmuster in JavaScript. Bei diesem Ansatz hat jede Instanz ihre eigenen Eigenschaften, während Methoden aus dem Prototyp gemeinsam genutzt werden können. Der Nachteil dieses Ansatzes besteht jedoch darin, dass der Konstruktor der Oberklasse unabhängig von der Situation zweimal aufgerufen wird. Einmal beim Erstellen des Unterklassenprototyps und ein anderes Mal im Unterklassenkonstruktor. Wie kann dieses Problem gelöst werden?

4. Parasitäre kombinierte Vererbung

Der Prototyp von SubType muss keine Instanz von SuperType sein, er muss nur ein gewöhnliches Objekt sein, dessen Konstruktor-Prototyp der Prototyp von SuperType ist. So macht es Douglas Crockford:

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

Tatsächlich ist dies die Implementierung von Object.create in ES5. Dann können wir die dritte Option in diesem Artikel ändern:

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();

Tatsächlich ist die parasitäre kombinierte Vererbung bereits ein sehr guter Mechanismus zur Vererbungsimplementierung, der für den täglichen Gebrauch ausreicht. Was wäre, wenn wir höhere Anforderungen stellen würden: Wie soll beispielsweise die Methode der übergeordneten Klasse in der Unterklasse aufgerufen werden?

5.Implementierung der einfachen Vererbungsbibliothek

Als ich mir einen so schwer verständlichen Code ansah, weigerte ich mich zunächst, aber nachdem ich tiefer gegangen war, wurde mir klar, dass großartige Menschen großartige Menschen sind und es überall subtile Ideen gibt. Ich habe detaillierte Kommentare zu jeder Codezeile. Wenn Sie die Details wissen möchten, lesen Sie es unbedingt im Detail und lesen Sie jede Zeile. Ich denke, der exquisiteste Teil dieser Implementierung besteht darin, die Methode der übergeordneten Klasse bei Bedarf neu zu schreiben. Im Instanzobjekt kann die gleichnamige Methode der übergeordneten Klasse über _super aufgerufen werden, ähnlich wie bei der Implementierung von Java.

(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;
  }
})();

Durch die Verwendung der Simple-Inheritance-Bibliothek können wir die Vererbung auf sehr einfache Weise implementieren. Finden Sie, dass sie der Vererbung einer stark typisierten Sprache besonders ähnlich ist?

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();

Erklären Sie den Javascript-Vererbungsmechanismus und die Analyse des Quellcodes mit einfacher Vererbung von der Tiefe bis zur Tiefe. Ich hoffe, dass das Teilen dieses Artikels allen helfen kann.

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn