var isSafari = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0;
有谁能告诉我上面的代码在做什么?
答案 0 :(得分:4)
让我们分解一下:
Object.prototype
这为我们提供了JavaScript对象,它是Object
变量的原型。什么是原型?请允许我引用Yehuda Katz的优秀blog post(非常值得一读):
如果您尝试在对象上查找某个键并且找不到该键, JavaScript将在原型中查找它。它将随之而来 “原型链”,直到它看到一个空值。在这种情况下, 它返回undefined。
接下来,我们有:
Object.prototype.toString
这将返回toString
原型上的Object
函数。可以使用call
函数调用JavaScript函数。这里有几个例子:
Object.prototype.toString.call("foo") # => "[object String]"
Object.prototype.toString.call(5) # => "[object Number]"
因此它基本上只是一个通用的toString函数,它返回一个字符串,描述你作为call
参数提供的内容。请注意,在这些示例中,参数是对象本身,因此它们返回将自身描述为对象的字符串。如果我们通过window.HTMLElement
怎么办?
Object.prototype.toString.call(window.HTMLElement) # => "[object HTMLElementConstructor]"
所以现在我们看到它返回一个包含子串"Constructor"
的字符串,这意味着它可能是一个构造HTML元素的对象。最后,我们可以理解完整的表达方式:
Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') # => 19
由于"Constructor"
是子字符串,indexOf
返回19,即> 0.所以基本上,这个表达式似乎检查window.HTMLElement
是否使用后缀“Constructor”来标识自己,我猜这可能是某种浏览器识别检查。
(注意:在写这篇文章时,我测试了使用Safari的Web Inspector控制台评估这些表达式,但你也可以使用Chrome或其他浏览器的控制台来测试这样的事情。)
答案 1 :(得分:2)
Object
是(几乎)javascript中所有类型都继承的类(构造函数)。Object.prototype
是可以在几乎所有对象的原型链中找到的对象。Object.prototype.toString
是在不覆盖它的对象上调用的方法。.call
,在函数上调用时,以第一个参数作为上下文调用该函数。 func.call(a)
与a.func=func; a.func()
类似。不同之处在于,虽然undefined.toString()
是TypeError
,但Object.prototype.toString.call(undefined)
的效果非常好。HTMLElement
是HTML元素继承的类。但是,规范并不要求这样做,在Internet Explorer中也不是这样,因为HTML元素没有原型,并且那里不存在HTMLElement
构造函数。由于window
是浏览器环境中的全局对象,window.HTMLElement
与HTMLElement
相同,如果未被局部变量遮蔽,如果> em>它存在。如果不存在,则在HTMLElement
返回ReferenceError
时,阅读window.HTMLElement
会引发undefined
。Object.prototype.toString.call(window.HTMLElement)
与HTMLElement.toString()
相同,除了它在IE中有效并使用了正确的toString
。它始终返回String
。indexOf
是一个String函数,它查找其子字符串的第一个出现,如果子字符串不存在则返回-1
。 .indexOf('Constructor') > 0
检查字符串是否包含"Constructor"
,但不包括toString
。 因此,此方法会在"Constructor"
上调用时确定HTMLElement
是否包含HTMLElement
。 The specification mandates that:
...
4)让class为O的[[Class]]内部属性的值 5)返回String值,该值是连接三个字符串“[object”,class和“]”的结果。
因此,这会检查[[class]]
的{{1}}是否为Constructor
。
最后,将检查结果分配给变量isSafari
。这表明这是真实的环境。此代码的作者假定返回值在Safari中,每个Safari版本中都包含"Constructor"
,并且仅在Safari中。
作为参考,在Chrome中,Object.prototype.toString.call(HTMLElement)
会返回"[object Function]"
。