Can I create an object for which Array.isArray () returns true without using an array constructor or array literal?

I can easily make a simple object look like an array by setting its prototype to Array.prototype:

const obj = {};
Reflect.setPrototypeOf(obj, Array.prototype);

(I know that there are also some problems with the magic property lengthand sparse arrays, but this is not a question of this question.)

I want to make Array.isArray(obj)return true(of course, without modifying the method Array.isArray()). The MDN polyfill for isArray.isArray() as follows:

if (!Array.isArray) {
  Array.isArray = function(arg) {
    return Object.prototype.toString.call(arg) === '[object Array]';
  };
}

Using the property Symbol.toStringTag, I can do Object.prototype.toString.call(obj)return '[object Array]':

obj[Symbol.toStringTag] = 'Array';
console.log(Object.prototype.toString.call(obj) === '[object Array]'); // true

polyfilled Array.isArray() true obj (, , , Array.isArray(), Symbol.toStringTag). Array.isArray() false obj. ECMAScript 2017 , Array.isArray() IsArray, true, Array. , IsArray , , .

Array.isArray(obj) return true? , Array.isArray() .

, Array.isArray() ?, 5 , ECMAScript 5. ECMAScript 2017.

+4
4

, , ( Array.isArray) - , , .length .

, Array ( ) . (, String::split, String::match, Array.from, Array.of, Array, Object.keys, Object.getOwnPropertyNames).
, , - apply/construct, , Promise.all .entries().

, , ( ) .

: " ?", .

+4

, .

, , Proxy, .

console.log(Array.isArray(new Proxy([], {}))) // true
Hide result

Proxy , Array.isArray. , , , .

function redirect(trap) {
  return (target, ...args) => Reflect[trap](obj, ...args);
}
var obj = {0:0, 1:1, length:2};
var arrayified = new Proxy([], {
  apply: redirect('apply'),
  construct: redirect('construct'),
  defineProperty: redirect('defineProperty'),
  deleteProperty: redirect('deleteProperty'),
  enumerate: redirect('enumerate'),
  get: redirect('get'),
  getOwnPropertyDescriptor: redirect('getOwnPropertyDescriptor'),
  getPrototypeOf: redirect('getPrototypeOf'),
  has: redirect('has'),
  isExtensible: redirect('isExtensible'),
  ownKeys: redirect('ownKeys'),
  preventExtensions: redirect('preventExtensions'),
  set: redirect('set'),
  setPrototypeOf: redirect('setPrototypeOf')
});
console.log(arrayified); // [0, 1]
Hide result
+1

, . , .push() , length, length , a[a.length] = "test" , nodeList HTMLCollection.

, Frankenstarray , .

0

Babel class MyObject extends Array ES5, Array.isArray(new MyObject) true:

ES2015

class MyObject extends Array{};

console.log(Array.isArray(new MyObject))

ES5, babel

"use strict";

function _possibleConstructorReturn(self, call) {
    if (!self) {
        throw new ReferenceError(
            "this hasn't been initialised - super() hasn't been called"
        );
    }
    return call && (typeof call === "object" || typeof call === "function")
        ? call
        : self;
}

function _inherits(subClass, superClass) {
    if (typeof superClass !== "function" && superClass !== null) {
        throw new TypeError(
            "Super expression must either be null or a function, not " +
                typeof superClass
        );
    }
    subClass.prototype = Object.create(superClass && superClass.prototype, {
        constructor: {
            value: subClass,
            enumerable: false,
            writable: true,
            configurable: true
        }
    });
    if (superClass)
        Object.setPrototypeOf
            ? Object.setPrototypeOf(subClass, superClass)
            : (subClass.__proto__ = superClass);
}

var MyObject = (function(_Array) {
    _inherits(MyObject, _Array);

    function MyObject() {
        return _possibleConstructorReturn(
            this,
            (MyObject.__proto__ || Object.getPrototypeOf(MyObject))
                .apply(this, arguments)
        );
    }

    return MyObject;
})(Array);

console.log(Array.isArray(new MyObject()));
0

Source: https://habr.com/ru/post/1663867/


All Articles