2013-07-15 13 views
10

Używam zamknięcia do tworzenia obiektów metodami prywatnymi i publicznymi. Wygląda na to -Czy możesz dziedziczyć funkcje prywatne w JavaScript?

var Dog = (function() { 
    function Dog() {} 

    var size = 'big'; 

    var _privateSaySize = function() { 
     return 'I am a ' + size + ' dog.'; 
    } 

    Dog.prototype.publicSaySize = function() { 
     return _privateSaySize(); 
    } 

    return Dog; 
})(); 

Ale teraz chciałbym mieć obiekt, który ma tylko prywatne funkcje i jest dziedziczony przez inny obiekt. Ale czy jest to możliwe w JavaScript?

+1

Co to jest 'funkcja Dog = (function() {})()'? – Amberlamps

+2

'private' członkowie są widoczni _only_ wewnątrz klasy, gdzie są zdefiniowani w _any_ języku, który obsługuje OOP. Nie dostaję tego, co próbujesz zrobić. – Leri

+0

Generalnie nie, ale twoja "prywatna funkcja" jest łatwo dostępna poprzez 'notSoPrivateSaySize = new Dog().publicSaySize(); ' – Bergi

Odpowiedz

1

Chcesz, aby jedna instancja dziedziczyła stan prywatny innej instancji? Oczywiście możesz to zrobić w JavaScript. Najpierw musimy zdefiniować funkcję użytkową:

function weakBind(functable, prototype, state) { 
    return function() { 
     return functable.apply(this, Object.getPrototypeOf(this) === prototype ? 
      [state].concat(Array.prototype.slice.call(arguments)) : arguments); 
    }; 
} 

Teraz możemy stworzyć naszą klasę bazową, co następuje:

var Dog = (function() { 
    function Dog() { 
     if (this instanceof Dog) { 
      // constructor code 
     } else return Object.create(private); 
    } 

    var public = Dog.prototype, private = Object.create(public, { 
     size: { 
      value: "big" 
     } 
    }); 

    public.saySize = weakBind(function (private) { 
     return "I am a " + private.size + " dog."; 
    }, public, private); 

    return Dog; 
}()); 

Teraz można tworzyć psa następująco:

var dog = new Dog; 
alert(dog.saySize()); // I am a big dog. 
alert(dog.size);  // undefined 

Mamy może dziedziczyć stan prywatny w następujący sposób:

var Chihuahua = (function() { 
    function Chihuahua() { 
     Dog.call(this); 
    } 

    var private = Dog(); 

    Object.defineProperty(private, { 
     size: { 
      value: "small" 
     } 
    }); 

    var public = Chihuahua.prototype = Object.create(Dog.prototype); 

    public.saySize = weakBind(public.saySize, public, private); 

    return Chihuahua; 
}()); 

Teraz można utworzyć chihuahua następująco:

var chi = new Chihuahua; 
alert(chi.saySize()); // I am a small dog. 
alert(chi.size);   // undefined 

Zobacz Demo: http://jsfiddle.net/b3Eyn/

Uwaga: Napisałem tę odpowiedź, żeby pokazać, że jest możliwe, aby odziedziczyć stan prywatny w JavaScript. Jednak radziłbym nie używać tego wzoru. Jeśli dobrze zaprojektujesz swój kod, nie będziesz musiał w pierwszej kolejności dziedziczyć stanu prywatnego.

8

Nie, nie możesz.

Dziedziczenie JavaScript jest oparte na prototypach, więc można "rozszerzyć" tylko metody w prototypie.

+0

Uzgodnione. Chociaż warto zauważyć, że wielu deweloperów JS idzie na kompromis, po prostu prefiksem innych publicznych metod z podkreśleniem sygnalizującym, że są one chronione lub w inny sposób nie są częścią publicznego interfejsu API. Programiści mogą je modyfikować, jeśli chcą, ale to jest własne ryzyko. Szczerze mówiąc, próba zabezpieczenia publicznie dostępnego obiektu w JS jest dość daremnym przedsięwzięciem, ponieważ każdy, kto korzysta z twojej biblioteki, może po prostu nadpisać jakąkolwiek publiczną funkcjonalność, lub nawet współużytkować współużytkowane obiekty/prototypy. Po prostu nie wydaje się warte bólu głowy. –

2

Rodzaj ... Jak wskazuje Bergi, dostęp jest zdefiniowany przez zakres, więc jeśli zdefiniujesz dziedzica w bezpośrednim otoczeniu rodzica, możesz uzyskać z grubsza to, co chcesz.

var BarkingDog; 
var Dog = (function() { 
    function Dog() {} 

    var size = 'big'; 

    var _privateSaySize = function() { 
     return 'I am a ' + size + ' dog.'; 
    }; 

    Dog.prototype.publicSaySize = function() { 
     return _privateSaySize(); 
    }; 

    BarkingDog = (function() { 
     function BarkingDog() {} 

     var say = 'woof'; 

     BarkingDog.prototype = new Dog(); 

     BarkingDog.prototype.bark = function() { 
      return _privateSaySize() + ' ' + say; 
     }; 

     return BarkingDog; 

    })(); 

    return Dog; 
})(); 

var myDog = new BarkingDog(); 
console.log(myDog.bark()); 
console.log(myDog.publicSaySize()); 

Nie wiesz, dlaczego chcesz, aby chociaż ...: D

5

Prywatność zmiennych (funkcji) w JavaScript odbywa się za pomocą zakresów funkcyjnych. Możesz uzyskać do nich dostęp z zewnątrz tylko wtedy, gdy są eksportowane z zakresu zamknięcia, nie ma innego sposobu.

Aby obiekt, którego metody mają dostęp do funkcji prywatnych, wystarczy umieścić go w tym samym zakresie. To, czy obiekt jest tym, który dziedziczy po innych przedmiotach, jest zupełnie nieistotne.

function Dog() {} 
function Dalmatian() {} 
Dalmation.prototype = Object.create(Dog.prototype); 
Dalmation.prototype.size = "big"; 
function Dackel() {} 
Dackel.prototype = Object.create(Dog.prototype); 
Dackel.prototype.size = "small"; 

(function() { 
    // private function 
    function say(s) { 
     console.log("I'm a "+s+" dog"); 
    } 
    // both accessible from the Dog and Dackel public methods 
    Dog.prototype.saySize = function() { 
     say(this.size || "normal"); 
    }; 
    Dackel.prototype.saySize = function() { 
     say(this.size + " but loud"); 
    }; 
})(); 
new Dog().saySize(); 
new Dalmatian().saySize(); 
new Dackel().saySize(); 
0

Można uniknąć użycia notacji kropkowej. Ale to nie jest naprawdę prywatne.

var Dog = (function() { 
    function Dog() {} 

    var size = 'big'; 

    Dog.prototype['-privateSaySize'] = function() { 
     return 'I am a ' + size + ' dog.'; 
    } 

    Dog.prototype.publicSaySize = function() { 
     return this['-privateSaySize'](); 
    } 

    return Dog; 
})() 
+0

Aby określić "wewnętrzność" właściwości, podkreślenie "_" nie jest używane jako minus. W ten sposób można uniknąć zapisu nawiasów ... – Bergi

+0

@Bergi Właśnie o to chodzi. Użyłem minus, ponieważ w ten sposób nie można korzystać z notacji kropkowej, więc jest ona dostępna tylko przy użyciu notacji nawiasów. – boskop

+0

A jak to pomaga? [Konwencja ma używać podkreśleń] (http://stackoverflow.com/q/4484424/1048572) dla oznaczenia prywatności. Notacja nawiasów nic nie zmienia. – Bergi

Powiązane problemy