new 做了什么?instanceof 为什么有时会误判?

先理解原理和示例,再练习完整口述与追问。

new 创建对象、把原型指到构造函数的 prototype、用该对象作为 this 调用构造函数;构造函数返回对象时,new 的结果是这个返回值,返回原始值则仍用新建对象。instanceof 沿实例的原型链查找构造函数的 prototype,可以被 Symbol.hasInstance、跨窗口和改写 prototype 影响。

new Fn(...args) 可以分成四步。先创建一个普通对象,把它的内部原型 [[Prototype]] 设为 Fn.prototype(Fn.prototype 必须是对象,否则回退到 Object.prototype)。然后以这个对象为 this 调用 Fn,参数原样传入。最后看返回值:返回对象(含函数、数组)就采用返回值,返回 undefined、数字、字符串等原始值则丢弃,结果仍是新建对象。因此“new 的核心就是 return this”只覆盖了构造函数没有显式返回对象的情况。

obj instanceof Fn 从 obj 的原型链向上找,看某一环是不是 Fn.prototype。它检查的是原型关系,不是“由谁 new 出来”。Object.create(Fn.prototype) 没有调用 Fn,instanceof 仍为 true;构造函数返回了另一个对象时,new 的结果可能和 Fn.prototype 没有关系,instanceof 为 false。Symbol.hasInstance 可以改写这个判断。iframe 或 worker 里的数组,原型链上是另一个 realm 的 Array.prototype,instanceof Array 为 false,所以判断数组用 Array.isArray。

js
function User(name) {
  this.name = name
  return { redirected: true }
}
const user = new User('Ada')
console.log(user.redirected, user instanceof User) // true false

function Point(x) { this.x = x }
const direct = Object.create(Point.prototype)
console.log(direct instanceof Point, direct.x) // true undefined

User 返回了普通对象,name 写在被丢弃的实例上,外面拿到的是 { redirected: true }。direct 只是原型接上了,构造函数没有执行,所以没有 x。

箭头函数没有 [[Construct]] 和 prototype,不能 new。类也不能当普通函数调用。改写 Fn.prototype 之后,之前创建的实例仍指向旧原型对象,instanceof 会变成 false。

new 会先创建一个对象,原型指向构造函数的 prototype,再用这个对象当 this 执行构造函数。如果构造函数返回的是对象,new 的结果就是该对象;返回数字、字符串这些原始值则忽略,仍用新建对象。instanceof 是沿着原型链找构造函数的 prototype,所以 Object.create 出来的对象也可能为 true,跨窗口的数组会为 false,还可能被 Symbol.hasInstance 改写。判断数组应该用 Array.isArray。