2015-05-22 28 views
5

Ten article definiuje instanceof jak poniżej:Javascript: Still mylić przez operatora instanceof

testy operatorskie

instanceof czy obiekt posiada w swoim prototypem łańcucha własności prototypu konstruktora.

To rzetelne wyjaśnienie, a życie było dobre, aż natknąłem tego kodu z książki Eloquent javascript:

function TextCell(text) { 
 
    this.text = text.split("\n"); 
 
} 
 

 
TextCell.prototype.minWidth = function() { 
 
    return this.text.reduce(function(width, line) { 
 
    return Math.max(width, line.length); 
 
    }, 0); 
 
} 
 

 
TextCell.prototype.minHeight = function() { 
 
    return this.text.length; 
 
} 
 

 
TextCell.prototype.draw = function(width, height) { 
 
    var result = []; 
 
    for (var i = 0; i < height; i++) { 
 
    var line = this.text[i] || ""; 
 
    result.push(line + repeat(" ", width - line.length)); 
 
    } 
 
    return result; 
 
} 
 

 
function RTextCell(text) { 
 
    TextCell.call(this, text); 
 
} 
 

 
RTextCell.prototype = Object.create(TextCell.prototype); 
 

 
RTextCell.prototype.draw = function(width, height) { 
 
    var result = []; 
 
    for (var i = 0; i < height; i++) { 
 
    var line = this.text[i] || ""; 
 
    result.push(repeat(" ", width - line.length) + line); 
 
    } 
 
    return result; 
 
};

Stwórzmy wystąpienie RTextCell i wykonać poniżej c

var rt = new RTextCell("ABC"); 
console.log(rt instanceof RTextCell); // true 
console.log(rt instanceof TextCell); // true 

Rozumiem, dlaczego dane wyjściowe drugiego pliku console.log są "prawdziwe" - ponieważ konstruktor TextCell jest częścią łańcucha prototypów.

Jednak 1. console.log myli mnie.

Jeśli spojrzysz na kod (dziesiąta linia od dołu), prototyp RTextCell zostanie zaktualizowany do nowego obiektu, którego prototyp jest ustawiony na TextCell.prototype.

RTextCell.prototype = Object.create(TextCell.prototype);.

Patrząc na migawki poniżej, nie ma wzmianki o konstruktorze "RTextCell" w prototypowym łańcuchu obiektu "rt". Więc, idąc za definicją, o której wspomniałem na początku mojego postu, czy wynik nie powinien być fałszywy? Dlaczego zwraca prawdziwą wartość?

Czytałem również this, ale nie pomogło mi zrozumieć tego konkretnego problemu.

Zobacz poniżej migawki rt, RTextCell, TextCell w tej kolejności.

snapshot of "rt" snapshot of RTextCell snapshot of TextCell

+0

To naprawdę dobrze skonstruowane pytanie. Pokazałeś wszystkie swoje poprzednie dochodzenie, masz nadzieję, że otrzymasz bardzo dobre odpowiedzi. –

+0

Oh! Powinienem dodać. Sprawdziłem to drzewo prototypów w powyższych migawkach w obu wersjach chrome 43.0.2357.65 i firefox 33.1.1. – Harish

Odpowiedz

1

Dokładne sformułowanie jest ważne. Mówisz o konstruktorze będącej w łańcuchu prototypów, ale oryginalny cytat nie:

instanceof testy operatorskie czy obiekt posiada w swojej prototyp łańcucha własnością prototyp z konstruktora.

Więc wyrażenie rt instanceof RTextCell rzeczywiście testuje coś takiego (pamiętając, że __proto__ nie jest standardem):

var p = rt.__proto__; 
while(p) 
{ 
    if(p == RTextCell.prototype) 
    return true; 
    p = p.__proto__; 
} 
return false; 

Więc nawet jeśli funkcja RTextCell nie odwołuje się bezpośrednio na drzewach obiektów powyżej, Obiektem jest obiekt RTextCell.prototype.

+0

lub w pojedynczym wyrażeniu, 'RTextCell.prototype.isPrototypeOf (rt)' :-) – Bergi

+0

@Cark Falcon: Wcześniej byłem zdezorientowany na instanceof operator i isPrototypeOf() i kiedy spojrzałem na słowo "constructor" w definicji na Witryna MDN całkowicie mnie źle zrozumiała. Twoja odpowiedź zmusiła mnie do zatrzymania się na chwilę i uświadomiłem sobie, co przegapiłem. "Treść". Teraz ma sens. A ja po prostu przeczytałem [this]. (Http://stackoverflow.com/questions/18343545/javascript-isprototypeof-vs-instanceof-usage) dla różnicy między instanceof i isPrototypeOf(). Dzięki stary. – Harish

1
obj instanceof RTextCell 

RTextCell.prototype testuje, czy obecny jest w łańcuchu prototypu obj. To dlatego, że obiekt został wykonany przy użyciu nowego RTextCell. Fakt, że RTextCell.prototype ma swój prototypowy TextCell.prototype, nie ma tu znaczenia i wydaje się, że cię rzuca.

RTextCell.prototype = Object.create(TextCell.prototype); 

nie pozbyć RTextCell.prototype, to wciąż przedmiot, ale to prototyp bywa TextCell.prototype.

4

Zmieniasz RTextCell.prototype, ale zmieniasz go przed konstruujesz wszystkie instancje . Rozważmy następujący masowo inny przykład, gdzie RTextCell.prototype jest modyfikowana po instancja jest tworzona z oryginalnego prototypu:

var rt = new RTextCell(); 
RTextCell.prototype = somethingTotallyDifferent; 
rt instanceof RTextCell; // false! 

Kiedy rt jest tworzony, prawdą jest, że rt.__proto__ === RTextCell.prototype. Po zmianie RTextCell.prototype przestaje być prawdziwe.

Nie testujemy jeśli rt ma oryginalnyprototype właściwość z RTextCell w łańcuchu prototypów. Zamiast tego testujesz, czy wartość RTextCell.prototypeteraz istnieje w łańcuchu prototypów obiektu. Będzie to zawsze prawdziwe w przypadku instancji RTextCell, ponieważ instancje tworzone przez konstruktor RTextCell zawsze pobierają bieżącą wartość RTextCell.prototype w łańcuchu prototypów, a po rozpoczęciu konstruowania nie zmienia się RTextCell.prototype.

+0

Poza odpowiedzią z @Dark Falcon pomógł mi twój przykład dotyczący ustawienia prototypu na "coś całkowicie odmiennego". To ma sens. Dzięki. – Harish