Implementing setter and getter in JavaScript object - javascript

I want to implement setter and getter on local
javascript variable. Here is an example function:
function someThing() {
var someLocalvariable = '';
}
// with this function I want to
// return value of someLocalvariable
// also if it is possible to implement
// setter in this way.
someThing.prototype.getLocalVar = function() {
}
I want variable to be 'realy' private. I don't wont
to use something like this:
someThing.prototype.someLocalvariable =
or
function someThing() {
this.someLocalvariable = '';
}
or attaching function inside someThing() like this:
function someThing() {
var someLocalvariable = '';
this.getLocalvariable = function() {
return someLocalvariable;
}
}
I would be very grateful for any guidance and assistance.

Your last example of what you don't want to do won't work (it has syntax errors), (it's been fixed) but I think you may have meant the usual way of doing this, which is to make the getter and setter closures within the constructor function (below).
Unfortunately, if you want truly private variables, this is just about your only option. There is no other way to get truly private, instance-specific variables. However, see "hack" below.
Here's the correct version of the usual way of doing this (which I think you said you don't want, but for completeness):
function SomeThing() {
var privateVar;
this.setPrivateVar = function(val) {
privateVar = val;
};
this.getPrivateVar = function() {
return privateVar;
};
}
// use:
var t = new Something();
t.setPrivateVar("foo");
console.log(t.getPrivateVar()); // "foo"
Like most, I first read of this pattern on Douglas Crockford's site.
This option does carry a downside: Every instance created via the SomeThing constructor function gets its own two functions. They cannot be shared between instances. So if there are going to be hundreds or thousands of SomeThing instances in your app, that's something to be considered from a memory perspective. If there are going to be a couple of hundred or fewer, it probably doesn't matter. (Those numbers are pulled out of a hat and you should not trust them, you'll have to review your code's memory use when/if there's some kind of issue; but you get the idea.)
The hack: If your instances will already have some kind of unique identifier on them as public data (or you're willing to add one, again it will be public), and if you're willing to add a fair bit of complication into the use of the instances, you can have a private cache that holds the data for all of your instances that only your code can access, and key into that cache via the unique identifier of the object. Like this (in this example, I'm allocating the id values, but you can use existing unique IDs if you have them):
var SomeThing = (function() {
var cache = {}, idAllocator = 0;
function SomeThing() {
this.id = ++idAllocator; // The unique identifier, can be a string if desired
cache[this.id] = {};
}
SomeThing.prototype.getPrivateVar = function() {
var data = cache[this.id];
return data && data.privateVar;
};
SomeThing.prototype.setPrivateVar = function(value) {
cache[this.id].privateVar = value;
};
SomeThing.prototype.destroy = function() {
delete cache[this.id];
};
return SomeThing;
})();
Here's how that works: All of the functions are closures over the cache local variable in the outer scoping function. We index into that using the unique ID of the object, which gives us an object on which we put our private data members. When the code using the instance is done using it, that code must call destroy (which is a major downside to this pattern) so we remove the private data object from cache by deleting the property for our id.
Caveats and costs:
You still have a public piece of data that is the key to your private data (id in the above)
Users of the instances created by SomeThing must call destroy on those instances when they're done with them. This is anathema to the way JavaScript's garbage handling works, but it's a requirement of the pattern above because otherwise you end up with cruft building up in the cache object.
(I wouldn't worry about this one) Eventually, if you're using the automatic id values above, you'll run out of them, if your app creates and destroys a lot of these instances. But JavaScript numbers go very high up indeed, and if that's an issue just find a different way to allocate IDs rather than the simplistic always-increasing system above.
I haven't had to use the pattern above in my work yet, but I expect there are use-cases for it involving thousands of SomeThing instances and thus the desire not to have per-instance functions.
Side note: In the above, I changed someThing to SomeThing. In JavaScript, the standard practice is for the names of normal functions to start with a lower-case letter, and for the names of constructor functions (ones you use with new) to start with a capital letter. Since SomeThing is meant to be used with new, I capped it. This is only convention, but it's an overwhelmingly popular one and, of course, it's used within the language definition itself (Date is a constructor, setHours is a function).

Use Object.defineProperty() in the function constructor in order to define your getter and setter more info here..
To make truly private (not visible to the outside) some values use a Closure,
more info can be found here.
In the following example we define a getter and setter for property temperature, where the inner "private" value is stored in a variable var temperature.
var temperature will never be visible/accessibly from the outside of Archiver() has it is a Closure.
Please note that this pattern works on ES5 as Object.defineProperty() it is not supported on ES3.
function Archiver() {
var temperature = null;
var archive = [];
Object.defineProperty(this, 'temperature', {
get: function () {
console.log('get!');
return temperature;
},
set: function (value) {
temperature = value;
archive.push({ val: temperature });
}
});
this.getArchive = function () {
return archive;
};
}
var arc = new Archiver();
arc.temperature; // 'get!'
arc.temperature = 11;
arc.temperature = 13;
arc.getArchive(); // [{ val: 11 }, { val: 13 }]

Something like this:
function Field(val){
var value = val;
this.getValue = function(){
return value;
};
this.setValue = function(val){
value = val;
};
}
var field = new Field("test");
field.value
// => undefined
field.setValue("test2")
field.getValue()
Check ref: http://ejohn.org/blog/javascript-getters-and-setters/

Douglas Crockford has written this on implementing private members in JavaScript

That's not possible. If you have a local variable in someThing(), the function you attach to the prototype can't read its value (it's private, remember?). Your last example is the normal solution to this problem, why isn't this good enough for you?

Try these two ways to achieve setter and getter
var address = {
street : "No street",
city : "No city",
state : "No state",
get getAddress()
{
return (this.street+","+this.city+","+this.state);
},
set setAddress(theAddress)
{
var part = theAddress.toString().split(", ");
this.street = part[0] || "";
this.city = part[1] || "";
this.state = part[2] || "";
}
};
address.setAddress = "27 Sus Road, Pune, MH";
console.log(address.getAddress);
//Other setter and getter
function Square(side)
{
this._side = side;
};
Square.prototype = {
set setSide(side){
this._side = side;
},
get getSide(){
return this._side;
},
get getArea(){
return (this._side * this._side);
}
};
var mySquare = new Square(10);
mySquare.setSide = 15;
console.log("Area of square is "+mySquare.getArea+" with side "+mySquare.getSide);

First method
var address = {
street : "No street",
city : "No city",
state : "No state",
get getAddress()
{
return (this.street+","+this.city+","+this.state);
},
set setAddress(theAddress)
{
var part = theAddress.toString().split(", ");
this.street = part[0] || "";
this.city = part[1] || "";
this.state = part[2] || "";
}
};
address.setAddress = "27 Sus Road, Pune, MH";
console.log(address.getAddress);
Second method
function Square(side)
{
this._side = side;
};
Square.prototype = {
set setSide(side){
this._side = side;
},
get getSide(){
return this._side;
},
get getArea(){
return (this._side * this._side);
}
};
var mySquare = new Square(10);
mySquare.setSide = 15;
console.log("Area of square is "+mySquare.getArea+" with side "+mySquare.getSide);

Related

Javascript - how do you add properties to an object constructor function

How do I add properties to a constructor function in JavaScript? For example. If I have the following function.
function Hotel(name)
{
this.name = name;
};
var hotel1 = new Hotel('Park');
can I add a "local" variable that can be used locally within the class as if it were private with the same notation using the keyword "this". Of course it would not be private since objects created will be able to use it correct?
Can I do something like this. Do I use the this keyword or do I use the var keyword
which one is it? I have example 2 on the function constructor on the bottom
1. var numRooms = 40;
2. this.numRooms = 40;
3. numRooms : 40,
function Hotel(name)
{
this.name = name;
this.numRooms = 40;
};
I know that if I want a function within the object constructor I need to use the this word. Will that work as well for normal variables as I have asked above.
function Hotel(name)
{
this.name = name;
this.numRooms = 40;
this.addNumRoomsPlusFive = function()
{
return this.numRooms + 5;
}
};
You can simple add a private variable to your constructor:
function Hotel(name) {
var private = 'private';
this.name = name;
};
But if you will use your Hotel function without a new operator, all properties and functions which was attached to this will become global.
function Hotel(name) {
var private = 'private';
this.name = name;
};
var hotel = Hotel('test');
console.log(name); // test
It is good idea to return an object in constructor function:
function Hotel(name) {
var
private_var = 'private',
private_func = function() {
// your code
};
retur {
name: 'name',
public_func: private_func
}
};
var hotel = Hotel('test');
console.log(name); // undefined
So if you will use Hotel constructor without new operator no global variable will be created. This is possible only if the return value is an object. Otherwise, if you try to return anything that is not an object, the constructor will proceed with its usual behaviour and return this.
can I add a "local" variable that can be used locally within the class as if it were private with the same notation using the keyword "this".
Yes we can:
// API implementation in the library
function Hotel(name) {
// only our library code knows about the actual value
const numRooms = 'privateNoRoomsVar';
this.name = name;
this[numRooms] = 40;
this.addNumRoomsPlusFive = function() {
return this[numRooms] + 5;
}
};
// from the library user's perspective
const hotel = new Hotel('Transylvania');
console.log('rooms+5 =', hotel.addNumRoomsPlusFive());
console.log('hotel.numRooms =', hotel.numRooms); // undefined
// also, users don't have access to 'numRooms' variable so they can't use hotel[numRooms].
If a user looks at the source code and finds out the value privateNoRoomsVar, then they can misuse the API.
For that we need to use symobls:
// API implementation in the library
function Hotel(name) {
// no one can duplicate a symbol so the variable is really private
const numRooms = Symbol();
this.name = name;
this[numRooms] = 40;
this.addNumRoomsPlusFive = function() {
return this[numRooms] + 5;
}
};
// from the library user's perspective
const hotel = new Hotel('Transylvania');
console.log('rooms+5 =', hotel.addNumRoomsPlusFive());
console.log('hotel.numRooms =', hotel.numRooms); // undefined
// there is no way users will get access to the symbol object so the variable remains private.
Private class features, #privateField, are supported by all the browsers so we don’t have to worry about this anymore.
// API implementation in the library
class Hotel {
// private field
#numRooms = 40;
constructor(name) {
this.name = name;
}
addNumRoomsPlusFive() {
return this.#numRooms + 5;
}
};
// from the library user's perspective
const hotel = new Hotel('Transylvania');
console.log('rooms+5 =', hotel.addNumRoomsPlusFive());
console.log('hotel.numRooms =', hotel.numRooms); // undefined
//console.log('hotel.numRooms =', hotel.#numRooms); // throws error
Javascript historically creates objects from prototypes of other objects. It was a result of EMCA2015, that you have a distinct syntax of a class that specifies an object. As an aside, if you mouse over the table in that link it gives dates of when the feature was implemented.
A javascript object created by the new operator is more or less a combination of an associative array ( what you make with let avar={}; ) that can access the function level scopes it is defined in. The keys of the array are its properties. According to its creator, Javascript was created to be an easy to use program language without a hierarchy of types. One of the ways it accomplished this is by more or less considering its mapping type to be equivalent to the prototypical Object which object oriented programming languages describe.
Adding properties in 2022
function AProtoype(arg1, arg2, arg3){
//this defines a property
this.pa=arg1;
/* unicorns in this section */
let x = 1;
/*
a getter which has the same syntax as a property
but returns x from the scope which it references and
not the object.
*/
get getx() => x;
}
let object = new AProtoype(2,3,4);
Is equivalent to the following code for the purposes of data access but not inheritance and typing. The new operator also sets variables on an object that are used for these purposes.
function NewObject(arg1, arg2, arg3){
let prototype = {};
/*dragons in this section, as you are not using the this keyword to accomplish things*/
prototype.pa = arg1;
Object.defineProperty(prototype, "getx", {get:()=>x});
return prototype;
}
//If you do this instead of using the new operator it is an anti-pattern.
//And like all anti-patterns: "But it works!"
let object = NewObject(2,3,4);
The relevant property defining methods where in some sense supported as early as 2010, 2011. I do not have a contemporary source to that time to confirm if you could pull off what I'm doing though, and you'd only want to if all else failed and it needed to run on Internet Explorer 9. In the event all else is failing, you may want to read the documentation for Object.create, which is also of interest because more or less provides an api to make new objects.
Now, for a fun time and horror, you can also define a function that returns this, and get an object back with an equivalent binding of that function. The horror comes when it is an object in global scope, and you rename a property of that object; as Javascript will resolve the name collision by happily writing on whatever it finds if it can. You can then use this to re-implement the prototype pattern that javascripts new operator is built off of conceptually, for the sake of science.
When you use a "constructor function" in Javascript, any properties defined on the instance using the this keyword become public. This is unavoidable, because Javascript objects have no concept of private properties - if it exists, it can be accessed directly as object.property.
For example, if you tried to do as in the following snippet, mimicking a typical getter/setter pattern with a private variable in Java or C# (note that even if this worked, this is not idiomatic Javascript):
function MyObject(privateVar) {
this.privateVar = privateVar;
}
MyObject.prototype.getVar = function() {
return this.privateVar;
};
MyObject.prototype.setVar = function(newVal) {
this.privateVar = newVal;
};
then while you can indeed use the getter and setter to do as you expect, you can also just access and set the private variable directly! Demonstration:
function MyObject(privateVar) {
this.privateVar = privateVar;
}
MyObject.prototype.getVar = function() {
return this.privateVar;
};
MyObject.prototype.setVar = function(newVal) {
this.privateVar = newVal;
};
var obj = new MyObject(1);
// using public getter/setter
console.log(obj.getVar()); // 1
obj.setVar(2);
console.log(obj.getVar()); // 2
// using private variable directly - not intended to work
console.log(obj.privateVar); // 2
obj.privateVar = 3;
console.log(obj.getVar()); // 3 (using public API to get it to show that the direct update to the private variable also affects the intended public methods)
There is though a way to mimic the effect of private variables. They're not actually object properties - because, as I have just demonstrated, such are intrinsically public - but the same can be mimicked by:
not using a "constructor function" at all, but a regular function that happens to return an object. This is all a constructor function really does, anyway - the difference in JS is only syntactic, that you do not need to use the new keyword when you call the function. (Although you still can, if you really prefer - any function that returns an object can be called with new and behave in the same way as without it, although performance will likely suffer a little as the function would then construct a brand new object and throw it away. See MDN for a justification of these statements, particularly step 4.)
inside this function, using a regular variable as the private variable. This variable will be completely inaccessible from outside by the simple rules of scope, but you can still have the returned object retain access to it by the "magic" of closures.
Here is the above getter/setter example translated to this procedure, as well as demonstrations of it working. (I hasten to add again though, that this wouldn't be considered idiomatic code in Javascript.)
function makeObjectWithPrivateVar(privateVar) {
function getPrivateVar() {
return privateVar;
}
function setPrivateVar(newVal) {
privateVar = newVal;
}
return { getPrivateVar, setPrivateVar };
}
var obj = makeObjectWithPrivateVar(1);
// getter
console.log(obj.getPrivateVar()); // 1
// setter
obj.setPrivateVar(2);
// getter again to observe the change
console.log(obj.getPrivateVar()); // 2
// but how could we access the private var directly??
// answer, we can't
console.log(obj.privateVar); // undefined
console.log(privateVar); // ReferenceError, privateVar is not in scope!
Note finally though that it's rare in modern Javascript to use the function-based constructors in this style, since the class keyword makes it easier to mimic traditional class-based languages like Java if you really want to. And in particular, more recent browsers support private properties directly (you just have to prefix the property name with a #), so the initial code snippet translated into a class and using this feature, will work fine:
class MyObject {
#privateVar
constructor(privateVar) {
this.#privateVar = privateVar;
}
getVar() {
return this.#privateVar;
}
setVar(newVal) {
this.#privateVar = newVal;
}
}
var obj = new MyObject(1);
// using public getter/setter
console.log(obj.getVar()); // 1
obj.setVar(2);
console.log(obj.getVar()); // 2
// using private variable directly - now doesn't work
console.log(obj.privateVar); // undefined, it doesn't exist
// console.log(obj.#privateVar); // error as it's explicitly private, uncomment to see error message
Usually it's performed using closures:
var Hotel = (function() {
var numrooms=40; // some kind of private static variable
return function(name) { // constructor
this.numrooms = numrooms;
this.name = name;
};
}());
var instance = new Hotel("myname");

Javascript Module pattern with private/public methods

I'm asked to make a Javascript Module that acts as counter of browser events and is not possible to modify the actual counted events (Private method).
var CountingLogger = (function() {
var secret ={};
var uid = 0;
function CountingLogger(events) {
secret[this.id = uid++] = {};
// Store private stuff in the secret container
// instead of on `this`.
secret[this.id].events = events || 0;
}
CountingLogger.prototype.log = function (eventName) {
alert(secret[this.id].events[eventName]);
if (typeof secret[this.id].events[eventName] === 'undefined') {
secret[this.id].events[eventName] = 0;
}
secret[this.id].events[eventName]++;
var count = secret[this.id].events[eventName];
$('#logContents').append('<li>' + eventName + ': ' + count + '</li>');
};
return CountingLogger;
}());
in the main.js I define:
var logger = new CountingLogger();
then call
logger.log('EventName');
And should appear as callback a counter "EventName" + Counter, so Eventname: 1, SecondEvent: 4...
But in the log always shows 'WhateverEvent' undefined.
Can anybody please have an idea how this can be solved?
Regards
You don't want secrets at the level you have it. As Bergi said, it's a memory leak.
(Note: When I say "truly private" below, remember that nothing is truly private if someone's using a debugger. "Truly private" below just makes it's impossible for anyone to write code that, using a reference to the object, gets or modifies the private data.)
ES7 will have truly private properties. Until then, you basically have three options:
Truly private data, held via closures over the call to the constructor
"Keep your hands off" properties via a property naming convention
Very-hard-to-use properties that, while not private, are very hard to write code against
Truly Private Data
If you want truly private information on a per-instance basis, the standard way to do that is using variables in the constructor, and define methods that need that private data within the constructor:
function Foo() {
var secret = Math.floor(Math.random() * 100);
this.iWillTellYouASecret = function() {
console.log("The secret is " + secret);
};
}
Foo.prototype.iDoNotKnowTheSecret = function() {
console.log("I don't know the secret");
};
Yes, that means a new iWillTellYouASecret function is created for every instance, but it (and the secret) are also reclaimed when that instance is removed from memory, and a decent JavaScript engine can reuse the function's code across those function objects.
"Keep your hands off" Properties
But most of the time, you don't need truly private information, just information saying "keep your hands off me." The convention for that in JavaScript is properties beginning with an _. Yes, that means that code with access to instances can use or change that property's value, but that's actually true in most languages that have "truly private" properties as well, such as Java, via reflection.
Very-Hard-to-Use Properties
If you want to make life harder on people trying to use your private data, you can use this trick from an old blog article of mine *(it was written back when ES6 was going to have true privacy via Name objects; since then, Name has turned into Symbol and it isn't used for privacy anymore):
First, you create a Name psuedo-class:
var Name = function() {
var used = {};
function Name() {
var length, str;
do {
length = 5 + Math.floor(Math.random() * 10);
str = "_";
while (length--) {
str += String.fromCharCode(32 + Math.floor(95 * Math.random()));
}
}
while (used[str]);
used[str] = true;
return new String(str); // Since this is called via `new`, we have to return an object to override the default
}
return Name;
}();
Then you use this pattern for your private instance properties:
// Nearly-private properties
var Foo = (function() {
// Create a random string as our private property key
var nifty = new Name();
// Our constructor
function Foo() {
// We can just assign here as normal
this[nifty] = 42;
}
// ***On ES5, make the property non-enumerable
// (that's the default for properties created with
// Object.defineProperty)
if (Object.defineProperty) { // Only needed for ES3-compatibility
Object.defineProperty(Foo.prototype, nifty, {
writable: true
});
}
// ***End change
// Methods shared by all Foo instances
Foo.prototype.method1 = function() {
// This method has access to `nifty`, because it
// closes over the private key
console.log("Truly private nifty info: " + this[nifty]);
};
Foo.prototype.method2 = function() {
// Also has access, for the same reason
console.log("Truly private nifty info: " + this[nifty]);
};
return Foo;
})();
var f = new Foo();
f.method1(); // Can use nifty!
f.method2(); // Can too! :-)
// Both `method1` and `method2` are *reused* by all `Foo` objects
Now, the name of your private property is different every time your code runs.
This still isn't private. It's just harder to find.
Private methods in javascript should only be used for encapsulation purposes.
It's impossible to prevent someone from manipulating any method in javascript.
A user can simply place a debug point on your private method and start to manipulate your private logic.

How to create shared, privileged, public methods?

Some methods of one of my classes right now are public, but can access private variables (they are privileged). This is because they are created in the class constructor, so their closure has access to the object closure.
What I would like to avoid, though, is the memory and performance overhead of creating new privileged methods every time. So I want to share them.
Is there any way to put privileged methods into a prototype?
Example was requested:
function Person(age) { // age is private
this.grow = function() { // grow is now public, but can access private "age"
age += 1;
}
}
dan = new Person(10);
dan.grow();
dan.age; // undefined
This works, I have a public method "grow" that can access the private variable "age", but grow has to be recreated for each object.
The more performant way is:
function Person(age) { // age is private
this.age = age; // but this.age is public
}
Person.prototype.grow = function() {
this.age += 1;
}
dan = new Person(10);
dan.grow();
dan.age; // 11
This shares the "grow" method, but now age is public.
You could do something like this (without ES6), though I don't consider it a good solution.
var Person = (function () {
var id = 0,
data = {},
key = Math.random();
function Person(age) {
var thisId = id;
data[id] = age;
id += 1;
this.getId = function(check) {
if (check !== key) {
return undefined;
}
return thisId;
};
}
Person.prototype.grow = function () {
var thisId = this.getId(key);
data[thisId] += 1;
console.log(data[thisId]);
return this;
};
Person.prototype.destroy = function () {
var thisId = this.getId(key);
data[thisId] = null;
delete data[thisId];
};
return Person;
}());
var dan = new Person(10);
dan.grow();
console.log(dan.age); // undefined
console.log(dan.getId()); // undefined
on jsFiddle
Added by #DanRedux:
function Person(age) {
this.private = {age:age}; }
Person.prototype.grow = function() {
this.private.age += 1; }
dan = new Person(10);
dan.grow();
dan.age; // undefined
dan.private.age; // 11
Yes, it is indeed possible. However it requires a little bit of trickery:
var createTree = require("functional-red-black-tree");
var Person = (function () {
var tree = createTree(), id = 0;
return function (age) {
tree.insert(id, {
age: age
});
this.id = id++;
this.grow = grow;
this.destroy = destroy;
};
function grow() {
tree.get(this.id).age++;
}
function destroy() {
tree.remove(this.id);
}
}());
We use functional red black trees to efficiently insert, remove and get the private properties of an object in O(log n) time. Hence for example say you create 2251799813685248 instances of Person at a time. It will still only require 51 operations to insert, remove and get objects from the tree.
You can use it as follows:
var dan = new Person(10);
dan.grow();
dan.age; // undefined
dan.destroy(); // frees shared memory
However I wouldn't recommend this approach because:
It unnecessarily complicates things.
If you forget to call destroy then you will waste a lot of memory.
Every "privileged" function has an additional overhead.
Changes made to the secret object are not reflected on the private variables.
Instead I would recommend that you just use public properties for everything. There's really no good reason to use private properties at all. What are you scared of?
Edit: If alll you want is to prevent your private properties from being printed out via console.log then you can make them non-enumerable:
function Person(age) {
Object.defineProperty(this, "age", {
enumerable: false,
writable: true,
value: age
});
}
Person.prototype.grow = function () {
this.age++;
};
Now the age property (although public) will not appear in for in loops or via console.log. In short you get the best of both worlds.
As I said in the comments, there's absolutely no need to use the shared privileged method hack. Simply make all your variables public and non-enumerable.
In addition prefix them with an underscore to indicate that they should not be tampered with. All good JavaScript programmers use this convention.
Well, as you have said, privileged methods are created by placing them in the constructor scope. By that definition, they cannot be shared amongst instances; otherwise they wouldn't be able to access the instance-specific scope.

Javascript object properties and functions

In JavaScript I see a few different ways, certain tasks can be performed within an object for example, the object Egg I have below.
Can anyone tell me the difference between each one, why I would use one and not the other etc
var Egg = function(){
//Properties
var shell = "cracked" // private property
this.shell = "cracked" // public property
shell: "cracked" // what is this??
//functions
function cook(){
//standard function
}
cook: function(){
//what kind of function is this?
}
//not sure what this is
details: {
//What is this? an array :S it holds 2 elements?
cost: 1.23,
make: 'Happy Egg';
}
}
Your code snippet isn't quite valid, but here are a few things it raises:
Property initializers, object initializers
You've asked what shell: cracked is. It's a property initializer. You find them in object initializers (aka "object literals"), which are written like this:
var obj = {
propName: "propValue"
};
That's equivalent to:
var obj = {};
obj.propName = "propValue";
Both of the above create an object with a property called propName which has a string value "propValue". Note that this doesn't come into it.
Functions
There are a couple of places where functions typically come into it vis-a-vis objects:
Constructor functions
There are constructor functions, which are functions you call via the new operator. Here's an example:
// Constructor function
function Foo(name) {
this.name = name;
}
// Usage
var f = new Foo("Fred");
Note the use of the keyword this in there. That's where you've seen that (most likely). When you call a constructor function via new, this refers to the new object created by the new operator.
this is a slippery concept in JavaScript (and completely different from this in C++, Java, or C#), I recommend these two (cough) posts on my blog:
You must remember this
Mythical methods
Builder/factory functions
You don't have to use constructor functions and new, another pattern uses "builder" or "factory" functions instead:
// A factory function
function fooFactory(name) {
var rv = {}; // A new, blank object
rv.name = name;
return rv;
}
// Usage
var f = fooFactory("Fred");
Private properties
You mentioned "private" properties in your question. JavaScript doesn't have private properties at all (yet, they're on their way). But you see people simulate them, by defining functions they use on the object as closures over an execution context (typically a call to a constructor function or a factory function) which contains variables no one else can see, like this:
// Constructor function
function EverUpwards() {
var counter = 0;
this.increment = function() {
return ++counter;
};
}
// Usage:
var e = new EverUpwards();
console.log(e.increment()); // "1"
console.log(e.increment()); // "2"
(That example uses a constructor function, but you can do the same thing with a factory function.)
Note that even though the function we assign to increment can access counter, nothing else can. So counter is effectively a private property. This is because the function is a closure. More: Closures are not complicated
Sure, Ben.
This sort of gets to the bottom of the dynamism of JavaScript.
First, we'll look at basics -- if you're coming from a place where you understand class-based languages, like, say, Java or C++/C#, the one that is going to make the most sense is the constructor pattern which was included very early on:
function Egg (type, radius, height, weight) {
// private properties (can also have private functions)
var cost = (type === "ostrich") ? 2.05 * weight : 0.35 * weight;
// public properties
this.type = type;
this.radius = radius;
this.height = height;
this.weight = weight;
this.cracked = false;
// this is a public function which has access to private variables of the instance
this.getCost = function () { return cost; };
}
// this is a method which ALL eggs inherit, which can manipulate "this" properly
// but it has ***NO*** access to private properties of the instance
Egg.prototype.Crack = function () { this.cracked = true; };
var myEgg = new Egg("chicken", 2, 3, 500);
myEgg.cost; // undefined
myEgg.Crack();
myEgg.cracked; // true
That's fine, but sometimes there are easier ways of getting around things.
Sometimes you really don't need a class.
What if you just wanted to use one egg, ever, because that's all your recipe called for?
var myEgg = {}; // equals a new object
myEgg.type = "ostrich";
myEgg.cost = "......";
myEgg.Crack = function () { this.cracked = true; };
That's great, but there's still a lot of repetition there.
var myEgg = {
type : "ostrich",
cost : "......",
Crack : function () { this.cracked = true; }
};
Both of the two "myEgg" objects are exactly the same.
The problem here is that EVERY property and EVERY method of myEgg is 100% public to anybody.
The solution to that is immediately-invoking functions:
// have a quick look at the bottom of the function, and see that it calls itself
// with parens "()" as soon as it's defined
var myEgg = (function () {
// we now have private properties again!
var cost, type, weight, cracked, Crack, //.......
// this will be returned to the outside var, "myEgg", as the PUBLIC interface
myReturnObject = {
type : type,
weight : weight,
Crack : Crack, // added benefit -- "cracked" is now private and tamper-proof
// this is how JS can handle virtual-wallets, for example
// just don't actually build a financial-institution around client-side code...
GetSaleValue : function () { return (cracked) ? 0 : cost; }
};
return myReturnObject;
}());
myEgg.GetSaleValue(); // returns the value of private "cost"
myEgg.Crack();
myEgg.cracked // undefined ("cracked" is locked away as private)
myEgg.GetSaleValue(); // returns 0, because "cracked" is true
Hope that's a decent start.
You are mixing syntaxes between object property declaration and simple javascript statements.
// declare an object named someObject with one property
var someObject = {
key: value
};
// declare an anonymous function with some statements in it
// and assign that to a variable named "someFunction"
var someFunction = function () {
// any javascript statements or expressions can go here
};
There's a key distinction in JavaScript between objects and functions. Objects hold a bunch of data (including functions), and functions can be used to make or modify objects, but they aren't inherently the same thing. OOP in JavaScript is based around using functions as classes. For example, take the following class:
Test = function(){
this.value = 5;
}
If you just call the function Test(), then nothing will happen. Even if you say var x = Test(), the value of x will be undefined. However, using the new keyword, magic happens! So if we say var x = new Test(), then now the variable x will contain a Test object. If you do console.log(x.value), it would print 5.
That's how we can use functions to make objects. There's also a key different in syntax--a function can contain any sort of JavaScript block you want, whether that's if statements or for loops or what have you. When declaring an object, though, you have to use the key: value syntax.
Hope that clears things up a little bit!

Is there anyway to have instances share the same function yet at the same time have private variables?

I have this piece of code:
var Human=function(name){
this._name=name;
};
Human.prototype.Shout=function(){
alert(this._name);
};
var tom=new Human("tom");
var john=new Human("john");
alert(tom.Shout===john.Shout);
Right now ._name is not "private". I want to make ._name "private", but at the same time i do not wish to create additional functions for each instance of Human (in other words tom.Shout Must be === to john.Shout) because creating additional functions for each instance is just well.. unnecessary (ok offtopic - we can debate this on another thread)
My conclusion is that what I'm trying to achieve (having ._name be "private" and at the same time having tom.Shout===john.Shout) is impossible.
But I just want to be 200% sure before jumping into any conclusions.
(I welcome any hacks as long as the requirements are met, i.e no creating of additional functions for each instance)
If we have to create additional functions to do scoping that's fine but that number should be a fixed number and that number should not increase with each additional instance of Human.
Update
Your looking for #name which is an instance variable. Pray it's in es.next, but we don't have it yet. Maybe in two years.
If you care about a clean API then here is your solution:
function Class(foo) {
Class.priv(this).foo = foo;
}
Class.priv = (function() {
var cache = [],
uid = 1;
return function(obj) {
if (!this.__id) {
this.__id = uid;
cache[uid++] = {};
}
return cache[this.__id];
};
}());
Class.prototype.bar = function() {
console.log(Class.priv(this).foo);
}
Store all the data in a cache as a function of the constructor. No data is cluttered on the object.
Original
However there is no such thing as "private".
All you can do is create a local variable inside a function.
The constructor function
var Human = function(name) {
// local variable.
var _name = name;
}
Has a local variable that by very definition of being local is not usable outside of the constructor function.
This means that you cannot access it in external code like the prototype.
What you can do however is make it read only using ES5
var Human = function(name) {
Object.defineProperty(this, "name", { value: name });
}
If you can truly achieve what your asking, you'd make a huge breakthrough in js. I've attempted to do just that for many hours.
A different pattern would be :
var Human = function(name) {
this.name = name;
return {
Shout: this.Shout.bind(this)
};
}
Human.prototype.Shout = function() {
console.log(this.name);
}
This has the overhead of calling .bind and creating a new object for every instance though.
how about this ?
var Human = function (name) {
var _name = name;
this.getName = function () {
return _name;
}
};
Human.prototype.Shout = function () {
alert(this.getName());
};
var tom = new Human("tom");
var john = new Human("john");
tom.Shout(); // tom
john.Shout(); // john
alert(tom.Shout === john.Shout); // true
EDIT:
the former creates another function for GET property,
it is not possible without creating additional functions.
Did read the question, didn't understand, because this._name is just not private, so the question is a bit weird. This is how in my test the prototype methods are added once and available to all instances. I repeat: this._name is not private here. If you add a local variable, and want to access it via a closure in a prototype method, calling the value of the local variable will result in the same value for all instances.
Anyway, with this constructor function the this._name getter and shout methods are added to the prototype chain once and thereby available for all instances of Human.
function Human(name) {
if (!(this instanceof Human)){
return new Human(name);
}
this._name = name;
if (!Human.prototype.Name){
Human.prototype.Name = function(val){
if (val){
this._name = val;
return this;
}
return this._name;
};
Human.prototype.shout = function(){
alert(this._name);
}
}
}

Categories