学了这么久,还真就不太懂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 其实就是删除一个引用。


写在最后



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



相关文章
|
1月前
|
SQL 前端开发 BI
如何开发设备管理系统中的设备点检板块 ?(附架构图+流程图+代码参考)
设备点检是设备管理系统中的核心模块,能够帮助企业制定点检标准、安排任务并记录结果,从而保障设备稳定运行,提升生产效率。本文详解设备点检模块的功能设计、业务流程、开发技巧与实现效果,并提供数据库设计、前端与后端实现建议,助力开发者快速构建高效、可靠的点检系统。
如何开发设备管理系统中的设备点检板块 ?(附架构图+流程图+代码参考)
|
安全 前端开发 Windows
EACCES: permission denied,mkdir … npm install 安装依赖问题解决
可是我们看到上面的提示发现,报的是permission denied,这就很奇怪,为什么我是root用户了,还会没有权限呢?
EACCES: permission denied,mkdir … npm install 安装依赖问题解决
|
域名解析 存储 缓存
DNS:DNS域名解析过程及原理
DNS:DNS域名解析过程及原理
794 1
mo-quarter-picker:基于 Vue2 和 ElementUI 的季度范围选择器
mo-quarter-picker:基于 Vue2 和 ElementUI 的季度范围选择器
1000 0
mo-quarter-picker:基于 Vue2 和 ElementUI 的季度范围选择器
|
11月前
|
监控 Serverless 数据库
探索 Serverless 架构:云计算的新浪潮
【10月更文挑战第18天】Serverless架构,即无服务器架构,是一种新兴的云计算模式,让开发者无需管理服务器即可构建和运行应用。本文探讨了其核心概念、优势、挑战及最佳实践,强调了按需付费、自动扩展和开发效率等优点,同时也指出了冷启动、状态管理和调试监控等挑战。
|
机器学习/深度学习 数据采集 传感器
使用Python实现深度学习模型:智能空气质量监测与预测
【8月更文挑战第21天】 使用Python实现深度学习模型:智能空气质量监测与预测
1228 3
|
11月前
|
存储 资源调度 JavaScript
Vite是什么?怎样使用Vite创建Vue3项目?
Vite是什么?怎样使用Vite创建Vue3项目?
723 0
|
存储 Java 索引
32 位和 64 位 JVM 中 int 变量的大小解析
【8月更文挑战第21天】
610 0
|
移动开发 JavaScript 前端开发
Taro——安装和使用
Taro——安装和使用
527 0
|
监控 NoSQL 调度
k8s--pod 生命周期、初始化容器、钩子函数
k8s--pod 生命周期、初始化容器、钩子函数