var isSafari = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0;
谁能告诉我上面的代码在做什么?
var isSafari = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0;
谁能告诉我上面的代码在做什么?
让我们分解一下:
Object.prototype
这为我们提供了作为Object
变量原型的 JavaScript 对象。什么是原型?请允许我引用 Yehuda Katz 的优秀博文(非常值得一读):
如果您尝试查找对象上的键但未找到,JavaScript 将在原型中查找它。它将遵循“原型链”,直到它看到一个空值。在这种情况下,它返回未定义。
接下来,我们有:
Object.prototype.toString
这将返回原型toString
上的函数。Object
可以使用它们的函数调用 JavaScriptcall
函数。这里有几个例子:
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]"
所以现在我们看到它返回了一个包含 substring 的字符串"Constructor"
,这意味着它很可能是一个构造 HTML 元素的对象。最后我们可以理解完整的表达方式:
Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') # => 19
因为"Constructor"
是一个子字符串,indexOf
所以返回 19,即 > 0。所以基本上,这个表达式似乎是检查是否window.HTMLElement
使用后缀“构造函数”来识别自己,我猜这可能是某种浏览器识别检查。
(注意:在写这篇文章时,我测试了使用 Safari 的 Web Inspector 控制台评估这些表达式,但你也可以使用 Chrome 或其他浏览器的控制台来测试这样的东西。)
Object
是 javascript 中(几乎)所有类型都继承的类(构造函数)。Object.prototype
是几乎所有对象的原型链中都能找到的对象。Object.prototype.toString
是在不覆盖它的对象上调用的方法。.call
,当在函数上调用时,以第一个参数作为上下文调用该函数。func.call(a)
类似于a.func=func; a.func()
。不同之处在于 while undefined.toString()
is a TypeError
,Object.prototype.toString.call(undefined)
工作得很好。HTMLElement
是一个继承自 HTML 元素的类。但是,这不是规范要求的,并且在 Internet Explorer 中并非如此,其中 HTML 元素没有原型并且HTMLElement
那里不存在构造函数。既然window
是浏览器环境中的全局对象,就和没有被局部变量遮蔽window.HTMLElement
一样,HTMLElement
如果存在的话。如果它不存在,读取HTMLElement
会抛出一段ReferenceError
时间window.HTMLElement
返回undefined
。Object.prototype.toString.call(window.HTMLElement)
除了HTMLElement.toString()
它在 IE 中工作并使用正确的toString
. 它总是返回一个String
.indexOf
是一个 String 函数,它查找其子字符串的第一次出现,-1
如果子字符串不存在则返回。.indexOf('Constructor') > 0
检查字符串是否包含,并且不以 . 开头"Constructor"
。因此,此方法在调用 on 时确定是否toString
包含。该规范要求:"Constructor"
HTMLElement
...
4) 令 class 为 O 的 [[Class]] 内部属性的值。
5) 返回作为连接三个字符串“[object”、class 和“]”的结果的字符串值。
因此,这会检查HTMLElement
's[[class]]
是否为Constructor
。
最后将检查结果分配给变量isSafari
。这表明在哪些环境中这是正确的。这段代码的作者假设返回值包含"Constructor"
在 Safari 中,在每个版本的 Safari 中,并且仅在 Safari 中。
作为参考,在 Chrome 中,Object.prototype.toString.call(HTMLElement)
返回"[object Function]"
.