真的是object?
废话不说,看代码:
typeof Boolean.prototype
Object.prototype.toString.call()
3
2
1
typeof Boolean.prototype
// 'object'
Object.prototype.toString.call(Boolean.prototype)
// '[object Boolean]'
What? What个鬼,遇到诡异现象,看协议标准!!!!!!!!!!!!!!!!!!!!!!!
- Else if O has an [[ErrorData]] internal slot, let builtinTag be “Error”.
- Else if
O has a [[BooleanData]] internal slot
, let builtinTag be “Boolean”. - Else if O has a [[NumberData]] internal slot, let builtinTag be “Number”.
The Boolean prototype object:
- is %Boolean.prototype%.
- is an ordinary object.
- is itself a Boolean object;
it has a [[BooleanData]] internal slot with the value false
.
has a [[Prototype]] internal slot whose value is %Object.prototype%.
这里有个 [[BooleanData]] internal slot
, 啥玩意,简单理解就是内置的属性,通常是伴随对象创建产生的,开发人员是不可见的。
参见协议: Object Internal Methods and Internal Slots, 翻译一段核心:
内部槽对应于与对象关联的内部状态,并由各种 ECMAScript 规范算法使用。内部槽不是对象属性,也不是继承的。根据特定的内部槽规范,这种状态可能由任何 ECMAScript 语言类型的值或特定的 ECMAScript 规范类型值组成。除非另有明确指定,否则内部槽是作为创建对象过程的一部分分配的,不能动态添加到对象中。除非另有说明,否则内部槽的初始值是未定义的值。本规范中的各种算法创建具有内部槽的对象。但是,ECMAScript 语言没有提供将内部插槽与对象关联的直接方法。
那么,以此类推:
- Number.prototype
- String.prototype
立即执行?
先看下面四个语句吧,各自返回什么值,
// 编号1
function f(){ return 1}()
// 编号2
(function f(){ return 2}())
// 编号3
var x = function f(){ return 3}()
// 编号4
x = function f(){ return 4}()
答案:
// 编号1
function f(){ return 1}()
// Uncaught SyntaxError: Unexpected token ')'
// 编号2
(function f(){ return 2}())
// 2
// 编号3
var x = function f(){ return 3}()
// undfined
// 编号4
x = function f(){ return 4}()
// 4
对于1:
是 函数申明 + 分组运算符, 分组运算符里面必须有表达式,因为上面没有,故报错。
稍微做修改
function f(){return this} (1) // 1
function f(){return this}; (1) // 1
对于2:
()
分组运算符,因其要求里面表达式和子表达式, 它强制将function f...
作为一个表达式来做语法解析,从而避免了它被(优先地)解释为函数声明语句。
对于3:
是赋值运算,类似2, 会把function f...
作为表达式来解析。
因为其是初始化,不是赋值,并无返回值
对于4:
类似3,区别与这是赋值,有返回值。
null 和 undefined
undefined是全局属性,null是关键字。
delete null
delete undefined
Object.getOwnPropertyDescriptor(window, "null")
Object.getOwnPropertyDescriptor(window, "undefined")
早期的JS,undefined
不是一个保留的关键字,后来嘛,为了兼容,所以就老实的呆在全局变量去了。
let你怎么呢?
for (let x in {a:1}) {
var x = 100
}
// Uncaught SyntaxError: Identifier 'x' has already been declared
for (let x in {a:1}) {
let x = 100
}
为什么第一段代码会抛出异常,而第二段没有呢? let你怎么呢?
先拆分一下代码:
- forHead: for (let x in {a:1})
- forBody: {}部分
引用大佬周爱民的原话:
语法parser引擎自己会处理这个重复检测(尽管ECMAScript没有定义)。
parser过程会维护当前块的词法上下文,并且拒绝在forBody和forHead中出现这种重复声明。而且有趣的是,这个检测过程对于let/const,以及var来说是不同的。——具体来说,let/const是只检测当前词法作用域,而var是检测词法作用域栈(scopeStack, scope chains)。
关于这一点的实现,可以在这里看到:
https://github.com/babel/babel/blob/master/packages/babel-parser/src/util/scope.js#L95
x = x 怎么解读
11.13.1 Simple Assignment ( = ) 62页
根据协议,可以理解为
v = GetValue(v)
将右手端 v 的值,赋给左手端的 v 的引用。
v在作为左手端的时候,它是引用;而作为右手端的时候,它是值。
当然还有很多其他的赋值操作,例子:
- *=
- /=
- %=
- +=
- -=
- <<=
- >>=
- >>>=
- &=
- ^=
- |=
间接调用
直接放到浏览器控制塔执行,看结果:
var obj = {
fn() {
return this === obj
}
};
obj.fn(); // true
(obj.fn)(); // true
(0, obj.fn)() // false
这里涉及两个运算符, 一个()
分组运算符,一个,
号运算符。
()
不产生赋值行为, 故(obj.fn)()
等同于obj.fn()
,
产生赋值行为,故(0, obj.fn)()
等同于(x = (0, obj.fn))()
, this上下文发生改变。
delete为什么不抛出异常
当你尝试删除一个不存在的变量的时候,并不会抛出异常。而且其还会返回一个布尔值true。
delete xxxxxxxxx // true
delete 10 // true
你删除一个不存在的东西,咋可能为true呢?
这个嘛,早期javascript并没有try/catch的语法来捕获错误,javaScript 就返回true,表示删除没有异常。
- delete 10 中 这个10 是一个表达式的值,其实并没有操作,返回true,用于表示没有错误。
- delete x 其实就是删除一个引用。
写在最后
不忘初衷,有所得,而不为所累,如果你觉得不错,你的一赞一评就是我前行的最大动力。
微信公众号:成长的程序世界 ,关注之后,海量电子书,打包拿走不送。
或者添加我的微信 dirge-cloud,一起学习。