2015-11-09 16 views
5

Czy możliwe jest zdefiniowanie prototypu tylko dla {} -Objects?Definiowanie prototypu tylko dla obiektów {...}

W JavaScript prawie wszystko jest przedmiotem.

Object.prototype.test = function() { 
    alert("test"); 
} 

Wszystkie obiekty (w tym numer, String i Array) będzie miał tej metody. Ale chcę tego tylko dla obiektu struct. > {...} <

Najpierw można utworzyć wszystkie prototypy obiektu i usunąć je z innych, takich jak liczba, ciąg i macierz.

// Overwrite 
Array.prototype.test = undefined; // or delete property 

To "działa" ... Prototyp jest nadpisywany. Ale klucz nadal istnieje.

// Show all keys 
for (key in arr) 
{ 
    alert(key); // print index of array AND keynames 
} 

Szukam najbardziej eleganckiego sposobu na zrobienie tego.

+4

Nie zmodyfikować 'prototyp Object' chyba że masz zamiar za nieruchomość mają być dostępne na każdym obiekcie, którym stwierdził, że nie chcesz. Niezależnie od tego modyfikowanie prototypu 'Object' jest prawie zawsze złym pomysłem. Zamiast tego powinieneś umieścić właściwość na prototypie jakiejś klasy, którą kontrolujesz, i dziedziczyć ją w razie potrzeby. –

+0

Usunięcie właściwości z prototypu 'Array' również nie spowoduje tego, co chcesz. Wywołanie 'testu' na tablicy nadal będzie działało, ponieważ przejdzie do łańcucha prototypów i proste wywołanie' testu' na prototypie 'Object': http://jsfiddle.net/x2wysox8/ –

+0

nie usuwaj właściwości 'test' z' Array.prototype', wystarczy rzucić błąd na połączenie, jeśli chcesz ograniczyć dostęp do metody 'Object.prototype.test'. Ale dodawanie metod do 'Object.prototype' jest złą praktyką i pomyślcie dwa razy, zanim zrobicie to. –

Odpowiedz

0

z Array.prototype.test = undefined; możesz ustawić wartości zestawów na undefinied, a to nie usunie go.

Jeśli naprawdę chcesz usunąć metodę (właściwość) używać delete Array.prototype.test;

PS: Ale w tym przypadku (z obiektem {}) -> nie można uzyskać tego, co chcesz z delete.

Array.prototype jest dziedziczona z Object.prototype, a po usunięciu Array.prototype.test kod znajdzie Object.prototype.test i nazwać.

Myślę, że najlepszym sposobem, aby to, co chcesz zrobić coś takiego:

Object.defineProperty(Object.prototype, 'test', { 
    enumerable: false, 
    configurable: false, 
    writable: true, 
    value: function(test) { alert('In test' + test); } 
}); 

Object.defineProperty(Array.prototype, 'test', { 
    enumerable: false, 
    configurable: false, 
    writable: false, 
    value: function() { throw new Error('You can\'t do it!'); } 
}); 

try { 
    var a = []; 
    var keys = ""; 

    for (key in a) { 
     keys += key + ', '; // get all keys 
    } 
    // call array test method -> will throw exception 
    a.test('from array'); 

} catch (e) { 
    // check keys -> test is not here 
    console.log("Error: " + e.message + ' ' + "KEYS: " + keys); 
} 

var b = {}; 
// and this will work 
b.test('from object'); 
+2

Nie uniemożliwi to wywołania 'test' na' Tablicy'. Łańcuch prototypowy znajdzie funkcję 'test' na prototypie' Object' i wywoła: http://jsfiddle.net/x2wysox8/ –

0

Dobrze chociaż można zmienić prototypu przedmiotu, jest wysoce niezalecane. Dzieje się tak dlatego, że wszystkie biblioteki, z których kiedykolwiek korzystasz, oczekują, że Obiekt zostanie nietknięty. Może to bardzo utrudnić wykrywanie błędów i nieoczekiwanych zachowań niektórych bibliotek.

Potrzebne jest, aby nauczyć się prawidłowej orientacji obiektu w JS. To bardzo mylący temat dla początkujących js. Zapraszam do lektury znakomitego "Zasad Zorientowanego na Obiekt JavaScript" od Nicolasa Zakasa i serii książek "Nie wiem JS" od Kyle'a Simpsona.

Ale można mieć dobry start z mojego wyjaśnienia, w jaki sposób zrobić obiektu Orientacja w javascript w moim blogu: http://www.ideasaboutcode.com/object-orientation-in-javascript/

nadzieję, że to pomaga.

2

Niemal na pewno nie chcesz modyfikować prototypu Object. Ten MDN article on JavaScript inheritance podsumowuje to ładnie:

Jedną z nieprawidłowych funkcji, które są często używane, jest rozszerzenie Object.prototype lub jednego z innych wbudowanych prototypów.

Ta technika nosi nazwę łatania małp i łamie hermetyzację. Chociaż używane przez popularne frameworki takie jak Prototype.js, wciąż nie ma dobrego powodu do zaśmiecania wbudowanych typów dodatkowymi niestandardowymi funkcjami.

W tym przykładzie usunięcie właściwości test z Array nie przyniesie oczekiwanego efektu. Po wywołaniu Array.test, po prostu przeszuka łańcuch prototypów i wykona Object.test. Zilustrowano to następującym kodem:

Object.prototype.test = function() { 
    alert('In test'); 
} 

delete Array.prototype.test; 

//Calls Object.test and shows the alert 
[].test(); 

Zamiast tego można utworzyć klasę bazową, którą kontrolujesz i dziedziczysz w razie potrzeby. Zobacz demonstrację roboczą.

function MyBaseClass() { 
 
    this.test = function() { 
 
    log('In test'); 
 
    }; 
 
} 
 

 
function Shape() { 
 
    this.shapeAction = function() { 
 
    log('Shape action'); 
 
    }; 
 
} 
 

 
Shape.prototype = new MyBaseClass(); 
 

 
function Square() { 
 
    this.squareAction = function() { 
 
    log('Square action'); 
 
    this.shapeAction(); 
 
    }; 
 
} 
 

 
Square.prototype = new Shape(); 
 

 
//Test function can be called on Square, but not on Array 
 
var s = new Square(); 
 

 
s.squareAction(); 
 
s.shapeAction(); 
 
s.test(); 
 

 
try { 
 
    [].test(); 
 
} 
 
catch (e) { 
 
    log('Exception when trying to run Array.test: ' + e); 
 
} 
 

 
//Log function for demonstration purposes 
 
function log(s) { 
 
    var e = document.createElement('p'); 
 
    e.innerHTML = s; 
 
    document.body.appendChild(e); 
 
}