2010-12-08 22 views
8
var f = function(o){ return this+":"+o+"::"+(typeof this)+":"+(typeof o) }; 
f.call("2", "2"); 
// "2:2::object:string" 

var f = function(o){ return this+":"+(typeof this)+":"+(typeof o); }; 
var x = [1,/foo/,"bar",function(){},true,[],{}]; 
for (var i=0;i<x.length;++i) console.log(f.call(x[i],x[i])); 
// "1:object:number" 
// "/foo/:object:object" 
// "bar:object:string" 
// "function() {\n}:function:function" 
// "true:object:boolean" 
// ":object:object" 
// "[object Object]:object:object" 

Veo los mismos resultados en Chrome, Firefox y Safari, así que supongo que es por the spec, pero ... ¿por qué? ¿Y en qué parte de la especificación se define esto? ¿Y por qué no para las funciones?`¿Por qué typeof this` "objeto" de retorno?

+0

wow, nunca sabía eso. ahora me pregunto por qué es eso también! – Matt

Respuesta

11

Como se define en ECMA-262 especificación del lenguaje ECMAScript 3ª edición (ver nota al pie), que está basado en the spec (Sección 15.3.4.4):

var result = fun.call(thisArg[, arg1[, arg2[, ...]]]); 

Parámetros

thisArg

Determina el valor de esto dentro de la diversión . Si thisArg es nulo o no definido, Este será el objeto global. lo contrario, este será igual a Object (thisArg) (que es thisArg si thisArg ya es un objeto, o una cadena , Boolean, o número si thisArg es un valor primitivo de la tipo correspondiente). Por lo tanto, es cierto que siempre typeof esta == "objeto" cuando la función se ejecuta.

Nota en particular, la última línea.

Lo crucial es que los primitivos js (string, number, boolean, null, undefined) son inmutables, por lo que una función no se puede unir a ellos. Por lo tanto la función de call envuelve el primitivo en un Object modo que la función se puede conectar.

Ej:

No funciona:

var test = "string"; 
//the next 2 lines are invalid, as `test` is a primitive 
test.someFun = function() { alert(this); }; 
test.someFun(); 

Obras:

var test = "string"; 
//wrap test up to give it a mutable wrapper 
var temp = Object(test); 
temp.someFun = function() { alert(this); }; 
temp.someFun(); 

(nota al pie) - patrick dw como se señala en los comentarios, esto cambiará en ECMA-262 ECMAScript Language Specification 5th edition cuando en estricto modo:

De la Sección 15.3.4.4:

NOTA se pasa el valor thisArg sin modificación como este valor. Este es un cambio de la Edición 3, donde undefined o null thisArg se reemplaza con el objeto global y ToObject es aplicado a todos los demás valores y el resultado se pasa como este valor.

+3

Tenga en cuenta que esto cambia a partir de ECMAScript 5. De la Sección 15.3.4.4: * NOTA \t El valor thisArg se pasa sin modificaciones como este valor.Esto es un cambio de la Edición 3, donde una undefined o null thisArg se reemplaza con el objeto global y ToObject se aplica a todos los demás valores y ese resultado se pasa como este valor. * – user113716

+0

Ah ha, eso nos pone en la pista correcta en la especificación ECMAScript-262 rev3. La Sección 15.3.4.4 dice "Si _thisArg_ es ** nulo ** o ** indefinido **, la función llamada pasa el objeto global como ** este ** valor. De lo contrario, la función llamada se pasa' ToObject (thisArg) 'como el ** valor **". El operador 'ToObject' se describe en la sección 9.9. Básicamente usar 'call' con un número es como pasar 'new Number (42)', para lo cual 'typeof' produce' "object" '. ¡Gracias! – Phrogz

+0

@patrickdw Excelentes noticias sobre el cambio, gracias por la nota! – Phrogz

Cuestiones relacionadas