Let say that i need to create a javascript library like so:
;(function(){
var root = this;
var Ctor = function(value) {
this.value = value;
};
var _ = new Ctor(value);
_.doSome = function(value) {
// do some work to the value
// if no value assigned, get the value of the previous method
};
_.doSome2 = function(value) {
// do some work to the value
// if no value assigned, get the value of the previous method
};
_.doSome3 = function(value) {
// do some work to the value
// if no value assigned, get the value of the previous method
};
root._ = _;
}.call(this));
If doSome method work the value of the _ object, and doSome2 and doSome3 too.
But what about chaining the methods like so:
// the doSome2 and doSome3 work with the value of doSome
_.doSome(value).doSome2().doSome3();
// the doSome3 work with the value of doSome2 cuz it has a value
_.doSome(value).doSome2(value).doSome3();
// every method work with the value assigned to it
_.doSome(value).doSome2(value).doSome3(value); // the same as:
_.doSome(value);
_.doSome2(value);
_.doSome3(value);
note: methods can be chained randomly, like:
_.doSome2(value).doSome().doSome3();
Live example: https://jsbin.com/vijehotora/edit?js,console
You could do something like this:
var Ctor = function() {};
Ctor.prototype = {
doSome: function(value) {
if(value) {
this.value = value;
}
return this;
},
doSome2: function(value) {
if(value) {
this.value = value;
}
return this;
}
};
new Ctor().doSome('value1').doSome2('value2').doSome();
Working example
Related
I would like to know what's the difference between these notations :
function Forms (formSelector) {
this.id;
this.formSelector = formSelector;
}
Forms.prototype.getAll = function () { return $(this.formSelector) } // get all forms in a JQuery object
Forms.prototype.get = function () { return $(this.getAll()).get(this.id) }
And
function Forms (formSelector) {
this.id;
this.formSelector = formSelector;
this.getAll = function () { return $(this.formSelector) }
this.get = function () { return $(this.getAll()).get(this.id) }
}
Or even
function Forms (formSelector) {
this.id;
this.formSelector = formSelector;
this.getAll = $(this.formSelector);
this.get = $(this.getAll()).get(this.id);
}
I can even write something like this:
var Forms = {
constructor: function (formSelector) {
this.formSelector = formSelector;
return this.formSelector;
},
setId: function (id) { if (!isNaN(id) this.id = id; }
getAll: function () {
return $(Forms.constructor.formSelector); // this should work I think ?
}
}
This is so confusing to me, I don't quite get to figure out what's the best and more optimized way to write my objects, in terms of speed and clarity, and to encapsulate their methods and properties.
In any case, it seems that I can modify my properties by just stating something like:
var test = new Forms('.forms');
test.id = 10;
test.getAll = 'something';
// What I want is something like :
test.setId(10) // and test.id = X shouldn't work
Thanks!
It's 2018 and almost all browsers support ES6 classes now, except IE 11 of course. But you can use babel to transpile your code if you want to support older browsers.
That being said, this is how you'd write a class OOP way in JavaScript.
class Form {
constructor(formSelector) {
this.id = 'default value';
this.formSelector = formSelector;
// probably also check if $ is defined
}
// you can use getter method
get id() {
return this.id;
}
// you can use setter method
set id(idVal) {
this.id = idVal;
}
get formSelector() {
return this.id;
}
set formSelector(val) {
this.formSelector = val;
}
getAll() {
return $(this.formSelector);
// whatever getAll is supposed to return
}
}
You would use this class as
const myForm = new Form('form-selector-value');
// no brackets for getter and setter
const formId = form.id; // get id value
form.id = 'some-val'; // set id value
form.getAll(); // invoke the get all method
// you can change the formSelector anytime for `form` variable
form.formSelector = 'some-value';
I need to add new objects to the list (Filters.list)
* Filters.prop - is a default prop
* list items also have prop - list[name].prop (equal default prop)
Chage default Filters.prop -> [not] change item list[name].prop
Where is the mistake?
function Filters() {
this.prop = 'some';
this.list = { };
this.add = function (name) {
this.list[name] = {
prop: this.prop,
};
}
}
let attempt = new Filters();
attempt.add('first');
attempt.prop = 'other';
document.writeln(attempt.prop);
document.writeln(attempt.list['first'].prop);
After run snippet output: other some
But I need: other other
I thought the property would be saved by reference. But this is not so, it does not change. When I change Filters.prop I expected that too it will change list[name].prop
The problem with this is that, as you noticed yourself, the value is passed the way you're doing it instead of the reference.
Thanks to JavaScript get, you can return the value of prop of the surrounding object within a function which behaves like an attribute.
function Filters() {
this.prop = 'some';
this.list = { };
this.add = function(name) {
let self = this;
this.list[name] = {
get prop() {
return self.prop;
},
};
}
}
let attempt = new Filters();
attempt.add('first');
attempt.prop = 'other';
document.writeln(attempt.prop)
document.writeln(attempt.list['first'].prop)
Side note: I use the variable self here because using this.prop within get prop() would reference the wrong object and hence cause a recursion.
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;
}
});
I am trying you get a better understanding of JavaScript, especially the prototype functionality. I am having trouble with this case:
I am trying to define a function someObject with a type function so that it will behave like the following:
var myTestObject = someObject();
If I call:
myTestObject() ===> "The object is initailType"
and then when this is called
myTestObject.type() ===> "InitialType"
Then if I make this call
myTestObject.type("newtype")
myTestObject.type() ===> "newType"
A call to
myTestObject() ===> "The Object is newType".
I have tried both this How does JavaScript .prototype work?
and this How do you create a method for a custom object in JavaScript?
,but I am getting several different errors depending on how it is implemented, mostly this though (Uncaught TypeError: Object myTestObject has no method 'type'). I feel like I am making this harder then it should be.
edit: more code.
function box(){
var _current = "initialType"
Object.defineProperty(this, "current", {
get: function(){return _current;},
set: function(value){
if(arguments.length === 1){
_current = value;
} }
})
return "The Object is " + this.type(this.current)
}
box.prototype.type = function(newValue){
var type = null;
if(arguments.length == 0){
type = "initialType";
}else {
type = newValue
}
return type
}
I would use something like this:
function Box(){}
Box.prototype.type = "initialType";
Box.prototype.toString = function() {
return "The Object is " + this.type + ".";
};
And use it like this:
var b = new Box();
b.type; // "initialType"
b + ''; // "The Object is initialType."
b.type = 'otherType'; // "otherType"
b.type; // "otherType"
b + ''; // "The Object is otherType."
This does what you've asked, but I don't understand what you want to do with the prototype, so this code doesn't use that. For example, the sample code doesn't use new, so the return value of someObject won't use its prototype.
function someObject()
{
var currentType = "initailType";
var formatter = function() {
return "The object is " + currentType;
};
formatter.type = function(value) {
if (arguments.length == 0) {
return currentType;
} else {
currentType = value;
}
};
return formatter;
}
var myTestObject = someObject();
myTestObject(); // => "The object is initailType"
myTestObject.type(); // => "initialType"
myTestObject.type("newType");
myTestObject.type(); // => "newType"
myTestObject(); // => "The object is newType".
see demo
Edit: example using prototype and new.
function Box() { // class name starts with a capital letter
this._type = "initialType"; // set up default values in constructor function
} // no "return" in constructor function, using "new" handles that
Box.prototype.type = function(value) { // adding method to the prototype
if (arguments.length == 0) { // magic arguments local variable...
return this._type; // initially returns the value set in the constructor
} else {
this._type = value; // update the stored value
}
};
Box.prototype.format = function() // another method on the box, rather than a return from the constructor
{
return "The object is " + this.type(); // could use this._type instead
};
var box = new Box(); // instance variable with lowercase name
console.log(box.type()); // read the default value
console.log(box.format()); // print the message with the initial value of type
box.type("another type"); // set the type property, no return value
console.log(box.format()); // print the new message
I am trying to create an object that defines getters/setters automatically for a new instance of an object. I want the setter to put the values in a separate object property called newValues. Why in the following code snippet does setting the value of prop1 actually set the value of newValues.prop2 instead of newValues.prop1?
Am I doing something silly here? It's totally possible as I am on only a few hours of sleep... :)
var Record = function(data) {
this.fieldValues = {}
this._data = data;
var record = this;
for(var key in data) {
record.__defineGetter__(key, function() {
return record._data[key];
});
record.__defineSetter__(key, function(val) {
record.fieldValues[key] = val;
});
}
}
var myRecord = new Record({prop1: 'prop1test', prop2: 'prop2test'});
myRecord.prop1 = 'newvalue';
console.log(myRecord.fieldValues.prop1); // undefined
console.log(myRecord.fieldValues.prop2); // 'newvalue'
Because when you eventually use the function that you've created for the getter/setter, key has its final value. You need to close over the value of key for each iteration of the loop. JavaScript has functional scope, not block scope.
var Record = function(data) {
var key;
this.fieldValues = {}
this._data = data;
for(key in data) {
//closure maintains state of "key" variable
//without being overwritten each iteration
(function (record, key) {
record.__defineGetter__(key, function() {
return record._data[key];
});
record.__defineSetter__(key, function(val) {
record.fieldValues[key] = val;
});
}(this, key));
}
}
This is the usual thing where people stumble with JS: The closure in a loop problem.
This explains it quite nicely along with a solution: http://www.mennovanslooten.nl/blog/post/62