Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

《你不知道的javascript(中)》附录A #32

Open
qunzi0214 opened this issue Apr 26, 2021 · 0 comments
Open

《你不知道的javascript(中)》附录A #32

qunzi0214 opened this issue Apr 26, 2021 · 0 comments
Labels
read book 读书笔记

Comments

@qunzi0214
Copy link
Owner

qunzi0214 commented Apr 26, 2021

ECMAScript Annex B

ECMAScript规范包含了Annex B,其中介绍了浏览器兼容性与官方规范的差异,应该注意避免使用

主要如下:

  • 非严格模式下,允许八进制数值常量,如 0123(十进制83)
  • window.escape()window.unescape() 可以将字符串转义和回转成带有 % 的十六进制转义序列,如 window.escape('?') 的结果是 %3F,此特性已废弃
  • String.prototype.substr()String.prototype.substring() 十分相似,前者的第二个参数是截取长度,而后者是结束索引。前者没有被严格废弃,但是应该避免使用

同时,Web ECMAScript规范中介绍了目前浏览器因为兼容性考虑,实现的一些内容(并未包含在官方规范内),同样应该避免使用

  • <!-- --> 在浏览器中是合法的
  • String.prototype 中包含HTML格式字符串的附加方法,如 anchor()、big()... 等等
  • RegExp 扩展 RegExp.$1 .. RegExp.$9RegExp.lastMatch/RegExp["$&"] (匹配组和最近匹配),同样是非标准
  • Function.prototype.argumentsarguments.caller 均已废止,Function.caller 非标准

宿主对象

var a = document.createElement('div')
typeof a // 'object'
Object.prototype.toString.call(a) // '[object HTMLDivElement]'

上例中,a 不仅仅是一个对象,还是个特殊的宿主对象,其内部的 [[Class]] 值来自预定义的属性,不可更改。需要注意如下问题:

  • 一些宿主对象在强制转化为 boolean 时会意外的成为假值或真值,需要注意
  • 无法访问正常的 object 内建方法,比如 toString()
  • 无法写覆盖
  • 包含一些预定义属性
  • 包含无法将 this 重载为其他对象的方法
  • 其他...

除此之外, console 及其各种方法也是宿主环境提供

全局DOM变量

一个不太为人所知的现象:创建带有id的DOM元素时,也会创建同名的全局变量

<div id="app"></div>
console.log(app) // HTML元素

因此尽量不要使用全局变量

原生原型

除非必要,否则不要扩展原生原型。其次,扩展时必须加入判断条件:

if (!Array.prototype.foobar) {
  Array.prototype.foobar = function () {
    this.push('foo', 'bar')
  }
}

这种情况一般称之为 polyfill/shim

<script>

多个 <script> 标签中的JavaScript代码是如何运行的:

  • 共享 global 对象(浏览器中是 window
  • 全局变量作用域提升机制在这些边界中不适用
<script>foo()</script>
<script>
  function foo () {
    // 报错
  }
</script>

保留字

保留字分为四类:关键字( function, switch等 )、预留关键字( enum等 )、null 常量和 true/false 布尔常量

一首关于保留字有趣的小诗:

Let this long package float,
Goto private class if short.
While protected with debugger case,
Continue volatile interface.
Instanceof super synchronized throw,
Extends final export throws.

Try import double enum?
-False, boolean, abstract function,
Implements typeof transient break!
Void static, default do,
Switch int native new.
Else, delete null public var
In return for const, true, char
...Finally catch byte

这首诗中也包含了一些ES3中的保留字(byte、long)等,它们在ES5中已经不再是保留字

在ES5之前,保留字也不能用作对象属性名或键,目前已经没有这个限制

实现中的限制

JavaScript规范对于函数中参数个数,字符串常量的长度等没有限制,但是由于JavaScript引擎实现各异,会导致一些限制:

  • 字符串常量允许的最大字符数
  • 传入函数的参数数据大小(也称为栈大小,以字节为单位)
  • 函数声明中的参数个数
  • 未经优化的调用栈,即函数调用链的最大长度
  • JavaScript程序以阻塞方式在浏览器中运行的最长时间(秒)
  • 变量名的最大长度
function addAll () {
  var sum = 0
  for (var i = 0; i < arguments.length; i++) {
    sum += arguments[i]
  }
}

var nums = []
for (var i = 1; i < 100000; i++) {
  nums.push(i)
}

addAll(2, 4, 6) // 12
addAll.apply(null, nums) // 499950000
// 在一些引擎中会报错
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
read book 读书笔记
Projects
None yet
Development

No branches or pull requests

1 participant