Last active
September 3, 2018 18:50
-
-
Save trusktr/c74867851a335dcc20aca6c614feabe7 to your computer and use it in GitHub Desktop.
Extending Array with ES5-style class constructors
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// With some ES2015+ language features:** | |
{ | |
function MyArray(...args) { | |
const self = new Array(...args) | |
self.__proto__ = MyArray.__proto__ | |
return self | |
} | |
MyArray.prototype = { | |
__proto__: Array.prototype, | |
constructor: MyArray, | |
add(...args) { | |
this.push(...args) | |
}, | |
} | |
MyArray.__proto__ = Array | |
const a = new MyArray | |
assert( a instanceof Array ) | |
assert( a instanceof MyArray ) | |
a.add(1,2,3) | |
assert( a.length === 3 ) | |
assert( a.concat(4,5,6).length === 6 ) | |
assert( a.concat(4,5,6) instanceof MyArray ) | |
assert( Array.isArray(a) ) | |
} | |
//**With Reflect.construct, and ES2015+ language features:** | |
{ | |
function MyArray(...args) { | |
const self = Reflect.construct(Array, args, new.target) | |
return self | |
} | |
// with ES6+ features: | |
MyArray.prototype = { | |
__proto__: Array.prototype, | |
constructor: MyArray, | |
add(...args) { | |
this.push(...args) | |
}, | |
} | |
MyArray.__proto__ = Array | |
const a = new MyArray | |
assert( a instanceof Array ) | |
assert( a instanceof MyArray ) | |
a.add(1,2,3) | |
assert( a.length === 3 ) | |
assert( a.concat(4,5,6).length === 6 ) | |
assert( a.concat(4,5,6) instanceof MyArray ) | |
assert( Array.isArray(a) ) | |
} | |
//**ES5 version with `new`, but uses non-standard __proto__ which may not be available in all ES5 engines:** | |
~function() { | |
function MyArray() { | |
// we need the null for the following bind call | |
var args = [null].concat( Array.prototype.slice.call(arguments) ) | |
var self = new ( Array.bind.apply(Array, args) ) | |
self.__proto__ = MyArray.prototype | |
return self | |
} | |
function assign(target, source) { | |
// naive implementation, can be improved | |
for (var key in source) { | |
target[key] = source[key] | |
} | |
return target | |
} | |
MyArray.prototype = assign( Object.create(Array.prototype), { | |
constructor: MyArray, | |
add: function() { | |
this.push.apply(this, Array.prototype.slice.call(arguments)) | |
}, | |
concat: function() { | |
var args = Array.prototype.slice.call(arguments) | |
return MyArray.from( Array.prototype.concat.apply( this, args ) ) | |
}, | |
}) | |
MyArray.__proto__ = Array // static inheritance | |
MyArray.from = function( other ) { | |
var result = new this | |
other.forEach( function( item, index ) { | |
result[index] = item | |
}) | |
return result | |
} | |
var a = new MyArray | |
assert( a instanceof Array ) | |
assert( a instanceof MyArray ) | |
a.add(1,2,3) | |
assert( a.length === 3 ) | |
assert( a.concat(4,5,6).length === 6 ) | |
assert( a.concat(4,5,6) instanceof MyArray ) | |
assert( Array.isArray(a) ) | |
}() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment