splat over JavaScript object (with new)? - javascript

How do I splat across objects without using ECMA6 features?
Attempt
function can(arg0, arg1) {
return arg0 + arg1;
}
function foo(bar, haz) {
this.bar = bar;
this.haz = haz;
}
myArgs = [1,2];
With can I can just do:
can.apply(this, myArgs);
When trying with foo:
new foo.apply(this, myArgs);
I get this error (because I'm calling new):
TypeError: function apply() { [native code] } is not a constructor

Using Object.create
function foo(bar, haz) {
this.bar = bar;
this.haz = haz;
}
x = Object.create(foo.prototype);
myArgs = [5,6];
foo.apply(x, myArgs);
console.log(x.bar);

Using Object.create(proto) is the right way to go about this.
Coco and LiveScript (Coffeescript subsets) offer a workaround:
new foo ...args
compiles to
(function(func, args, ctor) {
ctor.prototype = func.prototype;
var child = new ctor, result = func.apply(child, args), t;
return (t = typeof result) == "object" || t == "function" ? result || child : child;
})
(foo, args, function(){});
And in CoffeeScript:
(function(func, args, ctor) {
ctor.prototype = func.prototype;
var child = new ctor, result = func.apply(child, args);
return Object(result) === result ? result : child;
})(foo, args, function(){});
These hacks are ugly, slow, and imperfect; for example, Date relies on its internal [[PrimitiveValue]]. See here.

Related

How can you get Object.keys() to read the properties of a breeze entity?

I am trying to use Breeze with an Angular application using reactive forms.
The FormGroup.patchValue() function takes my breeze entity object and should be able to patch it into my form.
However, patchValue() uses Object.keys() to iterate over the objects properties to know what values to patch in.
Object.keys() does NOT recognize inherited properties.
The typescript objects that breeze tooling generates have the properties assigned using inheritance.
So none of the properties are visible to Object.keys() except for entityAspect and _backingStore for some reason.
So this makes reactive forms in Angular totally useless with breeze entities.
Is there a way to either avoid using inheritance to assign the breeze properties, or some kind of universal transform function I can use to get Object.keys() to see all the properties on my breeze entity objects?
I'm not sure if this will solve it (not familiar with breeze), but I would think you could do:
function getKeys(obj) {
var myKeys = Object.keys(obj);
var protoKeys = Object.keys(obj.constructor.prototype);
if (Object.getPrototypeOf(obj)) {
protoKeys = protoKeys.concat(getKeys(Object.getPrototypeOf(obj)));
}
return [...new Set(myKeys.concat(protoKeys))].filter(c => c !== 'constructor');
}
Which, using the transpiled typescript from:
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
class CustomGreeter extends Greeter {
howdy() {
return 'howdy';
}
}
let greeter = new Greeter("world");
Will give you the list:
["greeting", "howdy", "greet"]
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var Greeter = /** #class */ (function () {
function Greeter(message) {
this.greeting = message;
}
Greeter.prototype.greet = function () {
return "Hello, " + this.greeting;
};
return Greeter;
}());
var CustomGreeter = /** #class */ (function (_super) {
__extends(CustomGreeter, _super);
function CustomGreeter() {
return _super !== null && _super.apply(this, arguments) || this;
}
CustomGreeter.prototype.howdy = function () {
return 'howdy';
};
return CustomGreeter;
}(Greeter));
var greeter = new CustomGreeter("world");
function getKeys(obj) {
var myKeys = Object.keys(obj);
var protoKeys = Object.keys(obj.constructor.prototype);
if (Object.getPrototypeOf(obj)) {
protoKeys = protoKeys.concat(getKeys(Object.getPrototypeOf(obj)));
}
return [...new Set(myKeys.concat(protoKeys))].filter(c => c !== 'constructor');
}
console.log(getKeys(greeter))

What is the purpose of doing `Object(this)`?

I was going through the Array'a find polyfill implementation on MDN:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find?v=control#Polyfill
Copy pasting it below:
// https://tc39.github.io/ecma262/#sec-array.prototype.find
if (!Array.prototype.find) {
Object.defineProperty(Array.prototype, 'find', {
value: function(predicate) {
// 1. Let O be ? ToObject(this value).
if (this == null) {
throw new TypeError('"this" is null or not defined');
}
var o = Object(this);
// 2. Let len be ? ToLength(? Get(O, "length")).
var len = o.length >>> 0;
// 3. If IsCallable(predicate) is false, throw a TypeError exception.
if (typeof predicate !== 'function') {
throw new TypeError('predicate must be a function');
}
// 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
var thisArg = arguments[1];
// 5. Let k be 0.
var k = 0;
// 6. Repeat, while k < len
while (k < len) {
// a. Let Pk be ! ToString(k).
// b. Let kValue be ? Get(O, Pk).
// c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
// d. If testResult is true, return kValue.
var kValue = o[k];
if (predicate.call(thisArg, kValue, k, o)) {
return kValue;
}
// e. Increase k by 1.
k++;
}
// 7. Return undefined.
return undefined;
}
});
}
Why is it that we need to do var o = Object(this);?
What does Object(this) achieve?
Thanks for any discussion.
In strict mode, a primitive this will not be coerced to an object.
Therefore, explicit coercion to an object using Object(this) is necessary.
Here is a more detailed example:
const array = Array.prototype;
Object.defineProperty(array, 'foo1', { value() {
return this.length >>> 0; }});
Object.defineProperty(array, 'foo2', { value() {
"use strict";
return this.length >>> 0; }});
console.log(Array.prototype.foo1.call(undefined));
console.log(Array.prototype.foo2.call(undefined));
The first example runs successfully with a result of 0, because the argument undefined is coerced to an object in non-strict mode. The second example fails, because undefined is not coerced in non-strict mode, and thus this.length errors out.
From MDN:
the value passed as this to a function in strict mode is not forced into being an object (a.k.a. "boxed")
However, in this case, there is already an explicit check for null or undefined:
if (this == null) {
throw new TypeError('"this" is null or not defined');
}
so I am tempted to say the explicit casting to an object is not necessary. It is probably used here out of an abundance of caution, or as boilerplate.
This is a fascinating question... Thanks for your post!
To be honest, I am a bit surprised by Object(this) because JavaScript seems to coerce anything to object (using wrappers) in situations where this could potentially be a primitive value.
If we try to change this with Function.prototype.bind(), JavaScript always returns an object (a function is an object):
var foo = function () {
console.log(this, typeof this);
}.bind('foo');
var bar = function () {
console.log(this, typeof this);
}.bind(1337);
var baz = function () {
console.log(this, typeof this);
}.bind(false);
var qux = function () {
console.log(this, typeof this);
}.bind(NaN);
var quux = function () {
console.log(this, typeof this);
}.bind(undefined);
var corge = function () {
console.log(this, typeof this);
}.bind(null);
var grault = function () {
console.log(this, typeof this);
}.bind([]);
var garply = function () {
console.log(this, typeof this);
}.bind({});
var waldo = function () {
console.log(this, typeof this);
}.bind(/regex/);
var fred = function () {
console.log(this, typeof this);
}.bind(function () {});
foo(); // String { 0: "f", 1: "o", 2: "o" } object
bar(); // Number { 1337 } object
baz(); // Boolean { false } object
qux(); // Number { NaN } object
quux(); // Window object
corge(); // Window object
grault(); // Array [ ] object
garply(); // Object { } object
waldo(); // /regex/ object
fred(); // function fred<() function
If we try to change this with Function.prototype.call() or Function.prototype.apply(), once again, JavaScript always returns an object:
Array.prototype.foo = function () {
console.log(this, typeof this);
};
['foo'].foo(); // Array [ "foo" ] object
Array.prototype.foo.call('bar'); // String { 0: "b", 1: "a", 2: "r"} object
Array.prototype.foo.call(42); // Number { 42 } object
Array.prototype.foo.call(true); // Boolean { true } object
Array.prototype.foo.call(NaN); // Number { NaN } object
Array.prototype.foo.call(undefined); // Window object
Array.prototype.foo.call(null); // Window object
Array.prototype.foo.call({}); // Object { } object
Array.prototype.foo.call(/regex/); // /regex/ object
Array.prototype.foo.call(function () {}); // function () function
In JavaScript, we know that native objects may be useful for type conversion when they are not used as constructors but as regular functions. Number, String and Boolean are quite convenient:
var num = 1337,
str = '',
bool = true;
console.log(Number(str), typeof Number(str));
console.log(Number(bool), typeof Number(bool));
console.log(String(num), typeof String(num));
console.log(String(bool), typeof String(bool));
console.log(Boolean(num), typeof Boolean(num))
console.log(Boolean(str), typeof Boolean(str));
For the record, here is what we get with explicit conversions through Object():
console.log(typeof Object(false), Object(false) instanceof Boolean);
console.log(typeof Object('bar'), Object('bar') instanceof String);
console.log(typeof Object(42), Object(42) instanceof Number);
console.log(typeof Object(NaN), Object(NaN) instanceof Number);
console.log(typeof Object(undefined), Object(undefined) instanceof Object);
console.log(typeof Object(null), Object(null) instanceof Object);
console.log(typeof Object(['foo']), Object(['foo']) instanceof Array);
console.log(typeof Object({}), Object({}) instanceof Object);
console.log(typeof Object(/regex/), Object(/regex/) instanceof RegExp);
console.log(typeof Object(function () {}), Object(function () {}) instanceof Function);
Now it is obvious that Object(this) can be used to convert any primitive value for this and get a wrapper object instead. If this is already an object, it has no effect:
var obj1 = {baz: 'Baz'},
obj2 = Object(obj1);
var arr1 = ['foo', 'bar'],
arr2 = Object(arr1);
var reg1 = /regex/,
reg2 = Object(reg1);
var fun1 = function () { return 'Hello!'; },
fun2 = Object(fun1);
console.log(arr1 === arr2);
console.log(obj1 === obj2);
console.log(reg1 === reg2);
console.log(fun1 === fun2);
Moreover, Object is weird because it acts in the same way, whether it is called with new or not:
var foo = Object('foo'),
bar = new Object('bar');
console.log(foo);
console.log(bar);
I may be wrong, but my conclusion is the following: given that this is always coerced to an object, Object(this) is not necessary. However, it indicates explicitly what happens implicitly to avoid ambiguity and improve code comprehension.
What do you think?
EDIT
torazaburo is right: strict mode is the key! When functions are in strict mode, primitive values for this are not coerced! This is probably the most reasonable explanation for explicit conversion with Object(this)...
Function.prototype.bind()
var foo = function () {
'use strict';
console.log(this, typeof this);
}.bind('foo');
var bar = function () {
'use strict';
console.log(this, typeof this);
}.bind(1337);
var baz = function () {
'use strict';
console.log(this, typeof this);
}.bind(false);
var qux = function () {
'use strict';
console.log(this, typeof this);
}.bind(NaN);
var quux = function () {
'use strict';
console.log(this, typeof this);
}.bind(undefined);
var corge = function () {
'use strict';
console.log(this, typeof this);
}.bind(null);
var grault = function () {
'use strict';
console.log(this, typeof this);
}.bind([]);
var garply = function () {
'use strict';
console.log(this, typeof this);
}.bind({});
var waldo = function () {
'use strict';
console.log(this, typeof this);
}.bind(/regex/);
var fred = function () {
'use strict';
console.log(this, typeof this);
}.bind(function () {});
foo(); // foo string
bar(); // 1337 number
baz(); // false boolean
qux(); // NaN number
quux(); // undefined undefined
corge(); // null object
grault(); // Array [ ] object
garply(); // Object { } object
waldo(); // /regex/ object
fred(); // function fred<() function
Function.prototype.call()
Array.prototype.foo = function () {
'use strict';
console.log(this, typeof this);
};
['foo'].foo(); // Array [ "foo" ] object
Array.prototype.foo.call('bar'); // bar string
Array.prototype.foo.call(42); // 42 number
Array.prototype.foo.call(true); // true boolean
Array.prototype.foo.call(NaN); // NaN number
Array.prototype.foo.call(undefined); // undefined undefined
Array.prototype.foo.call(null); // null object
Array.prototype.foo.call({}); // Object { } object
Array.prototype.foo.call(/regex/); // /regex/ object
Array.prototype.foo.call(function () {}); // function () function

"Multiple inheritance" in prototypal inheritance

How can I create a function that inherits from two functions and respects changes for their prototypes when the two base functions don't have an inheritance relationship?
The example demonstrates the behavior I want because c gets modifications to A.prototype and B.prototype.
function A() { }
function B() { }
B.prototype = Object.create(A.prototype);
function C() { }
C.prototype = Object.create(B.prototype);
A.prototype.foo = "foo";
B.prototype.bar = "bar";
var c = new C();
console.log(c.foo); //prints foo
console.log(c.bar); //prints bar
However, I don't have the luxury where B inherits from A.
function A() { }
function B() { }
function C() { }
C.prototype = //something that extends A and B even though B does not extend A.
A.prototype.foo = "foo";
B.prototype.bar = "bar";
var c = new C();
console.log(c.foo); //should print foo
console.log(c.bar); //should print bar
This is not possible.
Try using a mixin pattern, or have a property of C inherit from B and another property inherit from A.
Then access through these properties.
You could change your code to do something like this
C.prototype.perform = function (key) {
var args = Array.prototype.slice(arguments, 1);
if (key in this)
return this[key].apply(this, args);
if (key in B.prototype)
return B.prototype[key].apply(this, args);
if (key in A.prototype)
return A.prototype[key].apply(this, args);
undefined(); // throw meaningful error
}
C.prototype.get = function (key) {
if (key in this)
return this[key];
if (key in B.prototype)
return B.prototype[key];
if (key in A.prototype)
return A.prototype[key];
}
Then use it like
var c = new C();
c.perform('toString');
c.get('foo');

_.bind source code in underscore

read the _.bind in source code, I didn't understand when the statement this instanceof bound will be true. Could anyone give an example.
_.bind = function(func, context) {
var args, bound;
if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
if (!_.isFunction(func)) throw new TypeError;
args = slice.call(arguments, 2);
return bound = function() {
if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
ctor.prototype = func.prototype;
var self = new ctor;
ctor.prototype = null;
var result = func.apply(self, args.concat(slice.call(arguments)));
if (Object(result) === result) return result;
return self;
};
};
For starters, Function.prototype.bind won't be defined. If bound is used as a constructor, (this instanceof bound) will be true. For example:
Function.prototype.bind = null;
var Constructor = function () {};
var BoundConstructor = _.bind(Constructor, {});
var b = new BoundConstructor(); // (this instanceof bound) === true
You can use the debugger to trace through this fiddle.

how to fix this class definition in javascript to support instanceof operator

I have a class definition method for create class in javascript:
var Class = function() {
var clazz = null,
pros = {};
for (var i = 0; i < arguments.length; i++) {
var arg = arguments[i];
if (typeof arg == "function") arg = arg.prototype;
else {
arg.init && (clazz = arg.init, delete arg.init)
}
for (var p in arg) pros[p] = arg[p];
}
clazz.prototype = pros;
return clazz;
};
var Person = Class({
init: function(name) {
this.name = name;
},
say:function(){
console.info(this.name);
}
});
var Man = Class(Person, {
init: function(name) {
Person.apply(this, arguments);
this.gender = 'man'
}
});
var m = new Man('kk');
console.info(m instanceof Man);
console.info(m instanceof Person);
However, it does not support the instanceof operator.
Any idea to fix it?
You should keep track of the prototype chain to make instanceof work. What you're currently doing is merely copying properties into one object, and use that as prototype of the returned function. As a result, the information that Parent is a parent of Man is lost.
You'd need to set the prototype instead of copying. Since you need to modify an existing object to set the underlying prototype of, the deprecated __proto__ property is required. Object.create cannot be used here, because that returns a new object.
Edit: It is possible without __proto__, but you'd need the function F trick: http://jsfiddle.net/p9pvQ/.
var clazz = null,
pros = Object.prototype; // root of chain
for (var i = 0; i < arguments.length; i++) {
var arg = arguments[i];
if (typeof arg === "function") {
arg = arg.prototype;
} else {
if(arg.init) {
clazz = arg.init;
delete arg.init;
}
var o = arg;
arg = (function() { function F() {}; F.prototype = pros; return new F; })();
for(var key in o) arg[key] = o[key];
}
pros = arg;
}
m will then have the prototype chain as follows:
Class.init // m
gender: "man"
name: "kk"
__proto__: F // Man
__proto__: F // Person
say: function (){
__proto__: Object // Object.prototype
__defineGetter__: function __defineGetter__() { [native code] }
__defineSetter__: function __defineSetter__() { [native code] }
... (Object.prototype functions)

Categories