Javascript'te polimorfizm nedir?


92

İnternette polimorfizm üzerine bulabildiğim bazı olası makaleleri okudum . Ama bunun anlamını ve önemini tam olarak kavrayamadığımı düşünüyorum. Makalelerin çoğu, neden önemli olduğunu ve OOP'de (elbette JavaScript'te) polimorfik davranışa nasıl ulaşabileceğimi söylemiyor.

Herhangi bir kod örneği veremiyorum çünkü onu nasıl uygulayacağım konusunda fikrim yok, bu yüzden sorularım aşağıdadır:

  1. Bu ne?
  2. Neden ihtiyacımız var?
  3. Nasıl çalışır?
  4. JavaScript'te bu polimorfik davranışı nasıl elde edebilirim?

Bu örneğe sahibim. Ancak bu kodun sonucunun ne olacağı kolayca anlaşılabilir. Polimorfizmin kendisi hakkında net bir fikir vermez.

function Person(age, weight) {
    this.age = age;
    this.weight = weight;
    this.getInfo = function() {
        return "I am " + this.age + " years old " +
        "and weighs " + this.weight +" kilo.";
    }
}
function Employee(age, weight, salary) {
    this.salary = salary;
    this.age = age;
    this.weight = weight;
    this.getInfo = function() {
        return "I am " + this.age + " years old " +
        "and weighs " + this.weight +" kilo " +
        "and earns " + this.salary + " dollar.";
    }
}

Employee.prototype = new Person();
Employee.prototype.constructor = Employee;
  // The argument, 'obj', can be of any kind
  // which method, getInfo(), to be executed depend on the object
  // that 'obj' refer to.

function showInfo(obj) {
    document.write(obj.getInfo() + "<br>");
}

var person = new Person(50,90);
var employee = new Employee(43,80,50000);
showInfo(person);
showInfo(employee);

Bu soru muhtemelen StackOverflow ile iyi çalışamayacak kadar geniş. Yapabileceğimizin en iyisi, sizi başka bir polimorfizm açıklamasına bağlamak olacaktır. StackOverflow, "Kaynak çok biçimliliğin XYZ olduğunu söyledi, ancak Y ne anlama geliyor?" Gibi belirli bir sorunla ilgili belirli soruları veya açıklamaları yanıtlamakta en iyisidir.
Vitruvius

2
buna ihtiyacın yok. hiç. JS'de sınıflara bile ihtiyacınız yok ve aslında, uygulama oluşturma için tartışmasız daha iyi birçok paradigma var. Apply / call / bind, homojenlik ihtiyacını ortadan kaldırır ve yumuşak nesne ile, önceden dekore etmeden veya özel durumları devralmadan ihtiyaçlarınıza uygun her şeyi değiştirebilirsiniz.
dandavis

1
Polimorfizm sadece OO ile ilgili değildir ve birçok anlamı vardır. Kalıtım Olmadan Polimorfizm Mümkün mü soruları altındaki bu diğer cevabı okumak isteyebilirsiniz .
Edwin Dalorzo

Devralma genellikle JavaScript'te yanlış yapılır. Child'ın prototipi olarak kullanılmak üzere bir Parent örneği oluşturmak, bir nesneyi tanımlamada ve yaratmada yapıcı işlevin ve prototipin oynadığı rolün anlaşılmadığını gösterir. Bu yanıtta daha fazla bilgi bulabilirsiniz: stackoverflow.com/a/16063711/1641941
HMR

Yanıtlar:


99

Polimorfizm, Nesne Yönelimli Programlamanın (OOP) ilkelerinden biridir. Davranışları paylaşmak ve belirli davranışlarla paylaşılan davranışları geçersiz kılmak için nesneler tasarlama pratiğidir. Çok biçimlilik, bunun gerçekleşmesi için kalıtımdan yararlanır.

OOP'de her şeyin bir nesne olarak modelleneceği kabul edilir. Bu soyutlama, bir araba için somunlara ve cıvatalara kadar veya bir yıl, marka ve model içeren basit bir araba tipi kadar geniş bir şekilde alınabilir.

Bir polimorfik araba senaryosuna sahip olmak için, temel araba tipi olacak ve daha sonra arabadan miras alacak ve bir arabanın sahip olacağı temel davranışların üzerine kendi davranışlarını sağlayacak alt sınıflar olacaktır. Örneğin, bir alt sınıf, bir yıllık modeli ve modeli olan TowTruck olabilir, ancak aynı zamanda IsTowing için bir bayrak kadar temel olabilecek ve asansörün özellikleri kadar karmaşık olabilecek bazı ekstra davranışlara ve özelliklere sahip olabilir.

İnsan ve çalışan örneğine dönersek, tüm çalışanlar insandır, ancak tüm insanlar çalışan değildir. Bu, insanların süper sınıf, alt sınıfın çalışanı olacağı anlamına gelir. İnsanların yaşları ve ağırlıkları olabilir, ancak maaşları yoktur. Çalışanlar insanlardır, bu nedenle doğaları gereği bir yaş ve kiloya sahip olacaklardır, ancak aynı zamanda çalışan oldukları için de maaşları olacaktır.

Yani bunu kolaylaştırmak için önce süper sınıfı (Kişi) yazacağız.

function Person(age,weight){
 this.age = age;
 this.weight = weight;
}

Ve Kişiye bilgilerini paylaşma olanağı vereceğiz

Person.prototype.getInfo = function(){
 return "I am " + this.age + " years old " +
    "and weighs " + this.weight +" kilo.";
};

Daha sonra bir Kişi, Çalışan alt sınıfına sahip olmak istiyoruz

function Employee(age,weight,salary){
 this.age = age;
 this.weight = weight;
 this.salary = salary;
}
Employee.prototype = new Person();

Ve bir Çalışan için daha uygun olanı tanımlayarak getInfo davranışını geçersiz kılacağız

Employee.prototype.getInfo = function(){
 return "I am " + this.age + " years old " +
    "and weighs " + this.weight +" kilo " +
    "and earns " + this.salary + " dollar.";  
};

Bunlar, orijinal kod kullanımınıza benzer şekilde kullanılabilir

var person = new Person(50,90);
var employee = new Employee(43,80,50000);

console.log(person.getInfo());
console.log(employee.getInfo());

Bununla birlikte, Çalışanın yapıcısı kişininkine çok benzediğinden ve prototipteki tek işlev geçersiz kıldığından, burada kalıtım kullanılarak çok fazla kazanılmamıştır. Polimorfik tasarımdaki güç, davranışları paylaşmaktır.


2
@ user3138436 - Bu doğru. Prototip zinciri, zincirde Kişininkinden getInfodaha yüksek olduğu için Çalışanın ilk oluşumu için incelenecektir . "Geçersiz kılındı" dediğimde kastettiğim buydu.
Travis J

17
Yapıcıyı (Person.call (this, arg)) kullanmıyorsunuz ve Employee prototipini bir Person örneğine ayarlamıyorsunuz. Prototip, paylaşılan üyelerin gittiği yerdir ve yapıcı işlevi, örneğe özgü üyelerin oluşturulduğu yerdir. Örnekleriniz kopyala yapıştır kodunu yeniden yapıcı işlevini kullanır ve prototip parçasını yanlış miras alır (Kişinin, özellikle değişken üyeleriniz varsa Employee.prototype üzerinde hiçbir işi olmayan örneğe özgü üyeleri vardır). Yapıcı işlevlerini ve prototipi kullanarak kalıtım hakkında daha fazla bilgiyi burada bulabilirsiniz: stackoverflow.com/a/16063711/1641941
HMR

3
Çalışan için kişinin getinfo'unu yeniden kullanması ve genişletmesi için basitçe yapabilirsiniz return Person.prototype.getInfo.call(this) + + "and earns " + this.salary + " dollar.";Kopyala yapıştırmak yerine kodu yeniden kullanın.
HMR

3
burada polimorfizm nerede uygulanır?
albert Jegani

2
@rpeg, çok biçimlilik noktası OPs örneğinde daha iyi görülebilir. showInfo () işlevi; genel bir nesneyi kabul eder. polimorfizm artık nesne türüne bağlı olarak farklı tepki verme yeteneğidir. Her belirli nesnede getInfo () 'yu çağırdığı için bu cevabın bunu yeterince netleştirmediğini düşünüyorum.
Stefan

26

Bu diğer cevapta açıklandığı gibi , polimorfizmin farklı yorumları vardır.

Konuyla ilgili okuduğum en iyi açıklama, ünlü bir tip teorisyeni olan Luca Cardelli'nin bir makalesi . Makalenin adı Türleri Anlamak, Veri Soyutlama ve Çok Biçimlilik Üzerine .

Bu ne?

Cardelli, bu makalede çeşitli polimorfizm türlerini tanımlamaktadır:

  • Evrensel
    • parametrik
    • dahil etme
  • Özel
    • aşırı yükleme
    • zorlama

Belki JavaScript'te, polimorfizmin etkilerini görmek biraz daha zordur çünkü daha klasik polimorfizm türleri statik tip sistemlerde daha belirgindir, oysa JavaScript dinamik bir tip sistemine sahiptir.

Bu nedenle, örneğin, JavaScript'te derleme zamanında yöntem veya işlev aşırı yükleme veya otomatik tür zorlaması yoktur. Dinamik bir dilde, bunların çoğunu doğal kabul ediyoruz. Dilin dinamik yapısı nedeniyle JavaScript'te parametrik polimorfizm gibi bir şeye de ihtiyacımız yok.

Yine de JavaScript, Java veya C # gibi diğer nesne yönelimli programlama dillerinde tipik olarak yaptığımıza benzer şekilde aynı alt tip polimorfizm fikirlerini (yukarıda Cardelli tarafından dahil etme polimorfizmi olarak sınıflandırılmıştır) taklit eden bir tür kalıtım biçimine sahiptir ( yukarıda paylaştığım başka bir cevap).

Dinamik dillerde çok tipik olan bir başka polimorfizm biçimine ördek yazımı denir .

Polimorfizmin yalnızca nesne yönelimli programlamayla ilgili olduğuna inanmak bir hatadır. Diğer programlama modelleri (işlevsel, prosedürel, mantık vb.), Muhtemelen yalnızca OOP için kullanılanlara biraz yabancı bir şekilde, kendi tip sistemlerinde farklı polimorfizm biçimleri sunar.

Neden İhtiyacımız Var?

Polimorfizm, diğer şeylerin yanı sıra, yazılımda birçok iyi özelliği teşvik eder, diğer şeylerin yanı sıra, modülerliği ve yeniden kullanılabilirliği teşvik eder ve tip sistemini daha esnek ve şekillendirilebilir hale getirir. Onsuz, türler hakkında mantık yürütmek gerçekten zor olurdu. Polimorfizm, bir ortak arabirimi karşılamaları koşuluyla, bir türün diğer uyumlu olanlarla ikame edilebilmesini sağlar, böylece bu aynı zamanda bilgi gizlemeyi ve modülerliği de teşvik eder.

O nasıl çalışır?

Bu basit bir cevap değil, farklı dillerin bunu uygulamak için farklı yolları var. JavaScript söz konusu olduğunda, yukarıda belirtildiği gibi, prototip kalıtım kullanarak tür hiyerarşileri biçiminde gerçekleştiğini göreceksiniz ve ördek yazmayı kullanarak da bundan yararlanabilirsiniz.

Konu biraz geniş ve tek bir gönderide iki soru açtınız. Belki de en iyisi Cardelli'nin makalesini okuyarak başlamanız ve daha sonra herhangi bir dil veya programlama paradigmasına bakmaksızın polimorfizmi anlamaya çalışmanız, o zaman teorik kavramlar ile JavaScript gibi belirli bir dilin bu fikirleri uygulamak için sunduğu şeyler arasında ilişki kurmaya başlayacaksınız.


14

Polimorfizmin amacı nedir?

Polimorfizm, tip eşdeğerliği koşullarını gevşeterek statik tip bir sistemi (önemli) statik tip güvenliğini kaybetmeden daha esnek hale getirir. Bunun kanıtı, bir programın yalnızca herhangi bir tür hatası içermediğinde çalışacağıdır.

Bir polimorfik fonksiyon veya veri tipi, monomorfik bir fonksiyondan daha geneldir, çünkü daha geniş bir senaryo yelpazesinde kullanılabilir. Bu anlamda polimorfizm, katı şekilde yazılmış dillerdeki genelleme fikrini temsil eder.

Bu, Javascript için nasıl geçerlidir?

Javascript zayıf, dinamik bir tip sistemine sahiptir. Böyle bir tip sistemi, sadece bir tip içeren katı tip sistemle eşdeğerdir. Böyle bir türü büyük bir birleşim türü olarak düşünebiliriz (sözde sözdizimi):

type T =
 | Undefined
 | Null
 | Number
 | String
 | Boolean
 | Symbol
 | Object
 | Array
 | Map
 | ...

Her değer, çalışma zamanında bu tür alternatiflerden biriyle ilişkilendirilecektir. Ve Javascript zayıf bir şekilde yazıldığından, her değer türünü istediğiniz kadar değiştirebilir.

Bir tip teorik perspektifi alırsak ve sadece bir tip olduğunu düşünürsek, Javascript'in tip sisteminin bir polimorfizm kavramına sahip olmadığını kesin olarak söyleyebiliriz. Bunun yerine ördek yazma ve örtük tür zorlama var.

Ancak bu bizi programlarımızdaki türleri düşünmekten alıkoymamalıdır. Javascript'teki türlerin eksikliğinden dolayı, kodlama sürecinde bunları çıkarmamız gerekir. Zihnimiz eksik derleyicinin yerine geçmelidir, yani bir programa bakar bakmaz, sadece algoritmaları değil, aynı zamanda temeldeki (belki polimorfik) türleri de tanımalıyız. Bu türler, daha güvenilir ve daha sağlam programlar oluşturmamıza yardımcı olacaktır.

Bunu düzgün bir şekilde yapabilmek için, size polimorfizmin en yaygın tezahürlerine genel bir bakış sunacağım.

Parametrik polimorfizm (jenerik olarak da bilinir)

Parametrik polimorfizm, farklı türlerin birbirinin yerine geçebileceğini söylüyor çünkü türlerin hiç önemi yok. Parametrik polimorfik tipin bir veya daha fazla parametresini tanımlayan bir fonksiyon, karşılık gelen argümanlar hakkında hiçbir şey bilmemeli, ancak hepsini aynı şekilde ele almalıdır çünkü herhangi bir türe uyarlayabilirler. Bu oldukça kısıtlayıcıdır, çünkü böyle bir işlev yalnızca kendi verilerinin parçası olmayan argümanlarının özellikleriyle çalışabilir:

// parametric polymorphic functions

const id = x => x;

id(1); // 1
id("foo"); // "foo"

const k = x => y => x;
const k_ = x => y => y;

k(1) ("foo"); // 1
k_(1) ("foo"); // "foo"

const append = x => xs => xs.concat([x]);

append(3) ([1, 2]); // [1, 2, 3]
append("c") (["a", "b"]); // ["a", "b", "c"]

Ad-hoc polimorfizm (aka aşırı yükleme)

Ad-hoc polimorfizm, farklı türlerin yalnızca belirli bir amaç için eşdeğer olduğunu söyler. Bu anlamda eşdeğer olması için, bir türün bu amaca özgü bir dizi işlev gerçekleştirmesi gerekir. Ad-hoc polimorfik tipin bir veya daha fazla parametresini tanımlayan bir fonksiyon, daha sonra argümanlarının her biriyle hangi fonksiyon setlerinin ilişkilendirildiğini bilmesi gerekir.

Ad-hoc polimorfizmi, bir işlevi daha geniş bir tür alanıyla uyumlu hale getirir. Aşağıdaki örnek, "eşleme" amacını ve türlerin bu kısıtlamayı nasıl uygulayabileceğini gösterir. Bir işlev kümesi yerine "eşlenebilir" kısıtlaması yalnızca tek bir mapişlevi içerir :

// Option type
class Option {
  cata(pattern, option) {
    return pattern[option.constructor.name](option.x);
  }
  
  map(f, opt) {
    return this.cata({Some: x => new Some(f(x)), None: () => this}, opt);
  }
};

class Some extends Option {
  constructor(x) {
    super(x);
    this.x = x;
  }
};

class None extends Option {
  constructor() {
    super();
  }
};


// ad-hoc polymorphic function
const map = f => t => t.map(f, t);

// helper/data

const sqr = x => x * x;

const xs = [1, 2, 3];
const x = new Some(5);
const y = new None();

// application

console.log(
  map(sqr) (xs) // [1, 4, 9]
);

console.log(
  map(sqr) (x) // Some {x: 25}
);

console.log(
  map(sqr) (y) // None {}
);

Alt tip polimorfizmi

Diğer cevaplar zaten alt tip polimorfizmi kapsadığı için onu atlıyorum.

Yapısal polimorfizm (diğer adıyla strutrual alt tipleme)

Yapısal polimorfizm, farklı türlerin eşdeğer olduğunu, aynı yapıyı bu şekilde içeriyorlarsa, bir türün diğerinin tüm özelliklerine sahip olduğunu ancak ek özellikler içerebileceğini söyler. Bununla birlikte, yapısal polimorfizm derleme zamanında ördek yazmadır ve kesinlikle bazı ek tip güvenliği sunar. Ancak iki değerin sırf bazı özellikleri paylaştıkları için aynı türde olduğunu iddia ederek, değerlerin anlamsal düzeyini tamamen yok sayar:

const weight = {value: 90, foo: true};
const speed =  {value: 90, foo: false, bar: [1, 2, 3]};

Ne yazık ki, speedbir alt türü olarak kabul edilir weightve valueözelliklerini karşılaştırır karşılaştırmaz, elmaları neredeyse portakallarla karşılaştırırız.


1
Bu, birçok bakımdan kabul edilen cevaptan daha doğru (ve kesinlikle daha kapsamlı) olsa da, aynı erişilebilirliğe sahip değildir: bu cevap, soruyu soranın zaten soruyla uğraşamayacak kadar akıllı olduğunu varsaymaktadır :)
Jared Smith

@JaredSmith Konuyu, anlaşılması kolay bazı paragraflara indirgemeye çalıştım. Ama ne kadar derine inersem o kadar karmaşıklaşır. Tiplenmemiş dillerde polimorfizm için hiçbir zaman iyi bir kaynak bulamadım, bu yüzden bu cevabın yine de değerli olduğunu düşünüyorum.

düzenleme, erişilebilirliği büyük ölçüde geliştirir. Çok biçimliliğin dinamik dillerdeki kullanışlılığına gelince, pek çok şey var ama JS'de iyi bir örnek bulmakta zorlanıyorum. Daha iyi bir örnek, Python'un kullanıcı tanımlı türlerin polimorfik işlevlerle çalışmasına izin veren sihirli yöntemleri olabilir.len . Ya da belki conjclojure'dan.
Jared Smith

8

bu ne?

Poli = çok, morfizm = form veya davranış değişimi.

neden ihtiyacımız var?

Programlamada, bir fonksiyonun (diyelim ki fonksiyon X'in) arayüzünün farklı tip veya sayıda parametreyi kabul edecek kadar esnek olmasını istediğimizde kullanılır. Ayrıca, değişen parametre türlerine veya sayılarına bağlı olarak, X işlevinin farklı davranmasını (morfizm) isteyebiliriz.

Nasıl çalışır?

Her uygulamanın farklı parametre türlerini veya parametre sayısını kabul ettiği birden fazla X işlevi uygulaması yazıyoruz. Parametrenin türüne veya sayısına bağlı olarak, derleyici (çalışma zamanında), X bir koddan çağrıldığında hangi X uygulamasının yürütülmesi gerektiğine karar verir.

javascript'te bu polimorfik davranışı nasıl elde edebilirim?

JS yazılı bir dil değildir, bu yüzden gerçekten çok biçimlilik gibi OOP kavramlarını kullanmak anlamına gelmez. Bununla birlikte, JS'nin daha yeni sürümü artık sınıfları içermektedir ve polimosfizmin JS'de de anlam kazanmaya başlaması ihtimali vardır. Diğer yanıtlar bazı ilginç çözümler sağlar.


4

Çok biçimlilik, aynı yöntemi farklı nesnelerde çağırma yeteneği anlamına gelir ve her nesne farklı şekilde yanıt verir, POLYMORPHISM olarak adlandırılır .

    function Animal(sound){
    this.sound=sound;
    this.speak=function(){
    			return this.sound;
    	}
    }
//one method 
    function showInfo(obj){
    		console.log(obj.speak());
    }
//different objects
    var dog = new Animal("woof");
    var cat = new Animal("meow");
    var cow = new Animal("humbow");
//responds different ways
    showInfo(dog);
    showInfo(cat);
    showInfo(cow);


2

JavaScript, yorumlanmış bir dildir, derlenmiş bir dil değildir.

Derleme zamanı Polimorfizmi (veya Statik polimorfizm) Derleme zamanı polimorfizmi, java, c ++ 'da aşırı yöntem yüklemesinden başka bir şey değildir

Dolayısıyla javascript'te yöntem aşırı yüklemesi mümkün değildir.

Ancak Dinamik (çalışma zamanı) polimorfizm, çalışma zamanında var olan polimorfizmdir, bu nedenle javascript'te yöntemi geçersiz kılmak mümkündür.

başka bir örnek de PHP'dir.

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.