var Editor = {};
Editor.Basic = function(obj) {
this.config ={
value: obj
}
};
Editor.Basic.prototype = {
getValue: function() {
return this.config.value;
}
};
Editor.Advanced = function(obj) {
Editor.Basic.call(this, obj);
};
Editor.Advanced.prototype = {
config: {
notValue: !this.config.value
}
};
var extendByPrototype = function(obj1, obj2) {
for (var key in obj2.prototype) {
if (obj2.prototype.hasOwnProperty(key) && obj1.prototype[key] === undefined)
obj1.prototype[key] = obj2.prototype[key];
}
};
extendByPrototype(Editor.Advanced, Editor.Basic);
Is there anyway to get the Editor.Advanced.prototype to extend existing objects (recursively of course) instead of overriding them? (As seen in extendByPrototype)
I know I would check obj1.prototype[key] !== undefined, but I am unsure as what I need to do to extend existing keys in a generic way, without moving the config from Editor.Advanced.prototype to the constructor and using the push function.
The proper way of extending an Object in JavaScript is using Object.create(prototype). Objects created this way will have proper inheritance setup. To get the prototype of any object, you'll use Object.getPrototypeOf(object).
Object.create(prototype) is new in JavaScript 1.8.5. If you're looking for backward compatible, you'll have to use the non-standard way
function extend(child, supertype) {
child.prototype.__proto__ = supertype.prototype;
}
extend(Animal, Lifeform);
extend(Plant, Lifeform);
var anOnion = new Plant();
After that, you can get the prototype object by...
object.contructor.__proto__
More details on __proto__ here: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/proto
Related
I want to create function that will return all properties of an object:
This is my initial code:
function dir(obj) {
if (obj === null || obj === Object.prototype) {
return [];
}
var names = Object.getOwnPropertyNames(obj);
return names.concat(dir(Object.getPrototypeOf(obj)));
}
and I have ES6 class where I want to hide some properties:
class Lexer {
constructor(input, { whitespace = false } = {}) {
this.__input__ = input.replace(/\r/g, '');
var internals = {};
[
'_i', '_whitespace', '_col', '_newline', '_line',
'_state', '_next', '_token', '_prev_char'
].forEach(name => {
Object.defineProperty(this, name, {
configurable: false,
enumerable: false,
get() {
return internals[name];
},
set(value) {
internals[name] = value;
}
});
});
this._whitespace = whitespace;
this._i = this._line = this._col = this._newline = 0;
this._state = this._next = this._token = null;
this._prev_char = '';
}
token() {
}
...
}
The problem I have is that Object.getOwnPropertyNames return enumerable properties and Object.key don't return ES6 class methods. So I if Use the first function I get hidden props and if I use second I only get __input__.
Is there a way to detect if something is hidden property and not ES6 class method? I don't want to detect if something is a function because I want something more generic there can be not enumerable properties that are functions.
I've also found that for ES5 constructor function there is constructor property that is also not enumerable and behave like ES6 method (in case of my Lexer class it work the same token method).
NOTE: this is not Y/X problem I want to create dir function for my Scheme interpreter that will work like similar function in Python, it should work with ES5 function constructor objects and ES6 class objects.
I've tried this:
function dir(obj, proto) {
if (obj === null || obj === Object.prototype) {
return [];
}
var names = Object.getOwnPropertyNames(obj);
if (!proto) {
names = names.filter(name => {
var d = Object.getOwnPropertyDescriptor(obj, name);
return d.configurable && d.enumerable;
});
}
return names.concat(dir(Object.getPrototypeOf(obj), true));
}
but I don't know if this is the best way, since the user may want to create property descriptor of prototype (i'm not sure if this is something that may happen). I want 100% working solution and not work around. Do you know any method to make it work?
EDIT:
Even that I have working solution for my case, I'm wondering if ES6 properties in fact are indistinguishable from not enunumerable properties.
Especially if you can detect if foo is different then bar:
class Test {
constructor() {
Object.defineProperty(this, 'foo', {
enumerable: false,
configurable: false,
value: function() { alert('foo') }
});
}
bar() {
alert('bar');
}
}
Is the only difference is that bar is on prototype object and there are no other way to detect the difference?
Is there a way to detect if something is hidden property and not ES6 class method? I don't want to detect if something is a function
There's no distinction. A class method is just a non-enumerable function-valued property of the prototype object.
If you absolutely had to distinguish them, you could .toString() the function and check whether it has method syntax, but that still won't catch methods that are copied around and miss ES5 methods. (See also How do you check the difference between an ECMAScript 6 class and function? and How can I differentiate between an arrow function, class and a normal function? for related topics)
I have two objects that are the same type and I want to copy the content of one of them to the other.
const Invoice1 = new InvoiceModel();
const Invoice2 = new InvoiceModel();
now in order to have something like : Invoice2 = Invoice1
After reading :
How do I correctly clone a JavaScript object?
I tried to use any of below commands but all of them say that invoice2 is not defined at runtime:
Invoice2 = { ...Invoice1 }; //OR
Invoice2 = Object.assign({}, Invoice1); //OR
Invoice2 = JSON.parse(JSON.stringify(Invoice1));
finally I used this function to copy the content of objects by reading this article (https://medium.com/#Farzad_YZ/3-ways-to-clone-objects-in-javascript-f752d148054d):
function CopyObject(src, target) {
for (let prop in src) {
if (src.hasOwnProperty(prop)) {
target[prop] = src[prop];
}
}
return target;
}
I wonder is there any cleaner way to do that except using above function?
I have read many post regarding this issue but all of them create a new object.
I recommend creating a method in the prototype in InvoiceModel that does this automatically for you.
class InvoiceModel {
constructor(num) {
this.num = num
}
duplicate() {
return Object.assign(Object.create(this), this)
}
}
const obj1 = new InvoiceModel(10)
console.log(obj1.num)
const obj1Copy = obj1.duplicate()
console.log(obj1Copy.num)
console.log(obj1Copy === obj1)
If the objects are just plain old data objects - with no methods or private state - you can just use a deep object clone method as specified here.
However, by the looks of things you are using classes with constructors, which implies you have methods and state. This is more tricky, because it suggests you may be relying on the constructor being re-run, e.g. to store private state in a closure, to allocate other resources, or rely on some kind of side effects. In that case you will need some kind of Invoice.prototype.clone method, that knows how to inject state into a new instance, and reruns the constructor function for the class - as per #andrew's answer.
I would avoid cloning objects with the syntax target = {...src}, which one commenter suggested. This will cause you trouble as soon as you have non-scalar reference members like sub-objects or arrays (as you will be copying pointers to the originals, not cloning their values). The same flaw applies to that CopyObject function you have picked up.
I have implemented a deep copier of objects, it does not override anything in the target option, but if you need that, you can achieve that as well:
var defaults = {
options: {
remove: true,
enable: false,
instance: {}
},
log: {
warn: true,
error: true
}
};
var config = {
options: {
remove: false,
instance: null
}
};
function applyDefaults(d, t) {
if ((typeof d !== "object") && (typeof d !== "array")) {
return d;
}
if (t === undefined) {
if (typeof d === "object") {
t = {};
} else if (typeof d === "array") {
t = [];
}
}
for (var key in d) {
if (t[key] === undefined) {
t[key] = d[key];
} else {
applyDefaults(d[key], t[key]);
}
}
return t;
}
applyDefaults(defaults, config);
console.log(config);
However, this will not copy "private" stuff, not defined as members of this.
I have a JavaScript object defined like so:
var Object = (function () {
function Object() {
this.id = RandomNumber();
}
// Custom Object.prototype / Object impementations here...
return Object;
})();
The problem is that once this has been constructed, it loses original functionality like Object.defineProperty etc.
The idea is that I want to extend the basic functionality of Object, not re-write or overwrite the existing prototype.
How can this be achieved?
EDIT: Just to be clear, I know I can do this without affecting the original functionality:
Object.prototype.foo = function() { }
but I need to specifically add functionality to Object's constructor, i.e.
function Object() { this.id = 0; }
The new functionality must not overwrite the original Functionality.
Use the .prototype to add a property:
Object.prototype.specialMethod = function () {
// Your method's code
};
And you'd use it like:
var a = {};
a.specialMethod();
Although I would discourage adding a property to the Object's prototype, because it is enumerable and will mess up looping, and will be inherited by all objects, and objects that inherit from Object, which is basically everything.
You could actually use the Object.defineProperty method you mention:
Object.defineProperty(Object.prototype, "specialMethod", {
enumerable: false, // The important one, to avoid looping problems
configurable: false,
writable: false,
value: function () {
// Your method's code
}
});
Do as Ian wrote. If you also want to check it the method already exists use
if (Object.prototype.specialMethod == null) Object.prototype.specialMethod = function() { ... };
In order to extend this object you should create another object that has its prototype assigned a new instance of Object.
var Object = (function () {
function Object() {
this.id = 5;
}
Object.prototype.speak = function(prop){
alert(this[prop]);
}
return Object;
})();
function ExtendsObject(prop){
this.someProperty = prop;
}
ExtendsObject.prototype = new Object();
var xObj = new ExtendsObject("derived");
xObj.speak("id");
xObj.speak("someProperty");
Working Example: http://jsfiddle.net/RbCcA/
If you want to stick with the self executing functions here is the example rewrote:
var Object = (function () {
function Object() {
this.id = 5;
}
Object.prototype.speak = function(prop){
alert(this[prop]);
}
return Object;
})();
var ExtendsObject = (function(){
function ExtendsObject(prop){
this.someProperty = prop;
}
ExtendsObject.prototype = new Object();
return ExtendsObject;
})();
var xObj = new ExtendsObject("derived");
xObj.speak("id");
xObj.speak("someProperty");
Working Example: http://jsfiddle.net/RbCcA/1/
I do question the use of self executing functions in this situation. They are usually used to encapsulate and shield internals, however in the code example they are being exposed by returning the object from the SEF. Returning the object and storing it in a global variable just re-exposes the object, allowing its prototype and properties to be manipulated. Maybe there are private variables you have not mentioned, but as stated I find the SEFs unnecessary.
I'm trying to extend Object functionality this way:
Object.prototype.get_type = function() {
if(this.constructor) {
var r = /\W*function\s+([\w\$]+)\(/;
var match = r.exec(this.constructor.toString());
return match ? match[1].toLowerCase() : undefined;
}
else {
return typeof this;
}
}
It's great, but there is a problem:
var foo = { 'bar' : 'eggs' };
for(var key in foo) {
alert(key);
}
There'll be 3 passages of cycle.
Is there any way to avoid this?
I, for one, am not completely against extending native types and ECMA-262 5th ed. solves the problems mentioned in other answers and linked articles for us in a nice manner. See these slides for a good overview.
You can extend any object and define property descriptors that control the behavior of those properties. The property can be made non enumerable meaning when you access the objects properties in a for..in loop, that property will not be included.
Here's how you can define a getType method on Object.prototype itself, and make it non enumerable:
Object.defineProperty(Object.prototype, "getType", {
enumerable: false,
writable: false,
configurable: false,
value: function() {
return typeof this;
}
});
// only logs "foo"
for(var name in { "foo": "bar" }) {
console.log(name);
}
The getType function above is mostly useless as it simply returns the typeof object which in most cases will simply be object, but it's only there for demonstration.
[].getType();
{}.getType();
(6).getType();
true.getType();
You shouldn't extend the object prototype, for that exact reason:
http://erik.eae.net/archives/2005/06/06/22.13.54/
Use a static method instead.
If you have no choice, you can use the "hasOwnProperty" method:
Object.prototype.foo = function(){ alert('x'); }
var x = { y: 'bar' };
for(var prop in x){
if(x.hasOwnProperty(prop)){
console.log(prop);
}
}
You can use the hasOwnProperty() method to check if the property belongs to the foo object:
var foo = { 'bar' : 'eggs' };
for (var key in foo) {
if (foo.hasOwnProperty(key)) {
alert(key);
}
}
Is there any way to avoid this?
Yes, don't extend native types.
Use a wrapper instead:
var wrapper = (function(){
var wrapper = function(obj) {
return new Wrapper(obj);
};
function Wrapper(o) {
this.obj = obj;
}
Wrapper.prototype = wrapper.prototype;
return wrapper;
}());
// Define your get_type method:
wrapper.prototype.get_type = function(){
if(this.obj.constructor) {
var r = /\W*function\s+([\w\$]+)\(/;
var match = r.exec(this.obj.constructor.toString());
return match ? match[1].toLowerCase() : undefined;
}
else {
return typeof this.obj;
}
};
Usage:
var obj = { 'bar' : 'eggs' };
alert(wrapper(obj).get_type());
for(var i in obj) { ... works properly }
When you loop over enumerable properties of an object, you can can determin if the current property was "inherited" or not with Object.hasOwnProperty()
for ( var key in foo )
{
if ( foo.hasOwnProperty( key ) )
{
alert(key);
}
}
But let the dangers of monkey patching be known to ye, especially on Object, as others have posted about
Create your own object instead of extending the default Object.
Also see:
http://erik.eae.net/archives/2005/06/06/22.13.54/
http://dean.edwards.name/weblog/2006/07/erlaubt/
STORE = {
item : function() {
}
};
STORE.item.prototype.add = function() { alert('test 123'); };
STORE.item.add();
I have been trying to figure out what's wrong with this quite a while. Why doesn't this work? However, it works when I use the follow:
STORE.item.prototype.add();
The prototype object is meant to be used on constructor functions, basically functions that will be called using the new operator to create new object instances.
Functions in JavaScript are first-class objects, which means you can add members to them and treat them just like ordinary objects:
var STORE = {
item : function() {
}
};
STORE.item.add = function() { alert('test 123'); };
STORE.item.add();
A typical use of the prototype object as I said before, is when you instantiate an object by calling a constructor function with the new operator, for example:
function SomeObject() {} // a constructor function
SomeObject.prototype.someMethod = function () {};
var obj = new SomeObject();
All the instances of SomeObject will inherit the members from the SomeObject.prototype, because those members will be accessed through the prototype chain.
Every function in JavaScript has a prototype object because there is no way to know which functions are intended to be used as constructors.
After many years, when JavaScript (ES2015 arrives) we have finally Object.setPrototypeOf() method
const STORE = {
item: function() {}
};
Object.setPrototypeOf(STORE.item, {
add: function() {
alert('test 123');
}
})
STORE.item.add();
You can use JSON revivers to turn your JSON into class objects at parse time. The EcmaScript 5 draft has adopted the JSON2 reviver scheme described at http://JSON.org/js.html
var myObject = JSON.parse(myJSONtext, reviver);
The optional reviver parameter is a
function that will be called for every
key and value at every level of the
final result. Each value will be
replaced by the result of the reviver
function. This can be used to reform
generic objects into instances of
pseudoclasses, or to transform date
strings into Date objects.
myData = JSON.parse(text, function (key, value) {
var type;
if (value && typeof value === 'object') {
type = value.type;
if (typeof type === 'string' && typeof window[type] === 'function') {
return new (window[type])(value);
}
}
return value;
});
As of this writing this is possible by using the __proto__ property. Just in case anyone here is checking at present and probably in the future.
const dog = {
name: 'canine',
bark: function() {
console.log('woof woof!')
}
}
const pug = {}
pug.__proto__ = dog;
pug.bark();
However, the recommended way of adding prototype in this case is using the Object.create. So the above code will be translated to:
const pug = Object.create(dog)
pug.bark();
Or you can also use Object.setPrototypeOf as mentioned in one of the answers.
Hope that helps.
STORE = {
item : function() {
}
};
this command would create a STORE object. you could check by typeof STORE;. It should return 'object'. And if you type STORE.item; it returns 'function ..'.
Since it is an ordinary object, thus if you want to change item function, you could just access its properties/method with this command.
STORE.item = function() { alert('test 123'); };
Try STORE.item; it's still should return 'function ..'.
Try STORE.item(); then alert will be shown.