【问题标题】:Why can't this be a primitive?为什么这不能是原始的?
【发布时间】:2012-01-27 19:46:02
【问题描述】:

我在玩 JavaScript,并注意到 this 永远不可能是原始的。我在说什么?让我解释一下。

以这个函数为例。

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

他们都是'object',而不是'string''number',就像我预期的那样。

经过一番困惑(并与instanceof 混淆)后,我弄清楚了发生了什么。 'Abc' 被转换为String 对象,123 被转换为Number 对象。

无论如何,我的问题是为什么会发生这种情况,以及如何将对象转换回其原始对象?

我知道我可以使用(String)this(Number)this,但如果我不知道类型怎么办?

编辑:我试图这样做:

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

它没有工作。 this 是一个String 对象,jQuery 只是制作了一个对象集合,而不是使用选择器来搜索 DOM。

【问题讨论】:

  • 它可能在规范中某处es5.github.com
  • 哇,这不是我所期望的。
  • 顺便说一句,您的element 函数完全不需要使用this。这太棘手了,为自己好。 function element(selector) 显然会避免这整件事。
  • @AlexWayne:我可能应该那样做:-P

标签: javascript jquery object primitive


【解决方案1】:

正如其他人指出的那样,它被强制转换为符合规范的对象。

需要注意的重要一点是,如果您处于严格模式,则不会发生强制。

"use strict";

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

所以真正的问题是你为什么不使用 strict? ;-)


正如您在评论中指出的那样,如果您支持不支持严格模式的实现,您应该可以使用 .valueOf()

如果您只期望一个字符串,或者如果您还期望一个数字,但您不介意数字字符串,您可以这样做...

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

"但是如果我不知道类型怎么办"

如果您想知道它的类型,请使用Object.prototype 上可用的通用toString 来获取内部[[Class]] 属性。

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

【讨论】:

  • @Rocket:大概是为了给用户期望的价值。严格模式真的不会过多地使用this。如果你刚刚做了test(),那么this 将是undefined 而不是全局对象。
  • @zzzzBov:好点。 @Rocket 的 .valueOf() 解决方案应该可以工作。 ...或者如果总是需要一个字符串,请执行(this + '')
  • 是的,在 IE 中测试 this fiddle(不支持 "use strict")不会产生预期的结果。
  • @Rocket:我建议您仍然使用 strict,但不要依赖仅在 strict 中有效的技术。换句话说,使用严格,但要保持兼容。
  • @amnotiam:我只需要this 是一个字符串,因为我使用的是$(this)。如果 this 是一个对象,jQuery 会返回一个对象集合(即使它是一个 String 对象),它不会进行 DOM 查找。 $(this+'') 工作正常。再次感谢:-)
【解决方案2】:

我找到了,ECMAScript 5.1

Function.prototype.call

注意 thisArg 值未经修改作为this 值传递。这是对第 3 版的更改,其中 undefinednull thisArg 被替换为全局对象,ToObject 应用于所有其他值,并将结果作为 this 值传递。

基本上它说undefinednull作为第一个参数导致this成为全局对象(window在浏览器上下文中),所有其他值都使用ToObject转换为对象。


由于typeof 的不一致,我建议使用Object.prototype.toString.call,它在我测试过的每个浏览器中都会返回一致的值:

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

【讨论】:

  • 至少这是记录在案的,并不是什么奇怪的行为 :-)
  • 感谢Object.prototype.toString.calltypeof 只是返回'object'。这稍微有用:-)
  • 有没有办法只获取类型(没有[object...),还是应该只获取Object.prototype.toString.call('foo').match(/\[object (.*)\]/)[1]
  • 您可以使用哈希来存储您想要的值转换:jsfiddle.net/SdN2n/3 我通常只检查 thetype === '[object Array]' 或我需要检查的任何类型。
【解决方案3】:

spec says 表示 this 始终是一个对象。

如果 Type(thisArg) 不是 Object,则将 ThisBinding 设置为 ToObject(thisArg)。

【讨论】:

  • 似乎严格模式不调用ToObject(正如“我不是”指出的那样)。
【解决方案4】:

我的理解是,this 在面向对象的上下文之外毫无意义,它总是指向某个对象的实例。所以根据定义,它不能是原始的。

此外,您的测试函数似乎返回了 typeof test 函数本身(在该上下文中为 this),而不是您传递的参数。

【讨论】:

  • 我在函数内部使用call设置this
  • 呃,对不起,你是对的,我没有注意到。但是,我仍然认为将原语分配给this 会很奇怪(因为我在回答的第一句话中所说的)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-23
  • 1970-01-01
  • 2016-01-12
相关资源
最近更新 更多