Skip to content

JavaScript 操作符,表达式,语句拾遗

await 操作符

await 操作符会等待后面的 Promise 表达式兑现后获取他的值,并且只能在顶层模块或者异步函数中使用。总结一下使用方式就是:

javascript
await expression;

这里的 expression 就很有讲究

  1. 若为 Promise 对象,那么就等待他的执行结果
  2. 若是 thenable 对象,那么就将其包装成一个 Promise 对象,构造时会调用其中的 then 函数
  3. 除此之外的其他类型会被隐式的包装进一个已兑现的 Promise 用于等待,其结果就是表达式的值。

async function

该语句用来声明一个异步函数,如果调用这个函数,必定返回一个 promise(即使内部没有写 return 语句)

TIP

即使异步函数的返回值看起来像是被包装在了一个 Promise.resolve 中,但它们不是等价的。

如果给定的值是一个 promise,异步函数会返回一个不同的引用,而 Promise.resolve 会返回相同的引用,具体原因可以看 Promise.resolve 的实现原理

javascript
const p = new Promise((res, rej) => {
  res(1);
});
async function asyncReturn() {
  return p;
}
function basicReturn() {
  return Promise.resolve(p);
}

console.log(p === basicReturn()); // true
console.log(p === asyncReturn()); // false

import.meta

这是一个 JavaScript 表达式,他是一个宿主环境创建的可扩展的 null 原型对象,他的所有属性均可写、可配置、可枚举。规范没有在对象上明确定义任何属性,但是宿主环境通常会定义以下属性:

  1. url

    到此模块的完整 URL(不是模块不能调用),包括查询参数和片段标识符(在 ?# 之后)。在浏览器中,它是可获取此脚本的 URL(对外部脚本)或者是包含此脚本的文档的 URL(对内联脚本)。在 Node.js 中,它是文件路径(包括 file:// 协议部分)。

  2. resolve

    将一个模块的标识符解析为相对于当前模块的 URL。

void

这个运算符允许在表达式执行完成时,产生(某些地方)期望获得的 undefined 值。

void 运算符通常只用于获取 undefined 的原始值,一般使用 void(0)(等同于 void 0)。在上述情况中,也可以使用全局变量 undefined 来代替。

当用户点击一个以 javascript: 开头的 URI 时,它会执行 URI 中的代码,然后用返回的值替换页面内容,除非返回的值是 undefined。void 运算符可用于返回 undefined。例如:

HTML
<a href="javascript:void(0);"> 这个链接点击之后不会做任何事情 </a>

<a href="javascript:void(document.body.style.backgroundColor='green');">
  点击这个链接会让页面背景变成绿色。
</a>

但这种做法很不推荐了,只能在老式脚本看到,现在推荐使用事件监听器

除此之外,箭头函数标准中,允许在函数体不使用括号来直接返回值。如果右侧调用了一个原本没有返回值的函数,其返回值改变后,则会导致非预期的副作用。安全起见,当函数返回值不会被使用到的时候,应该使用 void 运算符,来确保 API 改变时,并不会改变箭头函数的行为。

JavaScript
button.onclick = () => void doSomething();

这确保了当 doSomething 的返回值从 undefined 变为 true 的时候,不会改变代码的行为。

TIP

对于一些特定的事件,比如某些表单事件(如 onsubmit)或锚点点击事件(如 <a> 标签的 onclick),返回 false 会阻止默认行为。

  • 返回 true (或任何真值): 不会阻止默认行为。
  • 返回 false: 会阻止默认行为(相当于调用 event.preventDefault())。

new

老生常谈的东西,new 操作符在调用时发生了什么?

  1. 首先创建一个简单的 JavaScript 空对象
  2. 根据 new 后面跟的变量类型分别决定逻辑
    1. 如果不是函数,直接 throw 一个 TypeError
    2. 如果是函数,且函数的 prototype 是对象,那么将前面创建的对象的 [[Prototype]] 指向构造函数的 prototype 属性
    3. 否则其 [[Prototype]]Object.prototype
  3. 将 this 绑定到前面创建的对象上,执行构造函数
  4. 如果构造函数返回了对象,那么该返回的对象成为整个 new 表达式的结果。否则,如果构造函数未返回任何值或返回了一个原始值,则返回我们前面新建的对象

那么我们是否可以按照上述的规则来实现一个 new 函数?

javascript
function myNew(ctor, ...args) {
  if (typeof ctor !== "function") throw new TypeError("");
  const obj = Object.create(ctor.prototype); // 第一步和第二步
  const res = ctor.apply(obj, args); // 第三步
  if (res !== null && (typeof res === "object" || typeof res === "function"))
    return res;
  else return obj;
}