- JavaScript引擎与运行时入门小记:在哪些环境下可以运行JavaScript
- JavaScript学习笔记(一):理解概念,一等函数、编程范式、原型、单线程
继续梳理JavaScript基本概念。
有两个东西,表述起来像绕口令:
- global object:全局对象。全局环境的顶层对象。JavaScript中,始终会定义一个全局对象。(globalThis)
- global objects:全局对象们。涵盖了所有在全局环境中可用的内置对象。(standard built-in objects)。
全局对象
在 JavaScript 中,总是会存在一个全局对象。 在 Web 浏览器中,当使用使用 var 关键字定义全局变量时,它们将被创建为该全局对象的成员(在 Node.js 中,情况有所不同)。 例如:
- 在 Web 浏览器中,绝大多数 JavaScript 代码不作为后台任务使用。它们将 Window 作为其全局对象。
- 后台 Worker 中运行的代码有一个 WorkerGlobalScope 对象作为其全局对象。
- 在 Node.js 下运行的脚本有一个名为 global 的对象作为其全局对象。
先看个例子(在firefox、chrome、edge下可以运行,在node.js下不适用):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
注意:
- globalThis 的属性自动是 全局变量(例子中myAdd4)。
- 通过var定义的变量,都会作为 globalThis 的属性存在(注意myAdd和myAdd2)。
- 这个也仅适用于浏览器,nodejs行为不一样,见后面var部分。
globalThis
globalThis 是在ES11(ES2020)中引入的,用于访问 全局对象。在Qt中,截至6.5,QJSEngine尚不支持这个东西。
在globalThis引入之前,
- 浏览器中 使用 window、self、frames 指代全局对象。Web workers中使用 self 指代全局对象
- Node.js中使用 global 指代全局对象
全局对象,有属性指向它自己,比如
在浏览器下:
1 2 3 4 |
|
在Nodejs下:
1 2 |
|
在QJSEngine下:
在QJSEngine(Qt6.6)下,不支持globalThis,也没有其他self、window、global等变通方式。
但是我可以通过让函数返回this来间接获取它:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
输出结果
1 2 3 4 5 |
|
var 与全局对象
Nodejs手册提到:
In browsers, the top-level scope has traditionally been the global scope. This means that
var something
will define a new global variable, except within ECMAScript modules. In Node.js, this is different. The top-level scope is not the global scope;var something
inside a Node.js module will be local to that module, regardless of whether it is a CommonJS module or an ECMAScript module.
在浏览器中,顶级作用域传统上就是全局作用域,这意味着var会定义全局变量。而在Node.js中,顶级作用域不是全局作用域,var定义的变量属于当前模块。
node.js
1 |
|
QJSEngine
在Qt下,即使没有globalThis,但是我们也可以在C++端轻松验证——var定义的变量是globalObject的属性:
1 2 3 4 |
|
this 用法
不同于C++中的this和python中的self,javascript中这个东西似乎很乱。MDN中说:在非严格模式下,this
总是指向一个对象,在严格模式下可以是任意值。
this的值取决于函数的调用方式和上下文环境,状况很复杂。简单几个情况如下:
- 在对象的方法中,this指向调用该方法的对象
- 在构造函数中,this指向正在构造的对象
- 类静态方法中,this指向类
- 在箭头函数中,this指向定义箭头函数时的外层对象,不会随着调用方式改变
- 在事件处理函数中,this指向触发事件的元素??
- 在call,apply或bind方法中,this可以被显式地绑定到任意对象
- 在全局作用域或普通函数中,this不一定指向全局对象
对象方法
和C++、Python有点类似。这个比较直观,this指向调用该方法的对象:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
在函数内部,this
的值取决于函数如何被调用。同一个函数,根据其调用的方式,this
的值是不同的:
1 2 3 4 5 6 7 8 9 |
|
这这个基础上,对原型使用,也是符合预期:
1 2 |
|
构造函数
这个也容易理解。当一个函数被用作构造函数(使用 new
关键字)时,无论构造函数是在哪个对象上被访问的,其 this
都会被绑定到正在构造的新对象上。
1 2 3 4 5 6 7 8 9 |
|
类构造函数与此一样,this指向类实例:
1 2 3 4 5 6 7 8 9 10 11 |
|
类静态方法
这个和python也有些类似
1 2 3 4 5 6 7 |
|
箭头函数
在箭头函数中,this
保留了上下文的 this
值。
这个东西,挺反知觉的:
1 2 3 4 5 6 7 8 |
|
输出是
1 |
|
而不是
1 |
|
需要这样才行(注意:它指向全局的this,同时注意,在nodejs下this不等同于globalThis):
1 2 3 4 5 6 7 8 9 10 |
|
在下面情况中,箭头函数中的this指向obj:
1 2 3 4 5 6 7 8 9 10 |
|
事件处理函数
如下程序,在浏览器下显示”true“,即this指向globalThis:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
而下面addEventListenser用法,结果显示"Button id is myButton",即this指向button:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
call、apply、bind
JavaScript中的call()和apply()方法都是用来改变函数的this指向的,它们可以让一个函数以指定的对象作为执行上下文,从而访问该对象的属性和方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
全局作用域或普通函数
在全局作用域或普通函数中:非严格模式下,this指向全局对象(globalThis);严格模式下,this是undefined??
全局作用域中 this
全局作用域下,this并不一定是全局对象:
先看一段代码:
1 2 |
|
在Firefox浏览器与QJSEngine下,结果都是true,在Node.js中,结果为false。是否是strict没有影响。
更直接一点:
1 |
|
在Firefox下true,在node.js下为false,在QJSEngine下报错(不支持globalThis)。
普通函数中的this
搞不懂,普通函数中为什么要设计this。
在Firefox、Node.js、QJSEngine下测试以下:
1 2 3 4 5 6 |
|
结果:
1 2 |
|
在严格模式下测试:
1 2 3 4 5 6 |
|
结果
1 |
|
全局对象们(内置标准对象)
JavaScript内置标准对象是指JavaScript语言自带的一些对象,它们可以直接在代码中使用,而不需要引入其他文件或库。
这东西挺多,暂时先摘抄一点。
JavaScript内置标准对象可以分为以下几类:
值属性
这些全局属性返回一个简单值,这些值没有自己的属性和方法。
- globalThis
- Infinity
- NaN
- undefined
关于NaN一个梗,香蕉是怎么练成的:
1 |
|
注,NaN的特点:
1 2 |
|
对于C++看看:
1 2 3 |
|
函数属性
这些全局函数可以直接调用,不需要在调用时指定所属对象,执行结束后会将结果直接返回给调用者。
例如:
- eval(),
- isFinite(),
- isNaN(),
- parseFloat(),
- parseInt()
基本对象
这些对象是定义或使用其他对象的基础。
例如:
- Object,
- Function,
- Boolean,
- Symbol
注意:symbol 是一种基本数据类型,每个从 Symbol()
返回的 symbol 值都是唯一的。一个 symbol 值能作为对象属性的标识符;这是该数据类型仅有的目的。
1 2 3 4 5 6 7 8 |
|
symbol 在 for in中不可见,在JSON.stringify()也不可见:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
错误对象
这些对象是一种特殊的基本对象,它们用来表示和处理错误。
例如
- Error
- EvalError
- RangeError
- ReferenceError
数字和日期对象
这些对象用来表示和操作数字、日期和执行数学计算的对象。
例如
- Number
- BigInt
- Math
- Date
字符串对象
这些对象用来表示和操作字符串的对象。例如,String,RegExp等。
可索引的集合对象
这些对象用来表示和操作按照索引值来排序的数据集合,包括数组和类型数组,以及类数组结构的对象。
例如
- Array,
- Int8Array,
- Uint8Array,
- Uint8ClampedArray
使用键的集合对象
这些对象用来表示和操作使用键来存储数据的集合,包括可迭代的Map和Set,以及支持按照插入顺序来迭代元素的对象。
例如,
- Map,
- Set,
- WeakMap,
- WeakSet
结构化数据对象
这些对象用来表示和操作结构化的缓冲区数据,或使用JSON(JavaScript Object Notation)编码的数据。例如,ArrayBuffer,SharedArrayBuffer,Atomics,DataView,JSON等。
控制抽象对象
这些对象用来帮助构造代码,尤其是异步代码(例如不使用深度嵌套的回调)。
例如
- Iterator
- AsyncIterator
- Promise
- GeneratorFunction
- AsyncGeneratorFunction
- Generator
- AsyncGenerator
- AsyncFunction
反射对象
这些对象用来实现对对象的底层操作,或创建和操作代理对象。例如,Reflect,Proxy等。 Reflect是ES6引入的,Reflect对象提供了一系列的静态方法,它们与对象的基本操作一一对应,例如Reflect.get(),Reflect.set(),Reflect.has()等。这些方法的作用是将对象的操作转为函数调用,从而可以在函数中实现更灵活的逻辑:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Proxy对象用于创建一个对象的代理,它接受两个参数,第一个是目标对象,第二个是一个处理器对象,它包含了一些陷阱(trap)函数,用于拦截目标对象的基本操作。这些陷阱函数的名称和Reflect对象的方法一一对应,例如get,set,has等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
|
国际化对象
这些对象用来支持多语言处理。例如,Intl,Intl.Collator,Intl.DateTimeFormat,Intl.NumberFormat等。
例子:
1 2 3 4 5 6 7 8 |
|
结果
1 2 |
|
注,截至目前,QJSEngine不支持Intl。
参考
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis
- Symbol - JavaScript | MDN (mozilla.org)
- JavaScript 标准内置对象 - JavaScript | MDN (mozilla.org)
- https://doc.qt.io/qt-6/qtqml-javascript-functionlist.html