Heim  >  Artikel  >  Web-Frontend  >  So implementieren Sie Vererbungsfunktionen in JavaScript-Programmen (grafisches Tutorial)

So implementieren Sie Vererbungsfunktionen in JavaScript-Programmen (grafisches Tutorial)

亚连
亚连Original
2018-05-21 09:33:35844Durchsuche

JavaScript ist eine Sprache, die behauptet, objektorientiert zu sein, und Vererbung ist ein Hauptmerkmal der Objektorientierung. Hier ist, was ich für Sie zusammengestellt habe.

ÜbersichtAlle Objekte in JavaScript haben ihre eigene Vererbungskette. Das heißt, jedes Objekt erbt ein anderes Objekt, das als „Prototyp“-Objekt bezeichnet wird. Mit Ausnahme von null verfügt es über kein eigenes Prototypobjekt.

Die Bedeutung des Prototypobjekts besteht darin, dass, wenn das A-Objekt der Prototyp des B-Objekts ist, das B-Objekt alle Eigenschaften und Methoden des A-Objekts erhalten kann. Die Methode Object.getPrototypof wird verwendet, um das Prototypobjekt des aktuellen Objekts abzurufen.

var p = Object.getPrototypeOf(obj);

Im obigen Code ist Objekt p das Prototypobjekt von Objekt obj.

Die Object.create-Methode wird verwendet, um ein neues Objekt zu generieren und das angegebene Objekt zu erben.

var obj = Object.create(p);

Im obigen Code ist der Prototyp des neu generierten obj-Objekts das Objekt p.

Das nicht standardmäßige __proto__-Attribut (zwei Unterstriche davor und danach) kann das Prototypobjekt eines Objekts überschreiben. Sie sollten dieses Attribut jedoch so wenig wie möglich verwenden und stattdessen Object.getPrototypeof() und Object.setPrototypeOf() zum Lesen und Schreiben von Prototypobjekten verwenden.

var obj = {};
var p = {};

obj.__proto__ = p;
Object.getPrototypeOf(obj) === p // true

Der obige Code legt das p-Objekt über das Attribut __proto__ als Prototyp des obj-Objekts fest.

Hier ist ein praktisches Beispiel.

var a = {x: 1};
var b = {__proto__: a};
b.x // 1

Im obigen Code setzt das b-Objekt sein Prototypobjekt über das __proto__-Attribut auf das a-Objekt, sodass das b-Objekt alle Attribute und Methoden des a-Objekts erhalten kann. Das b-Objekt selbst hat kein x-Attribut, aber die JavaScript-Engine findet sein Prototypobjekt a über das __proto__-Attribut und liest dann das x-Attribut von a. Der Befehl

new erstellt über den Konstruktor ein neues Instanzobjekt. Das Wesentliche besteht darin, den Prototyp des Instanzobjekts an das Prototypattribut des Konstruktors zu binden und dann den Konstruktor für das Instanzobjekt auszuführen.

var o = new Foo();

// 等同于
var o = new Object();
o.__proto__ = Foo.prototype;
Foo.call(o);

Das eigene __proto__-Attribut des Prototypobjekts kann auch auf andere Objekte verweisen und so eine „Prototypkette“ Ebene für Ebene bilden.

var a = { x: 1 };
var b = { __proto__: a };
var c = { __proto__: b };

c.x // 1

Es ist zu beachten, dass die Suche nach einem bestimmten Attribut in der Prototypenkette eine Ebene höher einen Einfluss auf die Leistung hat. Je mehr Eigenschaften Sie suchen, desto größer ist die Auswirkung auf die Leistung. Wenn Sie nach einer Eigenschaft suchen, die nicht existiert, wird die gesamte Prototypenkette durchlaufen.

Diese Aktion zeigt auf Unabhängig davon, wo dies definiert ist, zeigt es bei Verwendung immer auf das aktuelle Objekt, nicht auf das Prototypobjekt.

var o = {
 a: 2,
 m: function(b) {
  return this.a + 1;
 }
};

var p = Object.create(o);
p.a = 12;

p.m() // 13

Im obigen Code stammt die m-Methode des p-Objekts von seinem Prototypobjekt o. Zu diesem Zeitpunkt zeigt das Objekt this in der m-Methode nicht auf o, sondern auf p.

KonstruktorvererbungIn diesem Abschnitt wird erläutert, wie Sie einen Konstruktor dazu bringen, einen anderen Konstruktor zu erben.

Angenommen, es gibt einen Shape-Konstruktor.

function Shape() {
 this.x = 0;
 this.y = 0;
}

Shape.prototype.move = function (x, y) {
 this.x += x;
 this.y += y;
 console.info('Shape moved.');
};
Rectangle构造函数继承Shape。

function Rectangle() {
 Shape.call(this); // 调用父类构造函数
}
// 另一种写法
function Rectangle() {
 this.base = Shape;
 this.base();
}

// 子类继承父类的方法
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;

var rect = new Rectangle();

rect instanceof Rectangle // true
rect instanceof Shape // true

rect.move(1, 1) // 'Shape moved.'

Der obige Code zeigt an, dass die Vererbung des Konstruktors in zwei Teile unterteilt ist. Ein Teil besteht darin, dass die Unterklasse die Konstruktormethode der übergeordneten Klasse aufruft, und der andere Teil besteht darin, dass der Prototyp der Unterklasse zeigt der Prototyp der übergeordneten Klasse.

Im obigen Code erbt die Unterklasse die übergeordnete Klasse als Ganzes. Manchmal ist nur die Vererbung einer einzelnen Methode erforderlich. In diesem Fall kann die folgende Schreibmethode verwendet werden.

ClassB.prototype.print = function() {
 ClassA.prototype.print.call(this);
 // some code
}

Im obigen Code ruft die Druckmethode der Unterklasse B zuerst die Druckmethode der übergeordneten Klasse A auf und stellt dann ihren eigenen Code bereit. Dies entspricht dem Erben der Druckmethode der übergeordneten Klasse A.

__proto__-Attribut __proto__-Attribut zeigt auf das Prototypobjekt des aktuellen Objekts, dh das Prototypattribut des Konstruktors.

var obj = new Object();

obj.__proto__ === Object.prototype
// true
obj.__proto__ === obj.constructor.prototype
// true

Der obige Code erstellt zunächst ein neues Objekt obj und sein __proto__-Attribut verweist auf das Prototypattribut des Konstruktors (Object oder obj.constructor). Daher wird nach dem Vergleich der beiden true zurückgegeben.

Daher gibt es drei Methoden, um das Prototypobjekt des Instanzobjekts obj zu erhalten.

  • obj.__proto__

  • obj.constructor.prototype

  • Object.getPrototypeOf(obj)

Von den oben genannten drei Methoden sind die ersten beiden nicht sehr zuverlässig. Der neueste ES6-Standard schreibt vor, dass das __proto__-Attribut nur in Browsern bereitgestellt werden muss und nicht in anderen Umgebungen bereitgestellt werden muss. Obj.constructor.prototype kann ungültig werden, wenn das Prototypobjekt manuell geändert wird.

var P = function () {};
var p = new P();

var C = function () {};
C.prototype = p;
var c = new C();

c.constructor.prototype === p // false

Im obigen Code wurde das Prototypobjekt des C-Konstruktors in p geändert, wodurch c.constructor.prototype verzerrt wurde. Daher müssen Sie beim Ändern des Prototypobjekts im Allgemeinen gleichzeitig das Konstruktorattribut festlegen.

C.prototype = p;
C.prototype.constructor = C;

c.constructor.prototype === p // true

Daher wird empfohlen, die dritte Methode Object.getPrototypeOf zu verwenden, um das Prototypobjekt abzurufen. Die Methode wird wie folgt verwendet.

var o = new Object();

Object.getPrototypeOf(o) === Object.prototype
// true

Mit der Methode Object.getPrototypeOf können Sie prüfen, ob der Browser das Attribut __proto__ unterstützt.

Object.getPrototypeOf({ __proto__: null }) === null

Der obige Code setzt das __proto__-Attribut eines Objekts auf null und verwendet dann die Methode Object.getPrototypeOf, um den Prototyp des Objekts abzurufen und zu bestimmen, ob er gleich null ist. Wenn die aktuelle Umgebung das Attribut __proto__ unterstützt, sollte das Vergleichsergebnis zwischen den beiden wahr sein.

Mit dem Attribut __proto__ können Sie ganz einfach den Prototyp des Instanzobjekts festlegen. Angenommen, es gibt drei Objekte: Maschine, Fahrzeug und Auto, wobei Maschine der Prototyp eines Fahrzeugs und Fahrzeug der Prototyp eines Autos ist. Zur Einrichtung sind nur zwei Codezeilen erforderlich.

vehicle.__proto__ = machine;
car.__proto__ = vehicle;

Das Folgende ist ein Beispiel für das Lesen der Attribute, die für das Prototypobjekt über das Attribut __proto__ und das Attribut constructionor.prototype definiert sind.

Array.prototype.p = 'abc';
var a = new Array();

a.__proto__.p // abc
a.constructor.prototype.p // abc

Offensichtlich sieht __proto__ einfacher aus.

通过构造函数生成实例对象时,实例对象的__proto__属性自动指向构造函数的prototype对象。

var f = function (){};
var a = {};

f.prototype = a;
var o = new f();

o.__proto__ === a
// true

属性的继承属性分成两种。一种是对象自身的原生属性,另一种是继承自原型的继承属性。

对象的原生属性对象本身的所有属性,可以用Object.getOwnPropertyNames方法获得。

Object.getOwnPropertyNames(Date)
// ["parse", "arguments", "UTC", "caller", "name", "prototype", "now", "length"]

对象本身的属性之中,有的是可以枚举的(enumerable),有的是不可以枚举的。只获取那些可以枚举的属性,使用Object.keys方法。

Object.keys(Date) // []
hasOwnProperty()

hasOwnProperty方法返回一个布尔值,用于判断某个属性定义在对象自身,还是定义在原型链上。

Date.hasOwnProperty('length')
// true

Date.hasOwnProperty('toString')
// false

hasOwnProperty方法是JavaScript之中唯一一个处理对象属性时,不会遍历原型链的方法。

对象的继承属性用Object.create方法创造的对象,会继承所有原型对象的属性。

var proto = { p1: 123 };
var o = Object.create(proto);

o.p1 // 123
o.hasOwnProperty("p1") // false

获取所有属性判断一个对象是否具有某个属性(不管是自身的还是继承的),使用in运算符。

"length" in Date // true
"toString" in Date // true

获得对象的所有可枚举属性(不管是自身的还是继承的),可以使用for-in循环。

var o1 = {p1: 123};

var o2 = Object.create(o1,{
 p2: { value: "abc", enumerable: true }
});

for (p in o2) {console.info(p);}
// p2
// p1

为了在for...in循环中获得对象自身的属性,可以采用hasOwnProperty方法判断一下。

for ( var name in object ) {
 if ( object.hasOwnProperty(name) ) {
  /* loop code */
 }
}

获得对象的所有属性(不管是自身的还是继承的,以及是否可枚举),可以使用下面的函数。

function inheritedPropertyNames(obj) {
 var props = {};
 while(obj) {
  Object.getOwnPropertyNames(obj).forEach(function(p) {
   props[p] = true;
  });
  obj = Object.getPrototypeOf(obj);
 }
 return Object.getOwnPropertyNames(props);
}

用法如下:

inheritedPropertyNames(Date)
// ["caller", "constructor", "toString", "UTC", "call", "parse", "prototype", "__defineSetter__", "__lookupSetter__", "length", "arguments", "bind", "__lookupGetter__", "isPrototypeOf", "toLocaleString", "propertyIsEnumerable", "valueOf", "apply", "__defineGetter__", "name", "now", "hasOwnProperty"]

对象的拷贝如果要拷贝一个对象,需要做到下面两件事情。

确保拷贝后的对象,与原对象具有同样的prototype原型对象。
确保拷贝后的对象,与原对象具有同样的属性。
下面就是根据上面两点,编写的对象拷贝的函数。

function copyObject(orig) {
 var copy = Object.create(Object.getPrototypeOf(orig));
 copyOwnPropertiesFrom(copy, orig);
 return copy;
}

function copyOwnPropertiesFrom(target, source) {
 Object
 .getOwnPropertyNames(source)
 .forEach(function(propKey) {
  var desc = Object.getOwnPropertyDescriptor(source, propKey);
  Object.defineProperty(target, propKey, desc);
 });
 return target;
}

多重继承JavaScript不提供多重继承功能,即不允许一个对象同时继承多个对象。但是,可以通过变通方法,实现这个功能。

function M1(prop) {
 this.hello = prop;
}

function M2(prop) {
 this.world = prop;
}

function S(p1, p2) {
 this.base1 = M1;
 this.base1(p1);
 this.base2 = M2;
 this.base2(p2);
}
S.prototype = new M1();

var s = new S(111, 222);
s.hello // 111
s.world // 222

上面代码中,子类S同时继承了父类M1和M2。当然,从继承链来看,S只有一个父类M1,但是由于在S的实例上,同时执行M1和M2的构造函数,所以它同时继承了这两个类的方法。

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

详细介绍在JS中Map和ForEach的区别

js装饰设计模式学习心得(详细解答)

详解解读JS数值Number类型(图文教程)

Das obige ist der detaillierte Inhalt vonSo implementieren Sie Vererbungsfunktionen in JavaScript-Programmen (grafisches Tutorial). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

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