polyfill of javascript Object create with simple form - javascript

The polyfill of javascript Object.create(), by some codes in which I am totally confused. The code link is polyfill of Object create.
if (typeof Object.create != 'function') {
// Production steps of ECMA-262, Edition 5, 15.2.3.5
// Reference: http://es5.github.io/#x15.2.3.5
Object.create = (function() {
// To save on memory, use a shared constructor
function Temp() {}
// make a safe reference to Object.prototype.hasOwnProperty
var hasOwn = Object.prototype.hasOwnProperty;
return function(O) {
// 1. If Type(O) is not Object or Null throw a TypeError exception.
if (typeof O != 'object') {
throw TypeError('Object prototype may only be an Object or null');
}
// 2. Let obj be the result of creating a new object as if by the
// expression new Object() where Object is the standard built-in
// constructor with that name
// 3. Set the [[Prototype]] internal property of obj to O.
Temp.prototype = O;
var obj = new Temp();
Temp.prototype = null; // Let's not keep a stray reference to O...
// 4. If the argument Properties is present and not undefined, add
// own properties to obj as if by calling the standard built-in
// function Object.defineProperties with arguments obj and
// Properties.
if (arguments.length > 1) {
// Object.defineProperties does ToObject on its first argument.
var Properties = Object(arguments[1]);
for (var prop in Properties) {
if (hasOwn.call(Properties, prop)) {
obj[prop] = Properties[prop];
}
}
}
// 5. Return obj
return obj;
};
})();
}
Why does it complicate the logic by using IIFE(Immediately Invoked Function Express) and a return function, and closure.
Instead, can I use the simple logic and code below? Is there any wrong or inappropriate content in it? There isn't IIFE and a return function.
if (typeof Object.createOwn != "function") {
Object.createOwn = function(O) {
// 1. if Type(O) is not Object or Null throw a TypeError exception.
if (typeof(O) != "object") {
throw TypeError("Object prototype may only be an Object or null");
}
// 2. Let obj be the result of creating a new object as if by the
// expression new Object() where Object is the standard built-in
// constructor with that name
// 3. Set the [[Prototype]] internal property of obj to O.
var obj;
var Temp = function() {};
Temp.prototype = O;
obj = new Temp();
// 4. If the argument Properties is present and not undefined, add
// own properties to obj as if by calling the standard built-in
// function Object.defineProperties with arguments obj and Properties
if (arguments.length > 1) {
var Properties = Object(arguments[1]);
for (var prop in Properties) {
if (Properties.hasOwnProperty(prop)) {
obj[prop] = Properties[prop];
}
}
}
return obj;
}
}
var foo = {
one: 1,
two: 2
};
var bar = Object.createOwn(foo, 3);

They will both work, but the original is using IIFE for a few reasons. Two of them is mentioned in the comments
// To save on memory, use a shared constructor
This is not the case with your version, where var Temp = function() {}; is wrapped into the function and a new instance is created every time you use it.
// make a safe reference to Object.prototype.hasOwnProperty
Since Object.prototype.hasOwnProperty could potentially be overridden for when it's time to use it, the polyfill makes sure it has it's own safe reference to it at each Object.create.
Then it's also the common reason many use IIFE, to avoid polluting the global namespace.
These are mostly safeguards, and not required in this case. But I see no reason to remove them.

Related

Why Object.create polyfill using prototype of Function instead of simple __proto__ of Object?

I read the Object.create() polyfill on the MDN. They create a new Function and set its prototype property to the passing object as following:
if (typeof Object.create != 'function') {
Object.create = (function() {
var Temp = function() {};
return function (prototype) {
if (arguments.length > 1) {
throw Error('Second argument not supported');
}
if (typeof prototype != 'object') {
throw TypeError('Argument must be an object');
}
Temp.prototype = prototype;
var result = new Temp();
Temp.prototype = null;
return result;
};
})();
}
I'm very curious that why it didn't be simply just using __proto__ as following:
if (typeof Object.create != 'function') {
Object.create = (function() {
var temp = {};
return function (prototype) {
if (arguments.length > 1) {
throw Error('Second argument not supported');
}
if (typeof prototype != 'object') {
throw TypeError('Argument must be an object');
}
temp.__proto__ = prototype;
return temp;
};
})();
}
I have tried to run both of these solutions and the result is the same:
In my opinion, the __proto__ is shorter and easier to read. Do I miss somethings important behind the scene of the standard solution?
As far as I know __proto__ is not a standard property until ECMAScript 6. So, one cannot use it without risking.
Also, there is the main idea behind using new keyword in JavaScript - creating new objects with the specified prototype. And you can create objects with new only through a constructor function. So, MDNs implementation of Object.create() polyfill is pretty idiomatic.
That is, the final answer is: until Object.create() was invented by Douglas Crockford there was only one way to create objects with the specified prototype. And this way was using new MyCtr(), where MyCtr.prototype was equal to the desired one. Furthermore, this way was a native way to accomplish this task.

How to call a constructor with dynamic amount of arguments?

I have a constructor and I don't know the number of arguments it needs, for instance:
function someCtor(a,b,c){
var that = this;
that.a = a;
that.b = b;
that.c = c;
}
I need to create a function which will return the instance of that constructor with a dynamic amount of arguments:
function makeNew(ctor, arguments){
// this doesn't work, but it shows what I'm trying to achieve
return new ctor.apply(arguments);
}
I want to use the function to pass the dynamic arguments to the constructor like below:
var instanceOfCtor = makeNew(someCtor, [5,6,7]);
How to implement this function?
Note: See the ES2015 compatibility note at the end.
You do it by first creating an object setting its underlying prototype to the object the prototype property on the constructor refers to via Object.create, then calling the constructor via Function#apply:
function makeNew(ctor, arguments){
var obj = Object.create(ctor.prototype);
var rv = ctor.apply(obj, arguments);
return rv && typeof rv === "object" ? rv : obj;
}
Note the bit of fiddling at the end, so we're emulating the new operator correctly: When you call a constructor via new, if it returns a non-null object reference, that ends up being the result of the new expression; if it returns anything else (or nothing), the object created by new is the result. So we emulate that.
Even on pre-ES5 browsers, you can emulate enough of Object.create to do that:
if (!Object.create) {
Object.create = function(proto, props) {
if (typeof props !== "undefined") {
throw new Error("The second argument of Object.create cannot be shimmed.");
}
function ctor() { }
ctor.prototype = proto;
return new ctor;
};
}
ES2015 Compatibility Note
If the constructor you're calling was created via ES2015's class syntax, the above won't work, because you can't call ES2015 class constructors that way. For example:
class Example {
constructor(a, b) {
this.a = a;
this.b = b;
}
}
const e = Object.create(Example.prototype);
Example.apply(e, [1, 2]); // TypeError: Class constructor Example cannot be invoked without 'new' (or similar)
The good news is that will only happen on an ES2015+-compatible JavaScript engine, and only if the constructor was created via class; the bad news is that it can happen.
So how do you make your makeNew bulletproof?
It turns out this is quite easy, because ES2015 also added Reflect.construct, which does exactly what you want makeNew to do but does it in a way that's compatible with both class constructors and function constructors. So you can feature-detect Reflect.construct and use it if it's present (ES2015 JavaScript engine, so a constructor might have been created with class) and fall back to the above if it's not there (pre-ES2015 engine, there won't be any class constructors around):
var makeNew; // `var` because we have to avoid any ES2015+ syntax
if (typeof Reflect === "object" && Reflect && typeof Reflect.construct === "function") {
// This is an ES2015-compatible JavaScript engine, use `Reflect.construct`
makeNew = Reflect.construct;
} else {
makeNew = function makeNew(ctor, arguments){
var obj = Object.create(ctor.prototype);
var rv = ctor.apply(obj, arguments);
return rv && typeof rv === "object" ? rv : obj;
};
}
That's pure ES5 syntax, so runs on ES5 engines, but uses ES2015's Reflect.construct if it's present.

Javascript: initialize object by property

var someObject = function(arg) {
this.property = function() {
// do something with the argument
return arg;
}();
};
var obj = new someObject(some argument);
// object.property instanceof "someObject" should be true
When property of someObject is used, a new instance of newObject should be created. For example, when I use the native DOM Element's nextSibling property, a new DOM Element object instance is returned. I wonder if it is possible to create a similar structure. Or would such cause infinite recursion?
Strictly speaking, this is possible in ES5 (all latest browsers, yes that includes IE).
ES5 specifies getters and setters via the get and set keyword or the Object.defineProperty function so you can make functions behave like properties (think innerHTML). Here's how you can do it:
function Mother () {
this.name = '';
Object.defineproperty(this,'child',{
get: function(){
return new Mother();
}
});
}
So the object can now create new instances of itself simply by reading the child property:
var a = new Mother();
a.name = 'Alice';
b = a.child;
b.name = 'Susan';
alert(a.name) // Alice
alert(b.name) // Susan
a instanceof Mother; // true
b instanceof Mother; // true
Having said that, your observation about DOM elements is wrong. The DOM is simply a tree structure. You can create a similar structure yourself using old-school javascript:
function MyObject () {}
var a = new MyObject();
var b = new MyObject();
var c = new MyObject();
a.children = [b,c];
b.nextSibling = c;
c.prevSibling = b;
// now it works like the DOM:
b.nextSibling; // returns c
a.children[1]; // returns c
b.nextSibling.prevSibling instanceof MyObject; // true
No, that's not possible. You could set function to the property, but anyway, you will need to invoke function somehow (with property() notation or with call/apply), because function it's an object itself, and only () or call/apply say to interpreter that you want to execute code, but not only get access to function's object data.
Your understanding of the nextSibling property in the DOM is incorrect. It does not create a new DOMElement, it simply references an existing DOM Node.
When you create a sibling of an element to which you have a reference (e.g., via jQuery or document.createElement), the browser knows to update sibling and parent/child references.
So, the behavior you're trying to emulate doesn't even exist.
As others have intimated, simply accessing a property on an object is not sufficient to get the Javascript interpreter to "do" anything (other than deference the name you're looking up). You'll need property to be a function.
nextSibling doesn't return a new element, it returns an existing element which is the next sibling of the target element.
You can store an object reference as a property of another object just like you can store primitive values.
function SomeObject(obj) {
this.obj = obj;
}
var someObject = new SomeObject(new SomeObject());
someObject.obj instanceof SomeObject //true
However if you want to create a new instance of SomeObject dynamically when accessing someObject.obj or you want to return an existing object based on conditions that shoul be re-evaluated every time the property is accessed, you will need to use a function or an accessor.
function SomeObject(obj) {
this.obj = obj;
}
SomeObject.prototype.clone = function () {
//using this.constructor is a DRY way of accessing the current object constructor
//instead of writing new SomeObject(...)
return new this.constructor(this.obj);
};
var someObject = new SomeObject(new SomeObject());
var someObjectClone = someObject.clone();
Finally with accessors (be aware that they aren't cross-browser and cannot be shimmed)
function SequentialObj(num) {
this.num = num;
}
Object.defineProperty(SequentialObj.prototype, 'next', {
get: function () {
return new this.constructor(this.num + 1);
},
configurable: false
});
var seq = new SequentialObj(0);
console.log(seq.next); //SequentialObj {num: 1}
console.log(seq.next.next.next); //SequentialObj {num: 3}
If you want this.property() to return a new someObject you can write the class as follows:
var someObject = function(arg) {
this.arg = arg;
};
someObject.prototype.property = function(arg) {
// do something with the argument
return new someObject(arg||this.arg);
}();
var obj = new someObject(/*some argument*/);
// object.property instanceof "someObject" should be true
If you want it to return some already instantiated version you can write the code as follows:
var someObject = (function() {
var previous;
function(arg) {
this.arg = arg;
this.propertyBefore = previous;//refers to the someObject created before this one
if(previous) previous.property = this; //before.property now references this class
//this.property will be undefined until another instance of someObject is created
previous = this;
};
})()
var obj = new someObject(/*some argument*/);// returns someObject already created earlier (similar to nextSibling)
One small note - its best practice in javascript to declare class names with a capitalized name (SomeObject rather than someObject)

How would JavaScript's new operator be defined as a function? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
If the JavaScript new operator was a function, how would it be defined?
function _new(fn) {
// What goes here?
}
Had this same curiosity recently.
There is an issue with some of the steps being internal tasks, which simply can't be reimplemented within language.
And, over my original take, Qantas has a good point about using typeof as a faux Type() -- that it should be exclusive to support custom host object types.
But, with that, this is as close as I could manage. Though, it requires that Object.create() be available (so, ES5+).
Object.new = function (constructor /*, args */) {
function isObject(operand) {
// detect and refuse primitives
var type = typeof operand;
return type !== 'undefined' &&
type !== 'boolean' &&
type !== 'number' &&
type !== 'string' &&
operand !== null;
}
var argList = Array.prototype.slice.call(arguments, 1);
if (typeof constructor !== 'function') {
throw new TypeError((typeof constructor) + ' is not a function');
}
var proto = constructor.prototype;
var obj = Object.create(isObject(proto) ? proto : Object.prototype);
var result = constructor.apply(obj, argList);
return isObject(result) ? result : obj;
};
Example:
function Foo(one, two) {
this.one = one;
this.two = two;
}
var bar = Object.new(Foo, 'a', 'b');
console.log(bar instanceof Foo); // true
console.log(bar.one); // "a"
console.log(bar.two); // "b"
And, the annotated version, with steps from 11.2.2 new Operator and 13.2.2 [[Construct]]:
// 1. Let ref be the result of evaluating MemberExpression.
// 2. Let constructor be GetValue(ref).
Object.new = function (constructor /*, args */) {
function isObject(operand) {
// detect and refuse primitives
var type = typeof operand;
return type !== 'undefined' &&
type !== 'boolean' &&
type !== 'number' &&
type !== 'string' &&
operand !== null;
}
// 3. Let argList be the result of evaluating Arguments, producing an internal list of argument values (11.2.4).
var argList = Array.prototype.slice.call(arguments, 1);
// 4. If Type(constructor) is not Object, throw a TypeError exception.
// 5. If constructor does not implement the [[Construct]] internal method, throw a TypeError exception.
if (typeof constructor !== 'function') {
throw new TypeError((typeof constructor) + ' is not a function');
}
// 6. Return the result of calling the [[Construct]] internal method on constructor, providing the list argList as the argument values.
// For [[Construct]], it gets a bit out of order with current options for internal vs. abstractions.
// 5. Let proto be the value of calling the [[Get]] internal property of F with argument "prototype".
var proto = constructor.prototype;
// 1. Let obj be a newly created native ECMAScript object.
// 2. Set all the internal methods of obj as specified in 8.12.
// 3. Set the [[Class]] internal property of obj to "Object".
// 4. Set the [[Extensible]] internal property of obj to true.
//
// 6. If Type(proto) is Object, set the [[Prototype]] internal property of obj to proto.
// 7. If Type(proto) is not Object, set the [[Prototype]] internal property of obj to the standard built-in Object prototype object as described in 15.2.4.
var obj = Object.create(isObject(proto) ? proto : Object.prototype);
// 8. Let result be the result of calling the [[Call]] internal property of F, providing obj as the this value and providing the argument list passed into [[Construct]] as args.
var result = constructor.apply(obj, argList);
// 9. If Type(result) is Object then return result.
// 10. Return obj.
return isObject(result) ? result : obj;
};
There are a few limitations owing to the capabilities of user code: native constructors such as new Date and new RegExp and bound function cannot be shimmed properly using this function.
If you're looking for the relevant specification sections, they are §11.2.2 and §13.2.2.
Anyway, here goes:
// we're assuming that correct arguments are given
function _new(F, args) {
// we could have host objects, make sure edge case not left out
// (typeof could be other than object or function in this case - see bottom)
function Type(arg) {
if (arg === undefined) return 'Undefined';
if (arg === null) return 'Null';
if (arg === false || arg === true) return 'Boolean';
var type = typeof arg;
if (type === 'string') return 'String';
if (type === 'number') return 'Number';
return 'Object';
}
// 1. Let obj be a newly created native ECMAScript object.
// 2. Set all the internal methods of obj as specified in 8.12.
// 3. Set the [[Class]] internal property of obj to "Object".
// 4. Set the [[Extensible]] internal property of obj to true.
// All of the steps above are implicitly completed in steps 6 or 7
var obj;
// 5. Let proto be the value of calling the [[Get]] internal property of F
// with argument "prototype".
var proto = F.prototype;
// 6. If Type(proto) is Object, set the [[Prototype]] internal property of
// obj to proto.
if (Type(proto) === 'Object') obj = Object.create(proto);
// 7. If Type(proto) is not Object, set the [[Prototype]] internal property
// of obj to the standard built-in Object prototype object as described
// in 15.2.4.
else obj = {};
// 8. Let result be the result of calling the [[Call]] internal property of
// F, providing obj as the this value and providing the argument list
// passed into [[Construct]] as args.
var result = F.apply(obj, args);
// 9. If Type(result) is Object then return result.
if (Type(result) === 'Object') return result;
// 10. Return obj.
return obj;
}
About the typeof cases, that is for the edge case when host objects return a typeof value which is not object or function. By testing for anything they can't be, this allows us to test for it properly instead of relying on them being native objects.
Note that this is for at least ES5 -- the only way to shim Object.create in ES3 or older environments would be to use the exact thing that we're currently trying to emulate, which defeats the point of doing so.
This appears to be the minimum necessary, albeit not 100% conformant with the language definition and without error checking. It's ES5 only. There is a shim for Object.create, but by necessity it must call new making it rather pointless in this context!
function _new(T, args) {
var o = Object.create(T.prototype);
var res = o.constructor.apply(o, args);
return (typeof res === 'object') ? res : o;
}
with usage:
function A(name) {
this.name = name;
}
A.prototype.hello = function() {
console.log(this);
}
var foo = _new(A, ['foo']);
var bar = _new(A, ['bar']);
console.log(foo.name);
console.log(bar.name);
The test of the return value of the call to the constructor is necessary because a constructor does not have to return this - if the constructor returns nothing the this is implicit.
See http://jsfiddle.net/uQpUv/
Haters gonna hate, but something like this?
Obviously this is just a round about alias of new but with scope to extend it's potential with the arguments.
http://jsfiddle.net/2qhE2/3/
function _new(classname, arguments) {
// other logic
return new classname(arguments || {});
}
function car(args){
alert(args.make);
}
var MyNewCar = _new(car, {make: "vw"});

How do I inherit javascript functions ?

// Don't break the function prototype.
// pd - https://github.com/Raynos/pd
var proto = Object.create(Function.prototype, pd({
"prop": 42
}));
var f = function() { return "is a function"; };
f.__proto__ = proto;
console.log(f.hasOwnProperty("prop")); // false
console.log(f.prop); // 42
console.log(f()); // "is a function"
.__proto__ is non-standard and deprecated.
How am I supposed to inherit prototypically creating an object but having that object be a function.
Object.create returns an Object not a Function.
new Constructor returns an Object not a Function.
Motivation: - A cross-browser finherit
var finherit = function (parent, child) {
var f = function() {
parent.apply(this, arguments);
child.apply(this, arguments);
};
f.__proto__ = parent;
Object.keys(child).forEach(function _copy(key) {
f[key] = child[key];
});
return f;
};
I don't believe this is possible, so we should probably propose a Function.create to the es-discuss mailing list
/*
Creates a new function whose prototype is proto.
The function body is the same as the function fbody.
The hash of propertydescriptors props is passed to defineproperties just like
Object.create does.
*/
Function.create = (function() {
var functionBody = function _getFunctionBody(f) {
return f.toString().replace(/.+\{/, "").replace(/\}$/, "");
};
var letters = "abcdefghijklmnopqrstuvwxyz".split("");
return function _create(proto, fbody, props) {
var parameters = letters.slice(0, fbody.length);
parameters.push(functionBody(fbody));
var f = Function.apply(this, parameters);
f.__proto__ = proto;
Object.defineProperties(f, props);
return f;
};
})();
Related es-discuss mail
As mentioned in the es-discuss thread there exists a ES:strawman <| prototype operator which would allow for this.
Let's see what it would look like using <|
var f1 = function () {
console.log("do things");
};
f1.method = function() { return 42; };
var f2 = f1 <| function () {
super();
console.log("do more things");
}
console.log(f1.isPrototypeOf(f2)); // true
console.log(f2()); // do things do more things
console.log(f2.hasOwnProperty("method")); // false
console.log(f2.method()); // 42
I hope that I'm understanding this right.
I believe you want a functor that's both an instance of a predefined prototype (yes, a class, just not a classic class) as well as directly callable? Right? If so, then this makes perfect sense and is very powerful and flexible (especially in a highly asynchronous environment like JavaScript). Sadly there is no way to do it elegantly in JavaScript without manipulating __proto__. You can do it by factoring out an anonymous function and copying all of the references to all of the methods (which seems to be the direction you were heading) to act as a proxy class. The downsides to this are...
It's very costly in terms of runtime.
(functorObj instanceof MyClass) will never be true.
Properties will not be directly accessible (if they were all assigned by reference this would be a different story, but primitives are assigned by value). This can be solved with accessors via defineProperty or simply named accessor methods if necessary (it appears that that is what you're looking for, just add all properties to the functor with defineProperty via getters/setters instead of just functions if you don't need cross-engine support/backwards compatability).
You're likely to run into edge cases where final native prototypes (like Object.prototype or Array.prototype [if you're inheriting that]) may not function as expected.
Calling functorObj(someArg) will always make the this context be the object, regardless of if it's called functorObj.call(someOtherObj, someArg) (this is not the case for method calls though)
Because the functor object is created at request time, it will be locked in time and manipulating the initial prototype will not affect the allocated functor objects like a normal object would be affected (modifying MyClass.prototype will not affect any functor objects and the reverse is true as well).
If you use it gently though, none of this should be a big deal.
In your prototype of your class define something like...
// This is you're emulated "overloaded" call() operator.
MyClass.prototype.execute = function() {
alert('I have been called like a function but have (semi-)proper access to this!');
};
MyClass.prototype.asFunctor = function(/* templateFunction */) {
if ((typeof arguments[0] !== 'function') && (typeof this.execute !== 'function'))
throw new TypeError('You really should define the calling operator for a functor shouldn\'t you?');
// This is both the resulting functor proxy object as well as the proxy call function
var res = function() {
var ret;
if (res.templateFunction !== null)
// the this context here could be res.asObject, or res, or whatever your goal is here
ret = res.templateFunction.call(this, arguments);
if (typeof res.asObject.execute === 'function')
ret = res.asObject.execute.apply(res.asObject, arguments);
return ret;
};
res.asObject = this;
res.templateFunction = (typeof arguments[0] === 'function') ? arguments[0] : null;
for (var k in this) {
if (typeof this[k] === 'function') {
res[k] = (function(reference) {
var m = function() {
return m.proxyReference.apply((this === res) ? res.asObject : this, arguments);
};
m.proxyReference = reference;
return m;
})(this.asObject[k]);
}
}
return res;
};
Resulting usage would look something like...
var aobj = new MyClass();
var afunctor = aobj.asFunctor();
aobj.someMethodOfMine(); // << works
afunctor.someMethodOfMine(); // << works exactly like the previous call (including the this context).
afunctor('hello'); // << works by calling aobj.execute('hello');
(aobj instanceof MyClass) // << true
(afunctor instanceof MyClass) // << false
(afunctor.asObject === aobj) // << true
// to bind with a previous function...
var afunctor = (new MyClass()).asFunctor(function() { alert('I am the original call'); });
afunctor() // << first calls the original, then execute();
// To simply wrap a previous function, don't define execute() in the prototype.
You could even chain bind countless other objects/functions/etc until the cows came home. Just refactor the proxy call a bit.
Hope that helps. Oh, and of course you could change the factory flow so that a constructor called without the new operator then instantiates a new object and returns the functor object. However you prefer (you could surely do it other ways too).
Finally, to have any function become the execution operator for a functor in a bit more elegant of a manner, just make the proxy function a method of Function.prototype and pass it the object to wrap if you want to do something like (you would have to swap templateFunction with this and this with the argument of course)...
var functor = (function() { /* something */ }).asFunctor(aobj);
With ES6 it's possible to inherit from Function, see (duplicate) question
javascript class inherit from Function class
default export Attribute extends Function {
...
}

Categories