学了这么久,还真就不太懂JavaScript,不信?

简介: 内部槽对应于与对象关联的内部状态,并由各种 ECMAScript 规范算法使用。内部槽不是对象属性,也不是继承的。根据特定的内部槽规范,这种状态可能由任何 ECMAScript 语言类型的值或特定的 ECMAScript 规范类型值组成。除非另有明确指定,否则内部槽是作为创建对象过程的一部分分配的,不能动态添加到对象中。

1.JPG


真的是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个鬼,遇到诡异现象,看协议标准!!!!!!!!!!!!!!!!!!!!!!!


Object.prototype.toString的定义:

  1. Else if O has an [[ErrorData]] internal slot, let builtinTag be "Error".
  2. Else if O has a [[BooleanData]] internal slot, let builtinTag be "Boolean".
  3. Else if O has a [[NumberData]] internal slot, let builtinTag be "Number".


Boolean.prototype的定义:

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")
复制代码

2.JPG


早期的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)。


关于这一点的实现,可以在这里看到:

github.com/babel/babel…


x = x 怎么解读



11.13.1 Simple Assignment ( = ) 62页


3.JPG


根据协议,可以理解为


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 其实就是删除一个引用。


写在最后



不忘初衷,有所得,而不为所累,如果你觉得不错,你的一赞一评就是我前行的最大动力。



相关文章
|
4月前
|
存储 JavaScript 前端开发
写给不耐烦程序员的 JavaScript 指南(二)
写给不耐烦程序员的 JavaScript 指南(二)
67 0
|
12月前
|
JavaScript 前端开发 算法
精通JavaScript系列,详解知识体系,等你开吃
精通JavaScript系列,详解知识体系,等你开吃
|
4月前
|
存储 JavaScript 前端开发
写给不耐烦程序员的 JavaScript 指南(四)
写给不耐烦程序员的 JavaScript 指南(四)
39 0
|
4月前
|
JavaScript 前端开发 测试技术
写给不耐烦程序员的 JavaScript 指南(三)
写给不耐烦程序员的 JavaScript 指南(三)
46 0
|
4月前
|
存储 JavaScript 前端开发
写给不耐烦程序员的 JavaScript 指南(一)
写给不耐烦程序员的 JavaScript 指南(一)
56 0
|
缓存 前端开发 网络协议
必知必会的JavaScript前端面试题篇(一),不看后悔!
必知必会的JavaScript前端面试题篇(一),不看后悔!
|
4月前
|
前端开发 JavaScript UED
【JavaScript】面试手撕防抖
防抖: 首先它是常见的性能优化技术,主要用于处理频繁触发的浏览器事件,如窗口大小变化、滚动事件、输入框内容改变等。在用户连续快速地触发同一事件时,防抖机制会确保相关回调函数在一个时间间隔内只会被执行一次。
58 0
|
4月前
|
存储 JavaScript 前端开发
写给不耐烦程序员的 JavaScript 指南(五)
写给不耐烦程序员的 JavaScript 指南(五)
57 1
|
4月前
|
JavaScript 前端开发 程序员
写给不耐烦程序员的 JavaScript 指南(六)
写给不耐烦程序员的 JavaScript 指南(六)
37 1
|
4月前
|
前端开发 JavaScript
能让你早点下班的36个JavaScript实用函数!
能让你早点下班的36个JavaScript实用函数!