When I tried to log the isCheckedOut setter on the console, I am getting an error testLib.isCheckedOut is not a function
I'm having a hard time figuring out why. Any help would be very great
/* Parent Class */
class Library {
constructor(title) {
this._title = title;
this._isCheckedOut = false;
this._ratings = [];
}
get title() {
return this._title;
}
get isCheckedOut() {
return this._isCheckedOut;
}
set isCheckedOut(value) {
this._isCheckedOut = value;
}
get ratings() {
return this._ratings;
}
getAverageRating() {
}
toggleCheckOutStatus() {
}
addRating() {
}
}
const testLib = new Library;
console.log(testLib.isCheckedOut(true));
Setters obfuscate the fact that they're functions to callers. When you have an object with a setter, to invoke the setter, assign to the property:
someObj.theSetterPropertyName = theArgumentToPassToSetter;
Similarly, to invoke a getter, reference the property as an expression:
someObj.theGetterPropertyName
So, you want:
class Library {
constructor(title) {
this._title = title;
this._isCheckedOut = false;
this._ratings = [];
}
get title() {
return this._title;
}
get isCheckedOut() {
return this._isCheckedOut;
}
set isCheckedOut(value) {
this._isCheckedOut = value;
}
get ratings() {
return this._ratings;
}
}
const testLib = new Library;
testLib.isCheckedOut = true; // invoke setter
console.log(testLib.isCheckedOut); // invoke getter
const testLib = new Library;
console.log(testLib.isCheckedOut = true);
JS setter
The set syntax binds an object property to a function to be called when there is an attempt to set that property.
You can't call setter like function.
a setter can be used to execute a function whenever a specified property
is attempted to be changed
Set a property using a setter:
const testLib = new Library;
testLib.isCheckedOut = true;
console.log(testLib.isCheckedOut);
Calling a function:
const testLib = new Library;
testLib.addRating();
I was having the same issue at this lesson, only used empty brackets instead of .isCheckedOut(true). Got the same error.
console.log(testLib.isCheckedOut(true));
Remove the brackets altogether after the isCheckedOut property and it'll work:
console.log(testLib.isCheckedOut);
is there a way to listen for a property call on a JavaScript Class
for example when i go something like this:
myForm = new Form();
myForm.name = 'Name';
-> when i set the name i dont only want to set the property but i also want to update my Vuex store.
Same thing with get i would like to read from Vuex store.
I knoew there are thins like Proxy but for this i need to wrap my Class with a Proxy object. Not so sure if i like this.
module.exports = new Proxy(new Form({}), {
get (receiver, name) {
console.log('getting property from Vuex Store');
}
});
What i need is something like this:
module.exports = class Form {
//this should be triggered when form.something
get(property) {
return this[property];
}
//this should be triggered when from.something = 'something'
set(property, value) {
return this[property] = value;
}
};
it there a best practice for this?
Javascript supports getters and setters
class Form{
set foo(val){
console.log("setting foo")
this.fooValue = val;
}
get foo(){
console.log("getting foo");
return this.fooValue;
}
}
let frm = new Form();
frm.foo = "bar";
console.log(frm.foo);
You could make this more dynamic by writing a withGetterSetter method which wraps each property of an object with a getter/setter.
var form = {
a: "aValue",
b: "bValue"
}
function withGetterSetter(obj){
var keys = Object.keys(obj);
var result = {};
for(var i=0;i<keys.length;i++){
var key = keys[i];
result[key+"_internal"] = obj[key];
(function(k){
Object.defineProperty(result,k, {
get:function() {
console.log("getting property:",k);
return this[k + "_internal"];
},
set: function(x) {
console.log("setting property:",k);
this[k + "_internal"] = x
}
});
})(key)
}
return result;
}
var setterObj = withGetterSetter(form);
console.log(setterObj.a);
setterObj.a = "updated";
console.log(setterObj.a);
It works by copying each property p to a new object with p_internal and creating a dynamic get/set for the original property name.
var user = {
Name: "Some user",
Methods: {
ShowGreetings: function() {
// at this point i want to access variable "Name",
//i dont want to use user.Name
// **please suggest me how??**
},
GetUserName: function() { }
}
}
You can't.
There is no upwards relationship in JavaScript.
Take for example:
var foo = {
bar: [1,2,3]
}
var baz = {};
baz.bar = foo.bar;
The single array object now has two "parents".
What you could do is something like:
var User = function User(name) {
this.name = name;
};
User.prototype = {};
User.prototype.ShowGreetings = function () {
alert(this.name);
};
var user = new User('For Example');
user.ShowGreetings();
var user = {
Name: "Some user",
Methods: {
ShowGreetings: function() {
alert(this.Parent.Name); // "this" is the Methods object
},
GetUserName: function() { }
},
Init: function() {
this.Methods.Parent = this; // it allows the Methods object to know who its Parent is
delete this.Init; // if you don't need the Init method anymore after the you instanced the object you can remove it
return this; // it gives back the object itself to instance it
}
}.Init();
Crockford:
"A privileged method is able to access the private variables and
methods, and is itself accessible to the public methods and the
outside"
For example:
function user(name) {
var username = name;
this.showGreetings = function()
{
alert(username);
}
}
You can try another approach using a closure:
function userFn(name){
return {
Methods: {
ShowGreetings: function() {
alert(name);
}
}
}
}
var user = new userFn('some user');
user.Methods.ShowGreetings();
Old question but why can't you just do something like this :
var user = {
Name: "Some user",
Methods: {
ShowGreetings: function() {
// at this point i want to access variable "Name",
//i dont want to use user.Name
// **please suggest me how??**
var thisName = user.Name; //<<<<<<<<<
},
GetUserName: function() { }
}
}
Because you will only call user.Methods.ShowGreetings() after the user has been instantiated. So you will know about the variable 'user' when you want to use its name ?
As others have said, with a plain object it is not possible to lookup a parent from a nested child.
However, it is possible if you employ recursive ES6 Proxies as helpers.
I've written a library called ObservableSlim that, among other things, allows you to traverse up from a child object to the parent.
Here's a simple example (jsFiddle demo):
var test = {"hello":{"foo":{"bar":"world"}}};
var proxy = ObservableSlim.create(test, true, function() { return false });
function traverseUp(childObj) {
console.log(JSON.stringify(childObj.__getParent())); // returns test.hello: {"foo":{"bar":"world"}}
console.log(childObj.__getParent(2)); // attempts to traverse up two levels, returns undefined because test.hello does not have a parent object
};
traverseUp(proxy.hello.foo);
Very late to the party, but this works
var user = {
Name: "Some user",
Methods() {
return {
that: this,
ShowGreetings: function() {
console.log(this.that.Name)
},
GetUserName: function() { }
}
}
}
user.Methods().ShowGreetings() // Some user
David Dorward's right here. The easiest solution, tho, would be to access user.Name, since user is effectively a singleton.
ES6 Classes
One simple solution would be to create a Class with methods!
class User {
// Assign properties when an instance
// is created using the `new` keyword
constructor(name) {
this.name = name;
}
// Methods:
showGreetings() {
console.log(`Hello, ${this.name}!`);
}
getUserName() {
return this.name;
}
// Or rather, use Getters:
get username() {
return this.name;
}
}
// Create a new user:
const user = new User("Praveen");
// Use methods:
user.showGreetings(); // "Hello, Praveen!"
console.log(user.getUserName()); // "Praveen"
console.log(user.username); // "Praveen"
Why the above suggestion? Mostly because:
you cannot reference a parent Object from a child Object directly
const User = {
name: "Some user", // hardcoded stuff? Is this an intentional Singleton?
methods: { // <<< Child Object of User
sayName() {
// Sadly, `this` refers to `methods`, not to `user`:
console.log(this); // methods{}
console.log(User.name); // "Some user" // Get Singleton's name
// ... but that's not what you want.
}
}
};
User.methods.sayName();
// ^^^^^^^ Why would you want this `methods` anyways?!
and it makes no sense to hardcode Strings (like "Some user") inside an Object Singleton — which could actually be a reusable function Object.
If you want to associate a child Node to a parent Node — read this answer (Get value of parent Object).
How about this way?
user.Methods.ShowGreetings.call(user, args);
So you can access user.Name in ShowGreetings
var user = {
Name: "Some user",
Methods: {
ShowGreetings: function(arg) {
console.log(arg, this.Name);
},
GetUserName: function() { }
},
Init: function() {
this.Methods.ShowGreetings.call(this, 1);
}
};
user.Init(); // => 1 "Some user"
As a variant:
var user = (obj => {
Object.keys(obj.Methods).map(option => {
const currOpt = obj.Methods[option];
if (currOpt instanceof Function) {
obj.Methods[option] = currOpt.bind(obj);
};
});
return obj;
})({
Name: "Some user",
Methods: {
Greeting: function () { return this.Name },
GetUserName: function() { console.log(this) }
},
});
But I don't know why somebody can use this strange approach
I know I'm very late.
I wrote this simple method. Let's say you have:
{
subObj: {
x:'hello_world';
}
}
Then, if you want a reference to the bigger object from subObj, you can convert it to a function, and utilize this.
var tmpVal=reference_to_subObj; //keep value of subObj safe
reference_to_subObj=function(){return this;}//this returns the scope, here the parent
var parent=reference_to_subObj(); //call the function
reference_to_subObj=tmpVal; delete tmpVal; //set things back to normal
//Now you have variable 'parent'.
I used a Function() constructor because it let me create the function as a string, so I could pass a string as code.
function findParent(stringReference) {
Function(/*same as above, except filled in all reference_to_subObj with stringReference.*/
//stringReference is a stringified version of dot or bracket notation.
So I could call findParent('obj.subObj').
// Make user global
window.user = {
name: "Some user",
methods: {
showGreetings: function () {
window.alert("Hello " + this.getUserName());
},
getUserName: function () {
return this.getParent().name;
}
}
};
// Add some JavaScript magic
(function () {
var makeClass = function (className) {
createClass.call(this, className);
for (key in this[className]) {
if (typeof this[className][key] === "object") {
makeClass.call(this[className], key);
}
}
}
var createClass = function (className) {
// private
var _parent = this;
var _namespace = className;
// public
this[className] = this[className] || {};
this[className].getType = function () {
var o = this,
ret = "";
while (typeof o.getParent === "function") {
ret = o.getNamespace() + (ret.length === 0 ? "" : ".") + ret;
o = o.getParent();
}
return ret;
};
this[className].getParent = function () {
return _parent;
};
this[className].getNamespace = function () {
return _namespace;
}
};
makeClass.call(window, "user");
})();
user.methods.showGreetings();
I ran across this old post trying to remember how to solve the problem. Here is the solution I used. This is derived from Pro JavaScript Design Patterns by Harmes and Diaz (Apress 2008) on page 8. You need to declare a function and then create a new instance of it as shown below. Notice the Store method can access "this".
function Test() {
this.x = 1;
}
Test.prototype = {
Store: function (y) { this.x = y; },
}
var t1 = new Test();
var t2 = new Test();
t1.Store(3);
t2.Store(5);
console.log(t1);
console.log(t2);
Like #Quentin said, there is no upwards relationship in JS. However try this workaround;
foo = { bar: {parent: foo} };
console.log(foo);
console.log(foo.bar.parent);
which is also similar to;
function Foo(){
this.bar = {parent: this}
}
foo = new Foo();
console.log(foo);
console.log(foo.bar.parent);
I need to add setter to the below JavaScript Module:
In the below code I am simply returning the form data to the module object.
I need to add setter functionality so that I can do minimal check on the user input.
var Mod = (function(){
var module = {};
var element = document.forms.[0];
Object.defineProperty(module, 'Country', {
get: function () {
return element.txtCountry.value;
}
});
Object.defineProperty(module, 'City', {
get: function () {
return element.txtCity.value;
}
});
return module;
})();
However, all of the examples I have come across, including those on MDN shows an object with literal values:
Like this one:
var module = {
Country: "United States",
get function() {
return this.Country;
},
set function(x) {
this.Country = x + ' ' + somethingElse;
}
};
How do I add the setter to return data to the object without literal object members?
Finally I am calling the module like this:
var btn = document.getElementById( 'btnDataEntry' );
var result = document.getElementById('result');
btn.addEventListener('click', function(e) {
var t = document.createTextNode(Mod.Country + ',' + Mod.City);
result.appendChild(t);
e.preventDefault();
}, false);
Update (Additional Info):
In the most simplest form I want to perform checks in the setter, something like this:
var Mod = (function(){
var module = {};
var element = document.forms.dataEntry;
Object.defineProperty(module, 'Country', {
get: function () {
return Country;
},
set: function(val) {
if( val == 'A') {
val = element.txtCountry.value;
}
}
});
return module;
})();
Update: (Solution).
So as simple as this may seem, it can become confusing because JavaScript is more abstract when it comes to how one can accomplish certain task.
The problem is, when using setter in an Object.defineProperty() method, you have to pass the value using a dot notation to the object, and by also using a variable within the scope of the function to emulate a private member.
If you look at my previous code, you will see that I was passing the form data directly within the getter, this defeats the entire purpose of having a getter/setter.
Here is a complete working code: Based on readings and example from the following book: The Principles of Object-Oriented JavaScript: By Nicholas C. Zakas.
Code:
var LocationData = (function(){
var location = {};
//Private member to eliminate global scope
var _country;
Object.defineProperty(location, "Country", {
get: function() {
return this._country;
},
set: function(value) {
if(value === 'A') {
this._country = value;
} else {
this._country = 'X';
}
}
});
return location;
})();
var btn = document.getElementById( 'btnDataEntry' );
var result = document.getElementById('result');
btn.addEventListener('click', function(e) {
var element = document.forms[0];
//Pass the value to the method
LocationData.Country = element.txtCountry.value;
var t = document.createTextNode(LocationData.Country);
result.appendChild(t);
e.preventDefault();
}, false);
Define the setter in the same defineProperty call where you define the getter:
Object.defineProperty(module, 'City', {
get: function () {
return element.txtCity.value;
},
set: function (value) {
// do minimal check
element.txtCity.value = value;
}
});
Lets say I have this class:
function classA(n){
this.name = n
}
classA.prototype.getName = function(){
return this.name
}
var x = new classA('john')
console.log(x.getName())
My question is: can I group multiple methods inside a namespace? So I would like to do that:
var x = new classA('john')
console.log(x.CONSTANT.getName())
So I would like to call some methods as x.someMethod() and others as x.CONSTANT.otherMethod()
PS: I'm looking for a cross-browser method. Bind is not working in Safari and IE9.
You can do it, for example, via bind. Google es5 shim for implementation of bind in browsers, which don't support it natively.
function MyClass(name) {
this.name = name;
this.CONSTANT.otherMethod = this.CONSTANT.otherMethod.bind(this);
}
MyClass.prototype.CONSTANT = {
otherMethod: function() {
alert(this.name);
}
};
As far as I know a constant is just a property and it can't contain methods, you need to separate your objects and use methods to have the same effect:
function A (id) {
this.id = id;
this.showId = function () { return this.id; }
};
function B (a) {
this.a = a;
this.getA = function () { return this.a; }
}
var a = new A(12);
var b = new B(a);
b.getA().showId();
edit:
You can use a literal object as follow
function B (id) {
this.id = id;
this.CONSTANT = { otherMethod: function () { alert("..."); } };
someMethod = function () { return this.id; }
}
but the literal CONSTANT object can't access B-object methods,
Consider the #kirilloid post to round this.
You can, but you have to be careful because it won't act like you think it will. The this for the method will be the namespace, not the root object.
For example, in x.CONSTANT.getName(), the this object will be x.CONSTANT, and not x.
Here's some sample code which kinda does what you ask (or in jsfiddle):
function MyClass() {}
MyClass.prototype.CONSTANT = {
getName: function() {
alert('Foo');
}
};
var c = new MyClass();
c.CONSTANT.getName();
To make sure the this is right, you need to do much more.
You can use getters/setters (read this article) to achieve this. For example you may define it like this:
classA.prototype.__defineGetter__('CONSTANT', function() {
var that = this;
return {
getName: function() {
return that.name;
}
};
});
Note that holding reference to the object. It will work now
x = new classA('test');
x.CONSTANT.getName();
// result - test