Why can't this be a primitive?

天涯浪子 提交于 2019-12-08 19:51:17

问题


I was messing around with JavaScript, and noticed that this can never be a primitive. What am I talking about? Let me explain.

Take this function for example.

function test(){
    return typeof this;
}
test.call('Abc'); // 'object'
test.call(123); // 'object'

They are both 'object', not 'string' or 'number', like I'd expect.

After a bit of confusion (and messing with instanceof), I figured out what's going on. 'Abc' is being coverted to a String object, and 123 is being converted to a Number object.

Anyway, my question is why does this happen, and how do I convert an object back to its primitive?

I know I could use (String)this or (Number)this, but how can I do that if I don't know the type?

EDIT: I was trying to do this:

function element(){
    var $e = $(this),
    $d = $e.closest('div');
}
element.call('#myID');

and it wasn't working. this is a String object, and jQuery just made a collection of objects instead of using the selector to search the DOM.


回答1:


As others noted, it's coerced to an object as per the spec.

Important thing to note is that if you're in strict mode, the coercion doesn't happen.

"use strict";

function test(){
    return typeof this;
}
test.call('Abc'); // 'string'
test.call(123); // 'number'

So the real question is why aren't you using strict? ;-)


As you noted in your comment, you should be able to use .valueOf() if you're supporting implementations that don't support strict mode.

If you're only expecting a String, or if you're also expecting a Number, but you don't mind a numeric String instead, you could do this...

(this + '') // "Abc"
(this + '') // "123"

"but how can I do that if I don't know the type"

If you want to know its type, use the generic toString available on Object.prototype to get the internal [[Class]] property.

Object.prototype.toString.call( this ); "[object String]"
Object.prototype.toString.call( this ); "[object Number]"



回答2:


I found it, ECMAScript 5.1

Function.prototype.call

NOTE The thisArg value is passed without modification as the this value. This is a change from Edition 3, where a undefined or null thisArg is replaced with the global object and ToObject is applied to all other values and that result is passed as the this value.

Basically it says undefined and null as the first parameter cause this to be the global object (window in a browser context), and all other values are converted to an object using ToObject.


Due to the inconsistencies of typeof, I recommend using Object.prototype.toString.call, which returns consistent values in every browser I've tested:

Object.prototype.toString.call('foo') //[object String]
Object.prototype.toString.call(10000) //[object Number]
Object.prototype.toString.call(someFunc) //[object Function]
...etc

you can compare the output in this fiddle




回答3:


The spec says that this is always an object.

Else if Type(thisArg) is not Object, set the ThisBinding to ToObject(thisArg).




回答4:


My understanding is, this makes no sense outside an object-oriented context, it will always be pointing to some object's instance. So by definition it cannot be a primitive.

Also, it seems your test function is returning the typeof the test function itself (which is this in that context), and not of the parameters you're passing.



来源:https://stackoverflow.com/questions/9039121/why-cant-this-be-a-primitive

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!