Is there a tidy way to create 'internal' properties in JavaScript? - javascript

In JavaScript, I may begin writing a 'library' or collection of functionality using a top level object like this:
window.Lib = (function()
{
return {
// Define Lib here.
//
};
})();
I may also add some functions within Lib which serve to create objects related to it:
window.Lib = (function()
{
return {
ObjectA: function()
{
var _a = 5;
return {
getA: function(){ return _a; }
};
},
ObjectB: function()
{
var _b = 2;
var _c = 1;
return {
getB: function(){ return _b; }
};
}
};
})();
Which would be used like so:
var thing = Lib.ObjectA();
var thing2 = Lib.ObjectA();
var thing3 = Lib.ObjectB();
And I can use the methods within each of those created above to get the values of _a defined within ObjectA() or _b defined within ObjectB():
alert(thing.getA()); // 5
alert(thing3.getB()); // 2
What I want to achieve is this:
Say I want to access the property _c (defined within ObjectB()) but only within the scope of Lib. How could I go about that? By this I mean, I want to make the property readable within any function that I define within the object returned by Lib(), but I don't want to expose those values outside of that.
Code example:
window.Lib = (function()
{
return {
ObjectA: function(){ ... },
ObjectB: function(){ ... },
assess: function(obj)
{
// Somehow get _c here.
alert( obj.getInternalC() );
}
};
})();
Which would work like so:
var thing = Lib.ObjectB();
alert( thing.getInternalC() ) // error | null | no method named .getInternalC()
Lib.assess(thing); // 1
Hope this makes sense.

So you want per-instance protected properties? That is, properties on the instances created by ObjectA, ObjectB, etc., but which are only accessible to the code within your library, and not to code outside it?
You cannot currently do that properly in JavaScript, but you'll be able to in the next version using private name objects. (See "Almost doing it" below for something similar you can do now in ES5, though.)
It's easy to create data that's shared by all code within Lib, but not per-instance properties, like so:
window.Lib = (function()
{
var sharedData;
// ...
})();
All of the functions defined within there (your ObjectA, etc.) will have access to that one sharedData variable, which is completely inaccessible from outside. But it's not per-instance, each object created by ObjectA, ObjectB, etc. doesn't get its own copy.
Almost doing it
If your code will be running in an environment with ES5 (so, any modern browser, where "modern" does not include IE8 or earlier), you can have obscured but not actually private properties, via Object.defineProperty. This is similar to how private name objects will work in ES.next, but not genuinely private:
Live Example | Source
window.Lib = (function() {
// Get a random name for our "c" property
var c = "__c" + Math.round(Math.random() * 1000000);
// Return our library functions
return {
ObjectA: function() {
// Create an object with a couple of public proprties:
var obj = {
pub1: "I'm a public property",
pub2: "So am I"
};
// Add our obscured "c" property to it, make sure it's
// non-enumerable (doesn't show up in for-in loops)
Object.defineProperty(obj, c, {
enumerable: false, // false is actually the default value, just emphasizing
writable: true,
value: "I'm an obscured property"
});
// Return it
return obj;
},
ObjectB: function(){ /* ... */ },
assess: function(obj) {
// Here, we access the property using the `c` variable, which
// contains the property name. In JavaScript, you can access
// properties either using dotted notation and a literal
// (`foo.propName`), or using bracketed notation and a string
// (`foo["propName"]`). Here we're using bracketed notation,
// and our `c` string, which has the actual property name.
display( obj[c] );
},
alter: function(obj, value) {
// Similarly, we can change the value with code that has
// access to the `c` variable
obj[c] = value;
}
};
})();
And use it like this:
// Create our object
var o = Lib.ObjectA();
// Play with it
display("pub1: " + o.pub1); // displays "pub1: I'm a public property"
display("c: " + o.c); // displays "c: undefined" since `o` has no property called `c`
Lib.assess(o); // displays "I'm an obscured property"
// Note that our obscured property doesn't show up in for-in loops or Object.keys:
var propName, propNames = [];
for (propName in o) {
propNames.push(propName);
}
display("propNames: " + propNames.join(","));
display("Object.keys: " + Object.keys(o).join(","));
// Our Lib code can modify the property
Lib.alter(o, "Updated obscured property");
Lib.assess(o);
The object returned by Lib.ObjectA has a property whose name will change every time Lib is loaded, and which is not enumerable (doesn't show up in for-in loops). The only way to get at it is to know it's name (which, again, changes every time Lib is created — e.g., every page load). The code within Lib knows what the property name is, because it's in the c variable which is shared by all of the Lib code. Since you can access properties using bracketed notation and a string, we can use instance[c] to access the property.
You see how these are pretty well obscured. Code outside of Lib don't see the obscured property when enumerating the property in the object, and they don't know the semi-random name we assigned it, so can't find the property. Of course, you could find it via inspection using a debugger, but debuggers can do lots of things.
And in fact, this is how private properties will work in ES.next, except that c won't be a string, it'll be a private name object.

Well, you would "just" need to declare those variables within the Context of Lib
window.Lib = (function()
{
var _c = 42;
return {
};
});
Notice that I removed the automatic invocation of that pseudo constructor function. That means, you would need to create multiple calls to Lib() for multiple instances, each would have its own unique set of values.
var inst1 = Lib(),
inst2 = Lib();
If you only want to have shared access from all child-context's (functions), you can just use the same pattern you already do (only with moving the var declarations to the parent context like shown above).

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");

How can I create an object of fixed structure?

I have the following code inside my revealing module, but I am uncertain with how to declare/define imageListItem, which is strictly a DTO and doesn't really require any information hiding. Am I correctly defining this object?
var imageListItem = function() {
var _title;
Object.defineProperty(this, "title", {
get: function () { return _title; },
set: function (value) { _title = value; }
}
);
};
var imageList = (function () {
var buffer = new CBuffer();
return {
populate: function (listItems) {
buffer.push(listItems);
},
rotate: function() {
buffer.rotateLeft();
}
}
})();
With imageListItem, I want to declare an object structure for later use. That declaration should not logically be dependent on how that object will later be used. That is, I don't want to find myself dynamically assigning new properties to, or deleting properties from, imageListItem by accident. Any assignment to properties should strictly be only to properties that have already been declared on the object.
Object.freeze() almost accomplihses this, by preventing properties being added or removed, but it also prevents properties being changed.
E.g. I want this:
var obj = {
prop: function() {},
foo: 'bar'
};
// New properties may be added, existing properties may be changed or removed
obj.foo = 'baz';
obj.lumpy = 'woof';
var o = Object.freeze(obj);
// Now any changes will fail
function fail(){
'use strict';
obj.delete(foo); // throws a TypeError
obj.quaxxor = 'the friendly duck'; // throws a TypeError
}
I dont' want this:
// Now any changes will fail
function fail(){
'use strict';
obj.foo = 'sparky'; // throws a TypeError
}
You see? I want freeze to prevent quaxxor being added to obj, but I don't want it to prevent me changing the value of foo.
What you are looking for may be either Object.preventExtensions() or Object.seal().
Similarly to Object.freeze(), both methods prevent new properties from being added to the object, nevertheless allow changing values of existing properties.
The difference between seal and preventExtensions is that seal strictly disallows deletion and conversion of properties from/to data accessors, while preventExtensions doesn't actually prevent existing properties from being deleted: this behavior depends on the JS engine you're using (some engines may let you delete the property, other ones may not).
So basically, quoting from the MDN Documentation:
The Object.preventExtensions() method prevents new properties from ever being added to an object (i.e. prevents future extensions to the object). [...] Note that the properties of a non-extensible object, in general, may still be deleted.
The Object.seal() method seals an object, preventing new properties from being added to it and marking all existing properties as non-configurable. Values of present properties can still be changed as long as they are writable. [...] Attempting to delete or add properties to a sealed object, or to convert a data property to accessor or vice versa, will fail.
Here's an example to demonstrate the behavior of both methods:
var myFirstObj = { foo: 1 },
mySecondObj = { bar: "baz" };
Object.preventExtensions(myFirstObj);
Object.seal(mySecondObj);
myFirstObj.foo = false; // Works fine
mySecondObj.baz = "hello"; // Works fine
delete myFirstObj.foo; // May work fine depending on your JS engine
(function() {
'use strict';
myFirstObj.qux = 'something'; // Throws a TypeError
mySecondObj.qux = 'something'; // Throws a TypeError
delete mySecondObj.foo; // Throws a TypeError
})();
Now, talking about your ImageListItem Object, you can achieve what you want simply adding a line of code:
var ImageListItem = function() {
var _title;
Object.defineProperty(this, "title", {
get: function () { return _title; },
set: function (value) { _title = value; }
});
// Choose the one which fits your needs
Object.preventExtensions(this);
// or
Object.seal(this);
};

Difference between creating javascript objects

When creating an object to use JS in an OO manner, is there any difference within a JS engine between (with the exception of being able to define a constructor:
var Uploader = Uploader || {};
and
var Uploader = function() {
}
and
function Uploader() {
}
Especially when later, you wish to do something along the lines of
Uploader.DOM = {
Create: function(file) {
}
};
Is it all down to personal preference? Or is there a real difference?
Objects:
var MyObj = {
myArr: [1,2,3],
find: function(/*some arguments*/) {
//some logic that finds something in this.myArr
}
}
In MyObj.find function this keyword will point to MyObj (which somewhat resembles how this works in languages those have classes). You can use this functionality to do mix-ins:
var MyObj2 = {
myArr: [4,2,6]
}
MyObj2.find = MyObj.find;
In MyObj2.find function this keyword will point to MyObj2.
Also objects support getters and setters (works on IE9+ and all good browsers):
var MyObj = {
myArr: [1,2,3],
find: function(/*some arguments*/) {
//some logic that finds something in this.myArr
},
get maxValue() {
return Math.max.apply(null, this.myArr);// maxValue is calculated on the fly
},
a_: null,
get a () {
return this.a_;
},
set a (val) {
//fire a change event, do input validation
this.a_ = val;
}
}
Now max value in the array can be accessed like this: MyObj.maxValue. I also added a property a_. It can't be named the same as its getter and setter so appended an underscore. Appending or prepending underscores is a naming convention for private variables which should not be accessed directly.
var qwe = MyObj.a // get a_
MyObj.a = 'something'; //set a_
Functions:
var u = new Uploader(); // will throw an exception
var Uploader = function() { }
Uploader is defined in runtime here. It does not exist yet when I try to instantiate it.
var u = new Uploader(); //will work
function Uploader() {}
Uploader is defined in compilation time here so it will work.
Functions can be used with revealing pattern to conceal some members. Functions don't support getters and setters but you can put objects inside functions.
function myFunc() {
function privateFunc() {};
function publicFunc() {};
var obj = {
//members, getters, setters
};
return {
publicFunc: publicFunc,
obj: obj
}
}
You can call muFunc.publicFunc() outside of myFunc because it is returned. But you can not use privateFunc outside because it is not returned.
Revealing pattern functions are not meant to be instantiated usually. This is because when you instantiate it everything inside will be copied to a new instance. So it will use up more memory than if you would add functions using prototype.
myFunc.prototype.someFunc = function() {};
Like this all instances of myFunc will share the same instance of someFunc.
Conclusion: with functions you can simulate a private access modifier but in objects the this keyword acts somewhat similar of what you'd expect in a language that have classes. But you always can use call, apply and bind to change the context (i.e. what 'this' keyword will be) of the function.

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!

Can Read-Only Properties be Implemented in Pure JavaScript?

Looking at the mozilla documentation, looking at the regular expression example (headed "Creating an array using the result of a match"), we have statements like:
input: A read-only property that reflects the original string against which the regular expression was matched.
index: A read-only property that is the zero-based index of the match in the string.
etc... is it possible to create your own object in JavaScript which will have read-only properties, or is this a privilege reserved to built-in types implemented by particular browsers?
With any javascript interpreter that implements ECMAScript 5 you can use Object.defineProperty to define readonly properties. In loose mode the interpreter will ignore a write on the property, in strict mode it will throw an exception.
Example from ejohn.org:
var obj = {};
Object.defineProperty( obj, "<yourPropertyNameHere>", {
value: "<yourPropertyValueHere>",
writable: false,
enumerable: true,
configurable: true
});
Edit: Since this answer was written, a new, better way using Object.defineProperty has been standardized in EcmaScript 5, with support in newer browsers. See Aidamina's answer. If you need to support "older" browsers, you could use one of the methods in this answer as a fallback.
In Firefox, Opera 9.5+, and Safari 3+, Chrome and IE (tested with v11) you can define getter and setter properties. If you only define a getter, it effectively creates a read-only property. You can define them in an object literal or by calling a method on an object.
var myObject = {
get readOnlyProperty() { return 42; }
};
alert(myObject.readOnlyProperty); // 42
myObject.readOnlyProperty = 5; // Assignment is allowed, but doesn't do anything
alert(myObject.readOnlyProperty); // 42
If you already have an object, you can call __defineGetter__ and __defineSetter__:
var myObject = {};
myObject.__defineGetter__("readOnlyProperty", function() { return 42; });
Of course, this isn't really useful on the web because it doesn't work in Internet Explorer.
You can read more about it from John Resig's blog or the Mozilla Developer Center.
It is possible to have read-only properties in JavaScript which are available via getter methods. This is usually called the 'Module' pattern.
The YUI blog has a good writeup of it: http://yuiblog.com/blog/2007/06/12/module-pattern/
Snippet from the post:
YAHOO.myProject.myModule = function () {
//"private" variables:
var myPrivateVar = "I can be accessed only from within YAHOO.myProject.myModule.";
//"private" method:
var myPrivateMethod = function () {
YAHOO.log("I can be accessed only from within YAHOO.myProject.myModule");
}
return {
myPublicProperty: "I'm accessible as YAHOO.myProject.myModule.myPublicProperty."
myPublicMethod: function () {
YAHOO.log("I'm accessible as YAHOO.myProject.myModule.myPublicMethod.");
//Within myProject, I can access "private" vars and methods:
YAHOO.log(myPrivateVar);
YAHOO.log(myPrivateMethod());
//The native scope of myPublicMethod is myProject; we can
//access public members using "this":
YAHOO.log(this.myPublicProperty);
}
};
}(); // the parens here cause the anonymous function to execute and return
As readonly property or variable here it is.
As aidamina said, and here is a short code for testing, by the way, very usefull now that JQuery pretends deprecate the selector property.
<script>
Object.defineProperties(window, {
"selector": { value: 'window', writable: false }
});
alert (window.selector); // outputs window
selector ='ddd'; // testing because it belong to the global object
alert (window.selector); // outputs window
alert (selector); // outputs window
window.selector='abc';
alert (window.selector); // outputs window
alert (selector); // outputs window
</script>
So there you have a readonly property or variable tested.
Yes we can have read only property for an object in JavaScript. It can be achieved with private variable and object.defineProperty() method,
See the following example which illustrates object having read only property,
function Employee(name,age){
var _name = name;
var _age = age;
Object.defineProperty(this,'name',{
get:function(){
return _name;
}
})
}
var emp = new Employee('safeer',25);
console.log(emp.name); //return 'safeer'
emp.name='abc';
console.log(emp.name); //again return 'safeer', since name is read-only property
Here's a link to Douglas Crockford's page on "Private Members in Javascript"....it would seem to me these would be read only if only getter methods are supplied, and no setters:
http://javascript.crockford.com/private.html
You will see that I have defined a setter and getter for color so it can be modified. The brand on the other hand becomes read-only once the object is defined. I believe this is the functionality you were looking for.
function Car(brand, color) {
brand = brand || 'Porche'; // Private variable - Not accessible directly and cannot be frozen
color = color || 'Red'; // Private variable - Not accessible directly and cannot be frozen
this.color = function() { return color; }; // Getter for color
this.setColor = function(x) { color = x; }; // Setter for color
this.brand = function() { return brand; }; // Getter for brand
Object.freeze(this); // Makes your object's public methods and properties read-only
}
function w(str) {
/*************************/
/*choose a logging method*/
/*************************/
console.log(str);
// document.write(str + "<br>");
}
var myCar = new Car;
var myCar2 = new Car('BMW','White');
var myCar3 = new Car('Mercedes', 'Black');
w(myCar.brand()); // returns Porche
w(myCar.color()); // returns Red
w(myCar2.brand()); // returns BMW
w(myCar2.color()); // returns White
w(myCar3.brand()); // returns Mercedes
w(myCar3.color()); // returns Black
// This works even when the Object is frozen
myCar.setColor('Green');
w(myCar.color()); // returns Green
// This will have no effect
myCar.color = 'Purple';
w(myCar.color()); // returns Green
w(myCar.color); // returns the method
// This following will not work as the object is frozen
myCar.color = function (x) {
alert(x);
};
myCar.setColor('Black');
w(
myCar.color(
'This will not work. Object is frozen! The method has not been updated'
)
); // returns Black since the method is unchanged
The above has been tested on Chromium Version 41.0.2272.76 Ubuntu 14.04 and yielded the following output:
Porche
Red
BMW
White
Mercedes
Black
Green
Green
function () { return color; }
Black
bob.js framework provides a way to declare read-only properties. Under the hood, it declares a private field and exposes the getter/setter functions for it. bob.js provides multiple ways of doing this same thing, depending on the convenience and specific goals. Here's one approach that uses object-oriented instance of the Property (other approaches allow defining setters/getters on the object itself):
var Person = function(name, age) {
this.name = new bob.prop.Property(name, true);
var setName = this.name.get_setter();
this.age = new bob.prop.Property(age, true);
var setAge = this.age.get_setter();
this.parent = new bob.prop.Property(null, false, true);
};
var p = new Person('Bob', 20);
p.parent.set_value(new Person('Martin', 50));
console.log('name: ' + p.name.get_value());
console.log('age: ' + p.age.get_value());
console.log('parent: ' + (p.parent.get_value ? p.parent.get_value().name.get_value() : 'N/A'));
// Output:
// name: Bob
// age: 20
// parent: N/A
At the end, p.name.set_value is not defined because that's a read-only property.
If you want a read-only property at runtime without having to enable "strict mode", one way is to define a "throwing setter". Example:
Object.defineProperty(Fake.prototype, 'props', {
set: function() {
// We use a throwing setter instead of frozen or non-writable props
// because that won't throw in a non-strict mode function.
throw Error();
},
});
Referenced from React

Categories