2013-07-06 9 views
7

Ten kod zgłasza błąd.Metoda Call.prototype obiektu na Global Scope

try { 
    alert(hasOwnProperty('window')); 
} catch(e) { 
    alert(e); // Type Error : can't convert undefined to object 
} 

ale ten kod nie zgłasza błędu.

try { 
    alert(this.hasOwnProperty('window')); // true (if on browser) 
} catch(e) { 
    // through catch block 
    alert(e); 
} 

Live Example | Live Source

Jeśli chodzi o I kwon, func(arg) jest równa this.func(arg), jeśli this jest globalnym obiektem. Dlaczego coś takiego się dzieje?

+1

* "O ile mi Kwon' func (arg) 'jest równe' this.func (Arg) 'jeśli to jest obiekt globalny." * Nie, to nie jest poprawne, ale jeśli kod działa w zasięgu globalnym, a nie jesteś w trybie ścisłym, może się to wydawać trochę podobne. –

+1

Naprawdę fascynujące pytanie. –

Odpowiedz

8

Myślę, że mamy interakcję kodu trybu ścisłego i kodu trybu nie ścisłego. I faktycznie, kiedy wykopałem kopię Firefoksa 3.6.15 (która nie obsługuje trybu ścisłego), nie dostaję błędu za pomocą linku, który zamieściłem na twoim pytaniu (dwa razy ostrzeże "prawda").

Podany kod jest oczywiście nie-ścisłym kodem trybu. Ale co z implementacją przeglądarki w wersji hasOwnProperty? Podejrzewam, że jest to ścisłe, w przeglądarkach, w których obsługiwany jest tryb ścisły.

Kiedy mówisz

func(); 

... co robi przeglądarka jest patrzeć func stosując standardową rozdzielczość identyfikator, a następnie wywołać ją tak, jakbyś to zrobił:

func.call(undefined); 

Jeśli func jest funkcja trybu swobodnego, a następnie w ramach wywołania func, this jest obiektem globalnym. Ale, jeśli func jest funkcją trybu ścisłego, this w ramach połączenia to undefined.

W przeciwieństwie do tego, z tego:

this.func(); 

... to znowu patrzy func (tym razem za pośrednictwem rozdzielczości mienia przy użyciu łańcucha prototypów), a następnie skutecznie robi to:

this.func.call(this); 

W tryb ścisły lub luźny, co oznacza, że ​​w ramach tej funkcji będzie thisthis. (I oczywiście w skali globalnej obiekt globalny to this.)

Oto przykład tej interakcji przy użyciu kodu widzimy zamiast hasOwnProperty:

(function() { 
    "use strict"; 

    window.strictFunction = function() { 
    display("strictFunction: this === window? " + 
      (this === window)); 
    display("strictFunction: typeof this: " + 
      typeof this); 
    }; 

})(); 

strictFunction(); 
strictFunction.call(undefined); 

Jak widać, to luźne kod z wyjątkiem bitu wyznaczającą strictFunction funkcję window. Potem mamy zadzwonić pod numer , który działa dwa razy od luźnego kodu. Rezultat jest taki:

strictFunction: this === window? false 
strictFunction: typeof this: undefined 
strictFunction: this === window? false 
strictFunction: typeof this: undefined

W przeciwieństwie do tego, jeśli zrobimy z luźnym funkcji, wynik jest:

looseFunction: this === window? true 
looseFunction: typeof this: object 
looseFunction: this === window? true 
looseFunction: typeof this: object

Kompletny przykład: Live Copy | Live Source

<!DOCTYPE html> 
<html> 
<head> 
<meta charset=utf-8 /> 
<title>Fun With Strict Interactions</title> 
    <style> 
    body { 
     font-family: sans-serif; 
    } 
    p { 
     margin: 0; 
    } 
    </style> 
</head> 
<body> 
    <script> 
    (function() { 
     "use strict"; 

     window.strictFunction = function() { 
     display("strictFunction: this === window? " + 
       (this === window)); 
     display("strictFunction: typeof this: " + 
       typeof this); 
     }; 

    })(); 
    (function() { 

     window.looseFunction = function() { 
     display("looseFunction: this === window? " + 
       (this === window)); 
     display("looseFunction: typeof this: " + 
       typeof this); 
     }; 

    })(); 

    display("Direct call:"); 
    strictFunction(); 
    looseFunction(); 

    display("<hr>Call with <code>.call(undefined)</code>:"); 
    strictFunction.call(undefined); 
    looseFunction.call(undefined); 

    display("<hr>Call with <code>.call(window)</code>:"); 
    strictFunction.call(window); 
    looseFunction.call(window); 

    function display(msg) { 
     var p = document.createElement('p'); 
     p.innerHTML = String(msg); 
     document.body.appendChild(p); 
    } 
    </script> 
</body> 
</html> 

Output (stosując silnik JavaScript, który obsługuje tryb ścisły):

Direct call: 
strictFunction: this === window? false 
strictFunction: typeof this: undefined 
looseFunction: this === window? true 
looseFunction: typeof this: object 
-- 
Call with .call(undefined): 
strictFunction: this === window? false 
strictFunction: typeof this: undefined 
looseFunction: this === window? true 
looseFunction: typeof this: object 
-- 
Call with .call(window): 
strictFunction: this === window? true 
strictFunction: typeof this: object 
looseFunction: this === window? true 
looseFunction: typeof this: object
+0

Dzięki wszystkim odpowiedzi! Zrozumiałem wszystkie problemy. –

+1

Dobra robota ... To naprawdę coś, o czym warto pamiętać i kolejny powód, dla którego powinniśmy próbować pisać kod tak blisko jak to tylko możliwe do trybu ścisłego, nawet jeśli nie jesteśmy w trybie ścisłym w naszych skryptach. +1 –

1

Problem dotyczy jednego z kontekstu. To znaczy, w istocie, jaka jest wartość wartości wewnątrz funkcji po jej wywołaniu.

Wywołanie hasOwnProperty('window') nie ma kontekstu. To jest taka sama jak w ten sposób:

hasOwnProperty.call(undefined, 'window'); 

Zważywszy this.hasOwnProperty('window') jest takie samo jak to zrobić:

hasOwnProperty.call(this, 'window'); 

Druga linia kodu będzie miał wyjścia można oczekiwać (true), ale pierwszy oczywiście nie będzie działać.

+1

Zauważ, że jeśli nie używasz trybu ścisłego, 'hasOwnProperty.call (undefined, 'window')' jest efektywnie 'hasOwnProperty.call (window, 'window')'. Jeśli wywołasz funkcję bez jawnego ustawienia 'this' (lub przekazania' undefined' lub 'null' do' call' lub 'apply '), poza trybem ścisłym,' this' jest obiektem globalnym. (A jednak tak nie jest, jak się zachowuje - http://jsbin.com/iquhes/7/edit - a więc jest coś w grze, po prostu nie całkiem się to dostaję.) –

+1

Ha! Świetna robota. Zastanawiałem się, dlaczego zdefiniowano 'hasOwnProperty', ale * call * zawodzi. JS i konteksty mogą być naprawdę fascynujące. – Matchu

+0

@ T.J.Crowder W tym przypadku, przyznaję, że jestem trochę zakłopotany. Ponieważ tryb ścisły z pewnością * nie jest * włączony. – lonesomeday