I am just learning javascript and I need to know how I will go about doing this please:
Task: Merge the given objects into var C
var a = {
name: "Danny"
};
var b = {
getName: function () {
return this.name;
}
};
Output should be danny
var solve = function () {
var C;
var instance = new C();
console.log("Name: "+ instance.getName());
};
solve();
You can use Object.assign() to merge existing objects into any other object. The syntax is:
Object.assign(target, src1, src2, ....);
And, here it is working with your code:
var a = {
name: "Danny"
};
var b = {
getName: function () {
return this.name;
}
};
var C = function() {
Object.assign(this, a, b);
}
var instance = new C();
console.log("Name: "+ instance.getName());
Related
I am trying to figure out how to put an object to a function and return that
object with its original values.
It's part from my "framework"...
Here an simplified example:
var _objectToFunction = function (obj) {
var F = function () { }
F.prototype = obj
return F
}
var myclass = {
a:"abc",
print: function(){
console.log("i am a func")
},
config: {
path: "c:/bla"
}
}
var fo = _objectToFunction(myclass)
var of = new fo()
of.config.path = "c:/ofpath"
of.z = "zzz"
of.a ="aaa"
console.log(of)
var fo2 = _objectToFunction(myclass)
var of2 = new fo2()
console.log(of2.z)
console.log(of2.a)
console.log(of2.config.path)
The output from console.log(of2.config.path) should "c:/bla", but is "c:/ofpath".
How can I do this right?
You may want to add a constructor (a function that is called, when an instance was created):
var _objectToFunction = function (obj) {
var F = function (...values) {
if( this.constructor) this.constructor(...values);
}
F.prototype = obj
return F
}
So you can create a new config Object for each instance:
var myclass = {
constructor:function(addconf){
this.config=Object.create(this.config);
if(addconf) Object.assign(this.config,addconf);
},
a:"abc",
print: function(){
console.log("i am a func")
},
config: {
path: "c:/bla"
}
}
Now it behaves as wanted.
var parent=_objectToFunction(myclass);
var instance=new parent({ path:"changed"});
Or with standard object funcs:
var instance=Object.create(myclass);
instance.constructor({path:"changed"});
I've got two object prototypes like this:
function Tag(name, description) {
this.name = name;
this.description = description || null;
}
function Category(name, description) {
this.name = name;
this.description = description || null;
}
Both of them are exactly the same, which seems awkward. Is it possible to merge them both into an object named 'Entity', and refer to them both by different names (the original 'Tag' and 'Category')?
This may be further complicated by the fact I need to refer to the current prototype name inside the prototype.
Tag.prototype.toJSON = function() {
return {
__type: 'Tag',
name: this.name,
description: this.description
};
};
How can I apply the same 'toJSON' extension to the 'Entity' object, but make sure it returns 'Tag' or 'Category' in the '__type' field, dependent on which object is being used?
I would do something like this:
Dummy = function () {};
Entity = function (name) {
this.name = name;
};
Entity.prototype.toString = function () {
return "My name is " + this.name + ".";
};
A = function () {
Entity.call(this, 'A');
};
Dummy.prototype = Entity.prototype;
Dummy.prototype.constructor = A;
A.prototype = new Dummy();
B = function () {
Entity.call(this, 'B');
};
Dummy.prototype = Entity.prototype;
Dummy.prototype.constructor = B;
B.prototype = new Dummy();
document.body.innerHTML = ""
+ (new A()) + "<br />"
+ (new B());
Here is a small function to make things cleaner (hopefully):
function Nothing () {};
function extend (Sup, proto) {
function Class () {
if (this.init) {
this.init.apply(this, arguments);
}
}
Nothing.prototype = Sup.prototype;
Nothing.prototype.constructor = Sup;
Class.prototype = new Nothing();
delete Nothing.prototype;
for (var k in proto) {
Class.prototype[k] = proto[k];
}
return Class;
}
Here is how to use it:
Entity = extend(Nothing, {
init: function (name) {
this.name = name;
},
toString: function () {
return "My name is " + this.name + ".";
}
});
A = extend(Entity, {
init: function () {
var sup = Entity.prototype;
sup.init.call(this, 'A');
}
});
B = extend(Entity, {
init: function () {
var sup = Entity.prototype;
sup.init.call(this, 'B');
}
});
My function gets model name as string, I need to create new instance of object based on its name.
ex.:
modelName = 'MockA';
model = new modelName();
this is ofcourse not working. in php i would use
model = new $$modelName
thanks in advance
If MockA is in global scope you can use:
var model = new window[modelName]();
if not then you should reconsider the way you store your models, eg. with an object of models:
var my_models = {
MockA: function() {},
MockB: function() {}
}
and to access
var MockA = my_models.MockA;
// or
var model_name = 'MockA';
var MockA = my_models[model_name];
You can use an object factory or bracket notation.
Sample of code:
// First example: Use a Factory
var MockA = function() {
this.sayHello = function() {
console.log('Hi from MockA ');
};
},
MockB = function() {
this.sayHello = function() {
console.log('Hi from MockB ');
}
},
factory = function(type) {
var obj;
switch (type) {
case 'MockA':
obj = new MockA();
break;
case 'MockB':
obj = new MockB();
break;
}
return obj;
}
var objA = factory('MockA');
objA.sayHello();
var objB = factory('MockB');
objB.sayHello();
// Second example: Using bracket notation
var models = {
BaseMockA: {
sayHello: function() {
console.log('Hi from BaseMockA ');
}
},
BaseMockB: {
sayHello: function() {
console.log('Hi from BaseMockB ');
}
}
};
var baseObjA = Object.create(models['BaseMockA']);
baseObjA.sayHello();
var baseObjB = Object.create(models['BaseMockB']);
baseObjB.sayHello();
I have a sealed object with an array member on which I want to prevent direct pushes.
var myModule = (function () {
"use strict";
var a = (function () {
var _b = {},
_c = _c = "",
_d = [];
Object.defineProperty(_b, "c", {
get: function () { return _c; }
});
Object.defineProperty(_b, "d", {
get { return _d; }
});
_b.addD = function (newD) {
_d.push(newD);
};
Object.seal(_b);
return _b;
}());
var _something = { B: _b };
return {
Something: _something,
AddD: _b.addD
};
}());
myModule.Something.c = "blah"; // doesn't update = WIN!!
myModule.AddD({}); // pushed = WIN!
myModule.Something.d.push({}); // pushed = sadness
How can I prevent the push?
UPDATE:
Thanks for all the thoughts. I eventually need the JSON to send to the server. It looks like I might need to use an object for the array then figure out a way to generate and return the JSON needed, or change _something to use .slice(). Will play and report.
you could override the push method:
var _d = [];
_d.__proto__.push = function() { return this.length; }
and when you need to use it in your module, call Array.prototype.push:
_b.addD = function (newD) {
Array.prototype.push.call(_d, newD);
};
I haven't done any performance tests on this, but this certainly helps to protect your array.
(function(undefined) {
var protectedArrays = [];
protectArray = function protectArray(arr) {
protectedArrays.push(arr);
return getPrivateUpdater(arr);
}
var isProtected = function(arr) {
return protectedArrays.indexOf(arr)>-1;
}
var getPrivateUpdater = function(arr) {
var ret = {};
Object.keys(funcBackups).forEach(function(funcName) {
ret[funcName] = funcBackups[funcName].bind(arr);
});
return ret;
}
var returnsNewArray = ['Array.prototype.splice'];
var returnsOriginalArray = ['Array.prototype.fill','Array.prototype.reverse','Array.prototype.copyWithin','Array.prototype.sort'];
var returnsLength = ['Array.prototype.push','Array.prototype.unshift'];
var returnsValue = ['Array.prototype.shift','Array.prototype.pop'];
var funcBackups = {};
overwriteFuncs(returnsNewArray, function() { return []; });
overwriteFuncs(returnsOriginalArray, function() { return this; });
overwriteFuncs(returnsLength, function() { return this.length; });
overwriteFuncs(returnsValue, function() { return undefined; });
function overwriteFuncs(funcs, ret) {
for(var i=0,c=funcs.length;i<c;i++)
{
var func = funcs[i];
var funcParts = func.split('.');
var obj = window;
for(var j=0,l=funcParts.length;j<l;j++)
{
(function() {
var part = funcParts[j];
if(j!=l-1) obj = obj[part];
else if(typeof obj[part] === "function")
{
var funcBk = obj[part];
funcBackups[funcBk.name] = funcBk;
obj[part] = renameFunction(funcBk.name, function() {
if(isProtected(this)) return ret.apply(this, arguments);
else return funcBk.apply(this,arguments);
});
}
})();
}
}
}
function renameFunction(name, fn) {
return (new Function("return function (call) { return function " + name +
" () { return call(this, arguments) }; };")())(Function.apply.bind(fn));
};
})();
You would use it like so:
var myArr = [];
var myArrInterface = protectArray(myArr);
myArr.push(5); //Doesn't work, but returns length as expected
myArrInterface.push(5); //Works as normal
This way, you can internally keep a copy of the interface that isn't made global to allow your helper funcs to modify the array as normal, but any attempt to use .push .splice etc will fail, either directly, or using the .bind(myArr,arg) method.
It's still not completely watertight, but a pretty good protector. You could potentially use the Object.defineProperty method to generate protected properties for the first 900 indexes, but I'm not sure of the implications of this. There is also the method Object.preventExtensions() but I'm unaware of a way to undo this effect when you need to change it yourself
Thank you, dandavis!
I used the slice method:
var myModule = (function () {
"use strict";
var a = (function () {
var _b = {},
_c = _c = "",
_d = [];
Object.defineProperty(_b, "c", {
get: function () { return _c; }
});
Object.defineProperty(_b, "d", {
get { return _d.slice(); } // UPDATED
});
_b.updateC = function (newValue) {
_c = newValue;
};
_b.addD = function (newD) {
_d.push(newD);
};
Object.seal(_b);
return _b;
}());
var _something = { B: _b };
return {
Something: _something,
AddD: _b.addD
};
}());
myModule.Something.c = "blah"; // doesn't update = WIN!!
myModule.AddD({}); // pushed = WIN!
myModule.Something.d.push({}); // no more update = happiness
This allows me to protect from direct push calls enforcing some logic.
In Douglas Crockford's JavaScript: The Good Parts he recommends that we use functional inheritance. Here's an example:
var mammal = function(spec, my) {
var that = {};
my = my || {};
// Protected
my.clearThroat = function() {
return "Ahem";
};
that.getName = function() {
return spec.name;
};
that.says = function() {
return my.clearThroat() + ' ' + spec.saying || '';
};
return that;
};
var cat = function(spec, my) {
var that = {};
my = my || {};
spec.saying = spec.saying || 'meow';
that = mammal(spec, my);
that.purr = function() {
return my.clearThroat() + " purr";
};
that.getName = function() {
return that.says() + ' ' + spec.name + ' ' + that.says();
};
return that;
};
var kitty = cat({name: "Fluffy"});
The main issue I have with this is that every time I make a mammal or cat the JavaScript interpreter has to re-compile all the functions in it. That is, you don't get to share the code between instances.
My question is: how do I make this code more efficient? For example, if I was making thousands of cat objects, what is the best way to modify this pattern to take advantage of the prototype object?
Well, you just can't do it that way if you plan on making lots of mammal or cat. Instead do it the old fashioned way (prototype) and inherit by property. You can still do the constructors the way you have above but instead of that and my you use the implicit this and some variable representing the base class (in this example, this.mammal).
cat.prototype.purr = function() { return this.mammal.clearThroat() + "purr"; }
I'd use another name than my for base access and store it in this in the cat constructor. In this example I used mammal but this might not be the best if you want to have static access to the global mammal object. Another option is to name the variable base.
Let me introduce you to Classical Inheritance that never uses prototype. This is a bad coding exercise but will teach you the real Classical Inheritance which always compared to prototypal inheritance:
Make a custructor:
function Person(name, age){
this.name = name;
this.age = age;
this.sayHello = function(){return "Hello! this is " + this.name;}
}
Make another cunstructor that inherits from it:
function Student(name, age, grade){
Person.apply(this, [name, age]);
this.grade = grade
}
Very simple! Student calls(applies) Person on itself with name and age arguments takes care of grade arguments by itself.
Now lets make an instance of Student.
var pete = new Student('Pete', 7, 1);
Out pete object will now contain name, age, grade and sayHello properties. It owns all those properties. They are not uplinked to Person through prototype. If we change Person to this:
function Person(name, age){
this.name = name;
this.age = age;
this.sayHello = function(){
return "Hello! this is " + this.name + ". I am " this.age + " years old";
}
}
pete will no recieve the update. If we call pete.sayHello, ti will return Hello! this is pete. It will not get the new update.
if you want privacy and you dont like protyping you may or may-not like this approach:
(note.: it uses jQuery.extend)
var namespace = namespace || {};
// virtual base class
namespace.base = function (sub, undefined) {
var base = { instance: this };
base.hierarchy = [];
base.fn = {
// check to see if base is of a certain class (must be delegated)
is: function (constr) {
return (this.hierarchy[this.hierarchy.length - 1] === constr);
},
// check to see if base extends a certain class (must be delegated)
inherits: function (constr) {
for (var i = 0; i < this.hierarchy.length; i++) {
if (this.hierarchy[i] == constr) return true;
}
return false;
},
// extend a base (must be delegated)
extend: function (sub) {
this.hierarchy.push(sub.instance.constructor);
return $.extend(true, this, sub);
},
// delegate a function to a certain context
delegate: function (context, fn) {
return function () { return fn.apply(context, arguments); }
},
// delegate a collection of functions to a certain context
delegates: function (context, obj) {
var delegates = {};
for (var fn in obj) {
delegates[fn] = base.fn.delegate(context, obj[fn]);
}
return delegates;
}
};
base.public = {
is: base.fn.is,
inherits: base.fn.inherits
};
// extend a sub-base
base.extend = base.fn.delegate(base, base.fn.extend);
return base.extend(sub);
};
namespace.MyClass = function (params) {
var base = { instance: this };
base.vars = {
myVar: "sometext"
}
base.fn = {
init: function () {
base.vars.myVar = params.myVar;
},
alertMyVar: function() {
alert(base.vars.myVar);
}
};
base.public = {
alertMyVar: base.fn.alertMyVar
};
base = namespace.base(base);
base.fn.init();
return base.fn.delegates(base,base.public);
};
newMyClass = new namespace.MyClass({myVar: 'some text to alert'});
newMyClass.alertMyVar();
the only downside is that because of the privacy scope you can only extend the virtual classes and not the instanceable classes.
here is an example of how i extend the namespace.base, to bind/unbind/fire custom events.
// virtual base class for controls
namespace.controls.base = function (sub) {
var base = { instance: this };
base.keys = {
unknown: 0,
backspace: 8,
tab: 9,
enter: 13,
esc: 27,
arrowUp: 38,
arrowDown: 40,
f5: 116
}
base.fn = {
// bind/unbind custom events. (has to be called via delegate)
listeners: {
// bind custom event
bind: function (type, fn) {
if (fn != undefined) {
if (this.listeners[type] == undefined) {
throw (this.type + ': event type \'' + type + '\' is not supported');
}
this.listeners[type].push(fn);
}
return this;
},
// unbind custom event
unbind: function (type) {
if (this.listeners[type] == undefined) {
throw (this.type + ': event type \'' + type + '\' is not supported');
}
this.listeners[type] = [];
return this;
},
// fire a custom event
fire: function (type, e) {
if (this.listeners[type] == undefined) {
throw (this.type + ': event type \'' + type + '\' does not exist');
}
for (var i = 0; i < this.listeners[type].length; i++) {
this.listeners[type][i](e);
}
if(e != undefined) e.stopPropagation();
}
}
};
base.public = {
bind: base.fn.listeners.bind,
unbind: base.fn.listeners.unbind
};
base = new namespace.base(base);
base.fire = base.fn.delegate(base, base.fn.listeners.fire);
return base.extend(sub);
};
To proper use Javascript-prototype based inheritance you could use fastClass https://github.com/dotnetwise/Javascript-FastClass
You have the simpler inheritWith flavor:
var Mammal = function (spec) {
this.spec = spec;
}.define({
clearThroat: function () { return "Ahem" },
getName: function () {
return this.spec.name;
},
says: function () {
return this.clearThroat() + ' ' + spec.saying || '';
}
});
var Cat = Mammal.inheritWith(function (base, baseCtor) {
return {
constructor: function(spec) {
spec = spec || {};
baseCtor.call(this, spec);
},
purr: function() {
return this.clearThroat() + " purr";
},
getName: function() {
return this.says() + ' ' + this.spec.name + this.says();
}
}
});
var kitty = new Cat({ name: "Fluffy" });
kitty.purr(); // Ahem purr
kitty.getName(); // Ahem Fluffy Ahem
And if you are very concerned about performance then you have the fastClass flavor:
var Mammal = function (spec) {
this.spec = spec;
}.define({
clearThroat: function () { return "Ahem" },
getName: function () {
return this.spec.name;
},
says: function () {
return this.clearThroat() + ' ' + spec.saying || '';
}
});
var Cat = Mammal.fastClass(function (base, baseCtor) {
return function() {
this.constructor = function(spec) {
spec = spec || {};
baseCtor.call(this, spec);
};
this.purr = function() {
return this.clearThroat() + " purr";
},
this.getName = function() {
return this.says() + ' ' + this.spec.name + this.says();
}
}
});
var kitty = new Cat({ name: "Fluffy" });
kitty.purr(); // Ahem purr
kitty.getName(); // Ahem Fluffy Ahem
Btw, your initial code doesn't make any sense but I have respected it literally.
fastClass utility:
Function.prototype.fastClass = function (creator) {
var baseClass = this, ctor = (creator || function () { this.constructor = function () { baseClass.apply(this, arguments); } })(this.prototype, this)
var derrivedProrotype = new ctor();
if (!derrivedProrotype.hasOwnProperty("constructor"))
derrivedProrotype.constructor = function () { baseClass.apply(this, arguments); }
derrivedProrotype.constructor.prototype = derrivedProrotype;
return derrivedProrotype.constructor;
};
inheritWith utility:
Function.prototype.inheritWith = function (creator, makeConstructorNotEnumerable) {
var baseCtor = this;
var creatorResult = creator.call(this, this.prototype, this) || {};
var Derrived = creatorResult.constructor ||
function defaultCtor() {
baseCtor.apply(this, arguments);
};
var derrivedPrototype;
function __() { };
__.prototype = this.prototype;
Derrived.prototype = derrivedPrototype = new __;
for (var p in creatorResult)
derrivedPrototype[p] = creatorResult[p];
if (makeConstructorNotEnumerable && canDefineNonEnumerableProperty) //this is not default as it carries over some performance overhead
Object.defineProperty(derrivedPrototype, 'constructor', {
enumerable: false,
value: Derrived
});
return Derrived;
};
define utility:
Function.prototype.define = function (prototype) {
var extendeePrototype = this.prototype;
if (prototype)
for (var p in prototype)
extendeePrototype[p] = prototype[p];
return this;
}
[* Disclaimer, I am the author of the open source package and the names of the methods themselves might be renamed in future` *]