From 9ab402d95bda0f596798d41e7df62e7f9638afab Mon Sep 17 00:00:00 2001 From: Kevin Kelley Date: Wed, 11 Jan 2017 23:06:33 -0800 Subject: [PATCH] Add simple implementation of Array.from() and TypedArray.from() These will be used for PhantomJS 1.x and browsers that do not support those methods. --- core/util.js | 26 ++++++++++++++++++++++++++ tests/test.util.js | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/core/util.js b/core/util.js index 5054ee9e..5aabf236 100644 --- a/core/util.js +++ b/core/util.js @@ -11,6 +11,32 @@ var Util = {}; +var addClassFunc = function (cl, name, func) { + if (!cl[name]) { + Object.defineProperty(cl, name, { enumerable: false, value: func }); + } +}; + +// TODO(kelleyk): There's probably a better way to do this, but TypedArray isn't +// directly accessible. +// N.B.(kelleyk): PhantomJS 1.x does not support Uint8ClampedArray or Float64Array, +// so those are left out. +[Array, Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array].forEach( + function (cls) { + var thatCls = cls; + addClassFunc(cls, 'from', function (arrayLike, mapFn, thisArg) { + if (typeof(mapFn) !== 'undefined' || typeof(thisArg) !== 'undefined') + throw new Error("This version of Array.from() does not support " + + "mapFn or thisArg arguments."); + + var result = new thatCls(arrayLike.length); + for (var i = 0; i < arrayLike.length; ++i) + result[i] = arrayLike[i]; + + return result; + }); + }); + /* * ------------------------------------------------------ * Namespaced in Util diff --git a/tests/test.util.js b/tests/test.util.js index 60cdb582..e34f1e15 100644 --- a/tests/test.util.js +++ b/tests/test.util.js @@ -7,6 +7,45 @@ var expect = chai.expect; describe('Utils', function() { "use strict"; + describe('Array class methods', function () { + + var expectTypedArrayEq = function (cls, arr) { + var other = cls.from(arr); + + expect(other).to.be.instanceof(cls); + + // N.B.: We might be tempted to say 'expect(other).to.deep.equal(arr);', + // but that would be incorrect in the situation where + // 'arr' is not an instance of 'cls'. + expect(other.length).to.equal(arr.length); + for (var i = 0; i < arr.length; ++i) + expect(other[i]).to.equal(arr[i]); + + // TODO: Test deep/shallow copy behavior? + }; + + describe('Array.from', function () { + it('should create a new object with the same type and contents', function () { + var arr = [5, 4, 3]; + expectTypedArrayEq(Array, arr); + }); + }); + + // As a stand-in for all of the TypedArray classes + describe('Int32Array.from', function () { + it('should create a new object with the same type and contents', function () { + var arr = new Int32Array(3); + arr[0] = 5; arr[1] = 4; arr[2] = 3; // want to do this without from(), obviously + expectTypedArrayEq(Int32Array, arr); + }); + + it('should return an Int32Array even if the argument is a different type of array', function () { + var arr = [5, 4, 3]; + expectTypedArrayEq(Int32Array, arr); + }); + }); + }); + describe('logging functions', function () { beforeEach(function () { sinon.spy(console, 'log');