Files
scriptc/tests/corpus/8078-instanceof-object-function.cjs
T
Chris Tate e00d3fd911 Check comparison operands and walk instanceof chains as Node does
- The assert comparison methods read as function values (equal,
  strictEqual, deepEqual, partialDeepStrictEqual and their negations)
  throw Node's ERR_MISSING_ARGS TypeError, `The "actual" and "expected"
  arguments must be specified`, when called with fewer than two
  arguments, where `[assert.equal][0]()` passed.
- Untyped `instanceof Object` starts at the value's prototype, so
  Object.prototype itself, whose prototype is null, is not an Object.
- Untyped `instanceof Function` follows the whole prototype chain through
  objects and functions: an object whose prototype is a function, or a
  function whose prototype was set to such an object, is a Function.
2026-10-24 16:22:03 -05:00

78 lines
2.5 KiB
JavaScript

'use strict';
// `x instanceof Object` and `x instanceof Function` on untyped values follow
// Node: objects are instances of Object unless their prototype chain ends
// in null first, and functions (classes and arrows included) are instances
// of Function.
class Shape {}
class Square extends Shape {}
const nullProto = Object.create(null);
const underNull = Object.create(nullProto);
const regrown = Object.create(null);
Object.setPrototypeOf(regrown, {});
const orphan = function orphan() {};
Object.setPrototypeOf(orphan, null);
function declared() {}
const values = {
'plain object': {},
array: [1, 2],
'Object.create(null)': nullProto,
'object under a null-prototype object': underNull,
'Object.create(null) given a prototype': regrown,
'Object.create(plain object)': Object.create({ a: 1 }),
'parsed JSON': JSON.parse('{"a":[1]}'),
'function declaration': declared,
'bound function': declared.bind(null),
'arrow function': () => 1,
'async function': async () => {},
class: Square,
'class instance': new Square(),
'function with a null prototype': orphan,
map: new Map(),
date: new Date(0),
'regular expression': /x/,
error: new TypeError('t'),
'typed array': new Uint8Array(2),
promise: Promise.resolve(1),
number: 1,
string: 's',
boolean: false,
null: null,
undefined: undefined,
symbol: Symbol('s'),
bigint: 10n,
};
for (const [label, value] of Object.entries(values)) {
console.log(`${label}: Object ${value instanceof Object}, Function ${value instanceof Function}`);
}
function describe(value) {
if (!(value instanceof Object)) return 'primitive or null-prototype';
return value instanceof Function ? 'function' : 'object';
}
console.log([nullProto, {}, describe, 0].map(describe).join(', '));
// Prototype chains through functions and objects, and Object.prototype
// itself, whose own prototype is null.
const base = function base() {};
const fromFunction = {};
Object.setPrototypeOf(fromFunction, base);
const throughObject = {};
Object.setPrototypeOf(throughObject, fromFunction);
const nullRooted = function nullRooted() {};
Object.setPrototypeOf(nullRooted, null);
const reparented = function reparented() {};
Object.setPrototypeOf(reparented, fromFunction);
const chains = {
objectPrototype: Object.getPrototypeOf({}),
fromFunction,
throughObject,
nullRooted,
reparented,
};
for (const [label, value] of Object.entries(chains)) {
console.log(`${label}: Object ${value instanceof Object}, Function ${value instanceof Function}`);
}