So I was thinking if a literal object can inherit properties and methods from a class. Here is the code
var Foo = function(val1, val2) {
this.prop1 = val1;
this.prop2 = val2;
}
var bar = {
//how to inherit properties from Foo class; also add new property
prop3: 'val3'
};
You could achieve this by creating an instance of Foo and then adding properties to that instance like so:
var Foo = function(val1, val2) {
this.prop1 = val1;
this.prop2 = val2;
}
var x = new Foo('valOfProp1', 'valOfProp2');
x.prop3 = 'valOfAddedProp';
Theres no inheritance in your code. Inheritance would look like this:
var Foo = function(val1, val2) {}
Foo.prototype={
prop1:val1,
prop2:val2
};
var bar = {
//how to inherit properties from Foo class; also add new property
prop3: val3
};
And now you could do:
Object.setPrototypeOf(bar, /*to*/ Foo.prototype);
or creating another object:
var instance=new Foo();
Object.assign(instance,bar);
You may do as follows;
var Foo = function(val1, val2) {
this.prop1 = val1;
this.prop2 = val2;
};
Foo.prototype.getProp = function(p){
return this[p]; // NOT!! this.p
};
var bar = {
//how to inherit properties from Foo class; also add new property
prop3: "val3"
};
Object.setPrototypeOf(bar,Foo.prototype);
console.log(bar.getProp("prop1"));
console.log(bar.getProp("prop2"));
console.log(bar.getProp("prop3"));
Related
let construct = function(name = "john", last = "marks") {
return {
name: name,
last: last,
};
};
let me = new construct("mike", "tyson");
console.log(me);
You do not have a constructor function.
A constructor function is one you can call with the keyword new in order to produce a new instance of said function. However, yours that just produces plain objects with no inheritance:
Your implementation:
let construct = function(name = "john", last = "marks") {
return {
name: name,
last: last,
};
};
let me = new construct("mike", "tyson");
console.log(me instanceof construct); //false
Proper constructor function:
let construct = function(name = "john", last = "marks") {
this.name = name;
this.last = last;
};
let me = new construct("mike", "tyson");
console.log(me instanceof construct); //true
This matters if you want to use prototypal inheritance for the produced instances:
let construct = function(name = "john", last = "marks") {
this.name = name;
this.last = last;
};
let me = new construct("mike", "tyson");
construct.prototype.fullName = function() {
return `${this.name} ${this.last}`;
}
console.log(me.fullName()); //"mike tyson"
In order to produce proper instances with new, it needs to either return nothing (which implicitly produces undefined) or return anything other than an object:
function example() {
this.foo = "bar";
return "this is not an object";
}
console.log(example());
console.log(new example());
When defining an object literal its possible to use a self-invoking function so the function has access to private variables,
obj={
value:(function(){
var private;
return function(){
return true;
}
}())
};
But is it possible to do the same thing with a getter/setter in an object literal?
obj={
get value(){
return value;
},
set value(v) {
value=v;
}
};
[edit 2022]
A pretty old answer.
More actual: you can create a factory function. In the snippet the factory creates an object with (get and set) access (through the closure) to a private variable.
const obj1 = objFactory(`Hello`);
const obj2 = objFactory(`World`);
console.log(`${obj1.privateThing} ${obj2.privateThing}`);
obj1.privateThing = `Goodbye`;
console.log(`${obj1.privateThing} ${obj2.privateThing}`);
function objFactory(somethingPrivate) {
return {
get privateThing() { return somethingPrivate; },
set privateThing(value) { somethingPrivate = value; }
};
}
The old answer:
Not really. You can also create an Immediately Invoked Function Expression (IIFE) for obj though:
obj = function(){
var privatething = 'hithere';
return {
get value() {
return privatething;
},
set value(v) {
privatething = v;
}
};
}();
obj.value; //=> 'hithere';
obj.value = 'good morning to you too';
obj.value; //=> 'good morning to you too'
As per ES6 and later style, default values can also be set in the signature.
const _ = function(_x = 'leafy greens', _y = 'chicken', _z = 'noodle soup') {
// console.log(_x)
return {
_x,
_y,
_z,
get x() { return this._x },
set x(value) { this._x = value }
}
}()
console.log(_.x)
_.x = 'beef & pork'
console.log(_.x)
This works.
var obj = {a:1};
console.log(obj.a); //1
Object.defineProperty(obj,"a",{
get: function(){
return this.b;
},
set: function(x){
this.b = x;
},
configurable:true,
});
obj.a = 10;
console.log(obj); //10
for(var key in obj)
{
console.log(key)
}
If you don't want the property b to be enumerated while using for...in loop or Object.keys(), just add the line
Object.defineProperty(obj,"b",{enumerable:false})
Note : The above code can also be used as a listener, to detect changes in the property's value. (By implementing the needed function in the set method, after setting the value.)
var obj = {a:1};
console.log(obj.a); //1
Object.defineProperty(obj,"a",{
get: function(){
return this.b;
},
set: function(x){
this.b = x;
console.log("obj.a value has been changed to "+x);
},
configurable:true,
});
obj.a = 10;
obj.c = 20;
obj.a = 30;
I have a problem with nested object and prototyping.
In following example I'm creating 2 instances of the object "o"
var o = function(){};
o.prototype = {
val : 1,
test : {
val2 : 1
}
};
var t1 = new o();
var t2 = new o();
t1.val = 5;
t2.val = 20;
t1.test.val2 = 5;
t2.test.val2 = 10;
console.log(t1.val) //5
console.log(t2.val) //20
console.log(t1.test.val2) //10
console.log(t2.test.val2) //10
My question is why t1.test.val2 === t2.test.val2, where t1 and t2 are different variables,
shouldn't they be totally separate ??
how to fix that code to have all objects and variables inside separate ?
When you define a new object, the prototype is copied, but objects in the prototype are not deep copied; they are copied by reference. Thus, each new o instance has a copied reference to the exact same member objects of the prototype.
Instead, make the test object in your constructor so each instance has its own copy:
var o = function(){
this.test = {
val2 : 1
}
};
o.prototype = {
val : 1 // this is fine, since primitive values aren't copied by reference
};
This happens because you are modifying a property of shared object (i.e. the prototype). Your code is basically the same as:
var val = 1;
var test = {
val2 : 1
};
var t1 = {
val: val,
test: test
};
var t1 = {
val: val,
test: test
};
t1.val = 5; // changing property
t2.val = 20; // changing property
t1.test.val2 = 5; // changing property of shared object
t2.test.val2 = 10; // changing property of shared object
To fix that simply don't use prototype, i.e.
var o = function(){
this.val = 1;
this.test = {
val2 : 1
};
// test is no longer shared, exists per instance
};
I need to do a bit of quick testing with my code (getting the value of some variables inside a function), and I want to globalise them, so I can access them through the console.
I know this method:
function foo() {
var foo = 'foo';
window.foo = foo; // Make foo global
}
But what if I had something like this:
function foo() {
var foo1 = 'foo';
var foo2 = 'foo';
var foo3 = 'foo';
var foo4 = 'foo';
var foo5 = 'foo';
var foo6 = 'foo';
var foo7 = 'foo';
var foo8 = 'foo';
}
What would be a quicker way to globalise all those variables, without going window.foo1 = foo1, window.foo2 = foo2, etc.?
I don't wish this to be a code golf question, just a normal programming question.
I don't think there's a way to do this. See this:
Access all local variables
Have you tried simply debugging in the console? With Chrome, you can set a breakpoint and then inspect all values. Check out this tutorial:
https://developers.google.com/chrome-developer-tools/docs/scripts-breakpoints
Why not a single globals object instead of a bunch of variables?
function foo() {
window.globals = {
foo1 = 'foo',
foo2 = 'foo',
foo3 = 'foo',
foo4 = 'foo',
foo5 = 'foo',
foo6 = 'foo',
foo7 = 'foo',
foo8 = 'foo'
};
}
If they're all simply named like that, you can take advantage of a little known trick, variables are actually dictionaries:
function foo() {
var foo1 = 'foo';
var foo2 = 'foo';
var foo3 = 'foo';
var foo4 = 'foo';
var foo5 = 'foo';
var foo6 = 'foo';
var foo7 = 'foo';
var foo8 = 'foo';
for (var i = 1; i <= 8; i++) {
window["foo" + i] = eval("foo" + i);
}
}
document.write("Running foo...<br/>");
foo();
document.write("Printing foo...<br/>");
for (var i = 1; i <= 8; i++) {
document.write(window["foo" + i]);
}
document.write("<br/>Just one: " + foo3);// Normal variable notation
I'm trying to understand how inheritance works in JS. Suppose we have a class:
Class = function () {
this.A = 'A';
this.B = 'B';
};
and we are trying to extend it
SubClass = function () {};
SubClass.prototype = new Class();
Do I understance correctly that after inheritance properties A and B are common for all instances of SubClass, since they belong to it's prototype? If yes, how can Class be extended so that A and B do not be part of prototype?
UPD: note that Class uses A and B, so I can't declare them in SubClass.
Thank you in advance!
All I want is to make A and B be accessible and specific for each
"instance"
The typical way of doing this is to pass parameters and assign them to properties. Then you can use call to reference the super class. In other words:
function Person( name, age ) {
this.name = name;
this.age = age;
}
function Student( name, age, grade ) {
Person.call( this, name, age ); // call super-class with sub-class properties
this.grade = grade;
}
Student.prototype = new Person();
Student.prototype.constructor = Student;
var roger = new Student( 'Roger', 18, 'A+' );
You can use properties in parent class without defining:
Class = function () {
this.sum = function() {
return this.a+this.b;
}
};
SubClass = function () {
this.a = 5;
this.b = 6;
};
SubClass.prototype = new Class();
var z = new SubClass();
z.sum(); //11
Another way: Create function in prototype which creates your properties:
Class = function () {
this.makeAB = function() { //called with context of SubClass
this.A = 'A';
this.B = 'B';
}
};
SubClass = function () { this.makeAB() };
SubClass.prototype = new Class();
var z = new SubClass();
z.A = 'AAA';
z.B = 'BBB';
var z2 = new SubClass();
console.log(z)
console.log(z2)