JavaScript geçersiz kılma yöntemleri


87

Aşağıdaki koda sahip olduğunuzu varsayalım:

function A() {
    function modify() {
       x = 300;
       y = 400;
    }

    var c = new C();
}

function B() {
    function modify(){
       x = 3000;
       y = 4000;
    }

    var c = new C();
}

C = function () {
   var x = 10;
   var y = 20;

   function modify() {
      x = 30;
      y = 40;
   };

   modify();
   alert("The sum is: " + (x+y));
}

Ben yöntemini geçersiz hangi bir yolu var Şimdi eğer soru, modifygelen Colan yöntemlerle Ave B. Java'da super-anahtar sözcüğünü kullanırsınız , ancak JavaScript'te böyle bir şeyi nasıl başarabilirsiniz?


6
modifybir yöntem değil, iç içe geçmiş bir işlev - bu ikisi arasında bir fark var ...
Šime Vidas

2
Java'da , bir süper sınıfın özel olmayan alanlarına ve yöntemlerine erişmek için superanahtar sözcüğü kullanırsınız . Onları geçersiz kılmak için kullanmazsınız.
FK82

Yanıtlar:


138

Düzenleme: Orijinal cevabın yazılmasının üzerinden altı yıl geçti ve çok şey değişti!

  • JavaScript yeni bir sürümünü kullanıyorsanız, muhtemelen böyle bir araç ile derlenmiş Babel şunları yapabilirsiniz gerçek sınıflarını kullanın .
  • Angular veya React tarafından sağlanan sınıf benzeri bileşen yapıcılarını kullanıyorsanız, bu çerçeve için dokümanlara bakmak isteyeceksiniz.
  • ES5 kullanıyorsanız ve prototipleri kullanarak elle "sahte" sınıflar oluşturuyorsanız, aşağıdaki cevap hala her zamanki gibi doğrudur.

İyi şanslar!


JavaScript kalıtımı, Java'dan biraz farklı görünüyor. Yerel JavaScript nesne sistemi şu şekilde görünür:

// Create a class
function Vehicle(color){
  this.color = color;
}

// Add an instance method
Vehicle.prototype.go = function(){
  return "Underway in " + this.color;
}

// Add a second class
function Car(color){
  this.color = color;
}

// And declare it is a subclass of the first
Car.prototype = new Vehicle();

// Override the instance method
Car.prototype.go = function(){
  return Vehicle.prototype.go.call(this) + " car"
}

// Create some instances and see the overridden behavior.
var v = new Vehicle("blue");
v.go() // "Underway in blue"

var c = new Car("red");
c.go() // "Underway in red car"

Maalesef bu biraz çirkin ve "süper" için çok hoş bir yol içermiyor: hangi ebeveyn sınıflarının yöntemini çağırmak istediğinizi manuel olarak belirtmeniz gerekiyor. Sonuç olarak, sınıfları daha güzel hale getirmek için çeşitli araçlar vardır. Prototype.js, Backbone.js veya js'de OOP yapmak için daha hoş bir sözdizimi içeren benzer bir kitaplığa bakmayı deneyin.


2
"Sınıf oluşturmayı daha güzel hale getirmek" için bir araç kullanmaya alternatif olarak, sınıfları hiç yapamazsınız. JS'deki klasik OO öykünmesi her zaman karmaşıklaşır.
Raynos

1
(yapıcı yorum değil) tarayıcı dünyasında "düşük seviyeli" dil olduğu için sebepsiz yere çok çirkin. Hala öğreniyorum, teşekkürler!
dnuske

9
Ben Car.prototype = new Vehicle () yerine inanıyorum; bu Car.prototype = Object.create (Vehicle.prototype) olmalıdır; Hayır?
Ürdün

@Martin haklı, bkz. Javascript-miras
matoni

Car.prototype = new Vehicle () nedenlerinden biri; bir renk alırken Araca () geçecek hiçbir şey olmadığı için yanlıştır.
Tushar Arora

63

Bu, Google'da çok popüler olduğu için, güncel bir cevap vermek istiyorum.

ES6 sınıflarını kullanmak , kalıtımı ve yöntemi geçersiz kılma işlemini çok daha kolay hale getirir:

'use strict';

class A {
    speak() {
        console.log("I'm A");
    }
}

class B extends A {
    speak() {
        super.speak();

        console.log("I'm B");
    }
}

var a = new A();
a.speak();
// Output:
// I'm A

var b = new B();
b.speak();
// Output:
// I'm A
// I'm B

superAnahtar kelime miras sınıfta kullanıldığında ana sınıfını ifade eder. Ayrıca, ebeveyn sınıftaki tüm yöntemler, alt sınıfın örneğine bağlıdır, bu nedenle yazmak zorunda kalmazsınız super.method.apply(this);.

Uyumluluk konusuna gelince: ES6 uyumluluk tablosu sadece büyük oyuncuların en son sürümlerini destekler (çoğunlukla). V8 tarayıcıları bu yılın Ocak ayından beri (Chrome ve Opera) bunlara sahipler ve SpiderMonkey JS motorunu kullanan Firefox, önümüzdeki ay resmi Firefox 45 sürümüyle birlikte sınıfları görecek. Mobil tarafta Android hala bu özelliği desteklemiyor, beş ay önce yayınlanan iOS 9 ise kısmi desteğe sahip.

Neyse ki, Harmony kodunu ES5 koduna yeniden derlemek için bir JS kütüphanesi olan Babel var . ES6'daki sınıflar ve diğer pek çok harika özellik, Javascript kodunuzu çok daha okunabilir ve sürdürülebilir hale getirebilir.


10
Bu cevap daha fazla itibarı hak ediyor ve şu anda doğru cevap.
Klompenrunner

6

Bir kez klasik OO'yu taklit etmekten kaçınmalı ve bunun yerine prototipik OO kullanmalıdır. Prototip OO için güzel bir yardımcı program kitaplığı özelliklerdir .

Daha sonra yöntemlerin üzerine yazmak ve miras zincirleri kurmak yerine (her zaman nesne kompozisyonunu nesne kalıtımına tercih etmelisiniz), yeniden kullanılabilir işlevleri özelliklerle birleştirmeli ve bunlarla nesneler yaratmalısınız.

Canlı Örnek

var modifyA = {
    modify: function() {
        this.x = 300;
        this.y = 400;
    }
};

var modifyB = {
    modify: function() {
        this.x = 3000;
        this.y = 4000;
    }
};

C = function(trait) {
    var o = Object.create(Object.prototype, Trait(trait));

    o.modify();
    console.log("sum : " + (o.x + o.y));

    return o;
}

//C(modifyA);
C(modifyB);

10
Soruyu cevaplamıyorsun. Bu bir yorum olmalı.
FK82


3

Örneğinizdeki modifiye (), A, B veya C tanımınız dışında hiçbir yerden erişilemeyen özel bir işlevdir. Bunu olarak ilan etmeniz gerekecek

this.modify = function(){}

Siz C'ye geçmedikçe, C'nin üstlerine referansı yoktur. C, A veya B'den miras alacak şekilde ayarlanmışsa, genel yöntemlerini miras alır (değiştirdiğiniz () gibi özel işlevleri değil). C, metotları üstünden devraldığında, miras alınan metotları geçersiz kılabilirsiniz.


değiştirme yerel bir işlevdir. Javascript'te özel yoktur
Raynos

yerel / özel, bu aynı şey değil, sadece farklı bir terim?
Alex Heyd

2

en modify()son çağırdığınız yöntem genel bağlamda çağrılır eğer geçersiz kılmak modify()istiyorsanız önce Aveya B.

Belki bunu yapmaya çalışıyorsun:

Bu durumda Cmiras alırA

function A() {
    this.modify = function() {
        alert("in A");
    }
}

function B() {
    this.modify = function() {
        alert("in B");
    }
}

C = function() {
    this.modify = function() {
        alert("in C");
    };

    C.prototype.modify(); // you can call this method where you need to call modify of the parent class
}

C.prototype = new A();

1
C.prototype.modify()yanlış thisdeğere sahip olur . Yani C.prototypec örneği yerine. Lütfen kullanın, .call(this)ancak cevabınız sadece bir kopya :)
Raynos

1

Tüm değişkenleri "genel" yapmazsanız, yani onları Functiondoğrudan veya prototypemülk aracılığıyla "genel" yapmazsanız .

var C = function( ) {
    this.x = 10 , this.y = 20 ;
    this.modify = function( ) {
        this.x = 30 , this.y = 40 ;
        console.log("(!) C >> " + (this.x + this.y) ) ;
    } ;
} ;

var A = function( ) {
    this.modify = function( ) {
       this.x = 300 , this.y = 400 ;
       console.log("(!) A >> " + (this.x + this.y) ) ;
    } ;
} ;
    A.prototype = new C ;

var B = function( ) {
    this.modify = function( ) {
       this.x = 3000 , this.y = 4000 ;
       console.log("(!) B >> " + (this.x + this.y) ) ;
    } ;
} ;


new C( ).modify( ) ;
new A( ).modify( ) ;
new B( ).modify( ) ; 

Birkaç değişiklik fark edeceksiniz.

En önemlisi, varsayılan "süper sınıflar" kurucusuna yapılan çağrı artık bu satırda örtüktür:

<name>.prototype = new C ;

Her ikisi de Ave Bşimdi bireysel olarak değiştirilebilir üyelere sahip olacak xve ybunun yerine yazacak olsaydık durum böyle olmayacaktı ... = C.

Sonra, x , yve modifytüm "kamu" üyeleri yüzden farklı atama olduğunu Functiononlara

 <name>.prototype.modify = function( ) { /* ... */ }

Functionbu ada göre orijinali "geçersiz kılacaktır" .

Son olarak, sözde "süper-sınıf" ı varsayılan "alt sınıfların" özelliğine ayarladığımızda "süper-sınıfa" yapılan örtük çağrı tekrar çalıştırılacağından modify, Functionbildirimde çağrı yapılamaz prototype.

Ancak, JavaScript'te bu tür şeyleri aşağı yukarı böyle yaparsınız.

HTH,

FK


<name>.prototype = new C;Zaten prototipin tüm üyelerini gölgelemenizin bir anlamı yok
Raynos

@Raynos: Evet var. Şüphesiz, bir Nesneyi başlatmazsanız , tüm miras Objectsalan aynı üyeyi paylaşıyor olacaktır . Böylece, değişen yılında değiştirecek içinde ve böylece değiştirmek içinde . Açıkçası istenmeyen bir durum. CCxAxCxB
FK82

noktayı kaçırdın. Satırı kaldırabilirsiniz ve kod çalışmaya devam eder
Raynos

@Raynos: Korkarım kendi fikrinizi kaçırıyorsunuz. ;-) Biz istiyoruz Ave Bmiras almak istiyoruz C. Bu satır eksik olsaydı, durum böyle olmazdı. Aslında, hem "gölge" nin hem Ade B"gölge" nin erişebileceği tek prototip bu durumda olacaktır Object.prototype.
FK82

koda bakın. A ve B, prototipte C üyelerinden hiçbirini kullanmaz. Yani C'den "miras almak" işe yaramaz. Bunun nedeni A ve B Redefine x, yvemodify dolayısıyla tüm gölge Cbireyin üyeleri. Kullanmıyorsanız prototipe C koymanın ne anlamı var? Ölü kod.
Raynos

0

function A() {
    var c = new C();
	c.modify = function(){
		c.x = 123;
		c.y = 333;
	}
	c.sum();
}

function B() {
    var c = new C();
	c.modify = function(){
		c.x = 999;
		c.y = 333;
	}
	c.sum();
}


C = function () {
   this.x = 10;
   this.y = 20;

   this.modify = function() {
      this.x = 30;
      this.y = 40;
   };
   
   this.sum = function(){
	this.modify();
	console.log("The sum is: " + (this.x+this.y));
   }
}

A();
B();

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.