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
Related
I know this will work:
function Foo() {};
Foo.prototype.talk = function () {
alert('hello~\n');
};
var a = new Foo;
a.talk(); // 'hello~\n'
But if I want to call
Foo.talk() // this will not work
Foo.prototype.talk() // this works correctly
I find some methods to make Foo.talk work,
Foo.__proto__ = Foo.prototype
Foo.talk = Foo.prototype.talk
Are there other ways to do this? I don’t know whether it is right to do so. Do you use class methods or static methods in your JavaScript code?
First off, remember that JavaScript is primarily a prototypal language, rather than a class-based language1. Foo isn't a class, it's a function, which is an object. You can instantiate an object from that function using the new keyword which will allow you to create something similar to a class in a standard OOP language.
I'd suggest ignoring __proto__ most of the time because it has poor cross browser support, and instead focus on learning about how prototype works.
If you have an instance of an object created from a function2 and you access one of its members (methods, attributes, properties, constants etc) in any way, the access will flow down the prototype hierarchy until it either (a) finds the member, or (b) doesn't find another prototype.
The hierarchy starts on the object that was called, and then searches its prototype object. If the prototype object has a prototype, it repeats, if no prototype exists, undefined is returned.
For example:
foo = {bar: 'baz'};
console.log(foo.bar); // logs "baz"
foo = {};
console.log(foo.bar); // logs undefined
function Foo(){}
Foo.prototype = {bar: 'baz'};
f = new Foo();
console.log(f.bar);
// logs "baz" because the object f doesn't have an attribute "bar"
// so it checks the prototype
f.bar = 'buzz';
console.log( f.bar ); // logs "buzz" because f has an attribute "bar" set
It looks to me like you've at least somewhat understood these "basic" parts already, but I need to make them explicit just to be sure.
In JavaScript, everything is an object3.
everything is an object.
function Foo(){} doesn't just define a new function, it defines a new function object that can be accessed using Foo.
This is why you can access Foo's prototype with Foo.prototype.
What you can also do is set more functions on Foo:
Foo.talk = function () {
alert('hello world!');
};
This new function can be accessed using:
Foo.talk();
I hope by now you're noticing a similarity between functions on a function object and a static method.
Think of f = new Foo(); as creating a class instance, Foo.prototype.bar = function(){...} as defining a shared method for the class, and Foo.baz = function(){...} as defining a public static method for the class.
ECMAScript 2015 introduced a variety of syntactic sugar for these sorts of declarations to make them simpler to implement while also being easier to read. The previous example can therefore be written as:
class Foo {
bar() {...}
static baz() {...}
}
which allows bar to be called as:
const f = new Foo()
f.bar()
and baz to be called as:
Foo.baz()
1: class was a "Future Reserved Word" in the ECMAScript 5 specification, but ES6 introduces the ability to define classes using the class keyword.
2: essentially a class instance created by a constructor, but there are many nuanced differences that I don't want to mislead you
3: primitive values—which include undefined, null, booleans, numbers, and strings—aren't technically objects because they're low-level language implementations. Booleans, numbers, and strings still interact with the prototype chain as though they were objects, so for the purposes of this answer, it's easier to consider them "objects" even though they're not quite.
You can achieve it as below:
function Foo() {};
Foo.talk = function() { alert('I am talking.'); };
You can now invoke "talk" function as below:
Foo.talk();
You can do this because in JavaScript, functions are objects as well.
Call a static method from an instance:
function Clazz() {};
Clazz.staticMethod = function() {
alert('STATIC!!!');
};
Clazz.prototype.func = function() {
this.constructor.staticMethod();
}
var obj = new Clazz();
obj.func(); // <- Alert's "STATIC!!!"
Simple Javascript Class Project: https://github.com/reduardo7/sjsClass
Here is a good example to demonstrate how Javascript works with static/instance variables and methods.
function Animal(name) {
Animal.count = Animal.count+1||1;// static variables, use function name "Animal"
this.name = name; //instance variable, using "this"
}
Animal.showCount = function () {//static method
alert(Animal.count)
}
Animal.prototype.showName=function(){//instance method
alert(this.name);
}
var mouse = new Animal("Mickey");
var elephant = new Animal("Haddoop");
Animal.showCount(); // static method, count=2
mouse.showName();//instance method, alert "Mickey"
mouse.showCount();//Error!! mouse.showCount is not a function, which is different from Java
In additions, now it is possible to do with class and static
'use strict'
class Foo {
static talk() {
console.log('talk')
};
speak() {
console.log('speak')
};
};
will give
var a = new Foo();
Foo.talk(); // 'talk'
a.talk(); // err 'is not a function'
a.speak(); // 'speak'
Foo.speak(); // err 'is not a function'
I use namespaces:
var Foo = {
element: document.getElementById("id-here"),
Talk: function(message) {
alert("talking..." + message);
},
ChangeElement: function() {
this.element.style.color = "red";
}
};
And to use it:
Foo.Talk("Testing");
Or
Foo.ChangeElement();
ES6 supports now class & static keywords like a charm :
class Foo {
constructor() {}
talk() {
console.log("i am not static");
}
static saying() {
console.log(this.speech);
}
static get speech() {
return "i am static method";
}
}
If you have to write static methods in ES5 I found a great tutorial for that:
//Constructor
var Person = function (name, age){
//private properties
var priv = {};
//Public properties
this.name = name;
this.age = age;
//Public methods
this.sayHi = function(){
alert('hello');
}
}
// A static method; this method only
// exists on the class and doesn't exist
// on child objects
Person.sayName = function() {
alert("I am a Person object ;)");
};
see #https://abdulapopoola.com/2013/03/30/static-and-instance-methods-in-javascript/
Just additional notes. Using class ES6, When we create static methods..the Javacsript engine set the descriptor attribute a lil bit different from the old-school "static" method
function Car() {
}
Car.brand = function() {
console.log('Honda');
}
console.log(
Object.getOwnPropertyDescriptors(Car)
);
it sets internal attribute (descriptor property) for brand() to
..
brand: [object Object] {
configurable: true,
enumerable: true,
value: ..
writable: true
}
..
compared to
class Car2 {
static brand() {
console.log('Honda');
}
}
console.log(
Object.getOwnPropertyDescriptors(Car2)
);
that sets internal attribute for brand() to
..
brand: [object Object] {
configurable: true,
enumerable: false,
value:..
writable: true
}
..
see that enumerable is set to false for static method in ES6.
it means you cant use the for-in loop to check the object
for (let prop in Car) {
console.log(prop); // brand
}
for (let prop in Car2) {
console.log(prop); // nothing here
}
static method in ES6 is treated like other's class private property (name, length, constructor) except that static method is still writable thus the descriptor writable is set to true { writable: true }. it also means that we can override it
Car2.brand = function() {
console.log('Toyota');
};
console.log(
Car2.brand() // is now changed to toyota
);
When you try to call Foo.talk, the JS tries to search a function talk through __proto__ and, of course, it can't be found.
Foo.__proto__ is Function.prototype.
Static method calls are made directly on the class and are not callable on instances of the class. Static methods are often used to
create utility function
Pretty clear description
Taken Directly from mozilla.org
Foo needs to be bound to your class
Then when you create a new instance you can call myNewInstance.foo()
If you import your class you can call a static method
When i faced such a situation, i have done something like this:
Logger = {
info: function (message, tag) {
var fullMessage = '';
fullMessage = this._getFormatedMessage(message, tag);
if (loggerEnabled) {
console.log(fullMessage);
}
},
warning: function (message, tag) {
var fullMessage = '';
fullMessage = this._getFormatedMessage(message, tag);
if (loggerEnabled) {
console.warn(fullMessage);`enter code here`
}
},
_getFormatedMessage: function () {}
};
so now i can call the info method as
Logger.info("my Msg", "Tag");
In your case, if you want to Foo.talk():
function Foo() {};
// But use Foo.talk would be inefficient
Foo.talk = function () {
alert('hello~\n');
};
Foo.talk(); // 'hello~\n'
But it's an inefficient way to implement, using prototype is better.
Another way, My way is defined as static class:
var Foo = new function() {
this.talk = function () {
alert('hello~\n');
};
};
Foo.talk(); // 'hello~\n'
Above static class doesn't need to use prototype because it will be only constructed once as static usage.
https://github.com/yidas/js-design-patterns/tree/master/class
Javascript has no actual classes rather it uses a system of prototypal inheritance in which objects 'inherit' from other objects via their prototype chain. This is best explained via code itself:
function Foo() {};
// creates a new function object
Foo.prototype.talk = function () {
console.log('hello~\n');
};
// put a new function (object) on the prototype (object) of the Foo function object
var a = new Foo;
// When foo is created using the new keyword it automatically has a reference
// to the prototype property of the Foo function
// We can show this with the following code
console.log(Object.getPrototypeOf(a) === Foo.prototype);
a.talk(); // 'hello~\n'
// When the talk method is invoked it will first look on the object a for the talk method,
// when this is not present it will look on the prototype of a (i.e. Foo.prototype)
// When you want to call
// Foo.talk();
// this will not work because you haven't put the talk() property on the Foo
// function object. Rather it is located on the prototype property of Foo.
// We could make it work like this:
Foo.sayhi = function () {
console.log('hello there');
};
Foo.sayhi();
// This works now. However it will not be present on the prototype chain
// of objects we create out of Foo
There are tree ways methods and properties are implemented on function or class objects, and on they instances.
On the class (or function) itself : Foo.method() or Foo.prop. Those are static methods or properties
On its prototype : Foo.prototype.method() or Foo.prototype.prop. When created, the instances will inherit those object via the prototype witch is {method:function(){...}, prop:...}. So the foo object will receive, as prototype, a copy of the Foo.prototype object.
On the instance itself : the method or property is added to the object itself. foo={method:function(){...}, prop:...}
The this keyword will represent and act differently according to the context. In a static method, it will represent the class itself (witch is after all an instance of Function : class Foo {} is quite equivalent to let Foo = new Function({})
With ECMAScript 2015, that seems well implemented today, it is clearer to see the difference between class (static) methods and properties, instance methods and properties and own methods ans properties. You can thus create three method or properties having the same name, but being different because they apply to different objects, the this keyword, in methods, will apply to, respectively, the class object itself and the instance object, by the prototype or by its own.
class Foo {
constructor(){super();}
static prop = "I am static" // see 1.
static method(str) {alert("static method"+str+" :"+this.prop)} // see 1.
prop="I am of an instance"; // see 2.
method(str) {alert("instance method"+str+" : "+this.prop)} // see 2.
}
var foo= new Foo();
foo.prop = "I am of own"; // see 3.
foo.func = function(str){alert("own method" + str + this.prop)} // see 3.
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 1.9.3 / ECMAScript 5 introduces Object.create, which Douglas Crockford amongst others has been advocating for a long time. How do I replace new in the code below with Object.create?
var UserA = function(nameParam) {
this.id = MY_GLOBAL.nextId();
this.name = nameParam;
}
UserA.prototype.sayHello = function() {
console.log('Hello '+ this.name);
}
var bob = new UserA('bob');
bob.sayHello();
(Assume MY_GLOBAL.nextId exists).
The best I can come up with is:
var userB = {
init: function(nameParam) {
this.id = MY_GLOBAL.nextId();
this.name = nameParam;
},
sayHello: function() {
console.log('Hello '+ this.name);
}
};
var bob = Object.create(userB);
bob.init('Bob');
bob.sayHello();
There doesn't seem to be any advantage, so I think I'm not getting it. I'm probably being too neo-classical. How should I use Object.create to create user 'bob'?
With only one level of inheritance, your example may not let you see the real benefits of Object.create.
This methods allows you to easily implement differential inheritance, where objects can directly inherit from other objects.
On your userB example, I don't think that your init method should be public or even exist, if you call again this method on an existing object instance, the id and name properties will change.
Object.create lets you initialize object properties using its second argument, e.g.:
var userB = {
sayHello: function() {
console.log('Hello '+ this.name);
}
};
var bob = Object.create(userB, {
'id' : {
value: MY_GLOBAL.nextId(),
enumerable:true // writable:false, configurable(deletable):false by default
},
'name': {
value: 'Bob',
enumerable: true
}
});
As you can see, the properties can be initialized on the second argument of Object.create, with an object literal using a syntax similar to the used by the Object.defineProperties and Object.defineProperty methods.
It lets you set the property attributes (enumerable, writable, or configurable), which can be really useful.
There is really no advantage in using Object.create(...) over new object.
Those advocating this method generally state rather ambiguous advantages: "scalability", or "more natural to JavaScript" etc.
However, I have yet to see a concrete example that shows that Object.create has any advantages over using new. On the contrary there are known problems with it. Sam Elsamman describes what happens when there are nested objects and Object.create(...) is used:
var Animal = {
traits: {},
}
var lion = Object.create(Animal);
lion.traits.legs = 4;
var bird = Object.create(Animal);
bird.traits.legs = 2;
alert(lion.traits.legs) // shows 2!!!
This occurs because Object.create(...) advocates a practice where data is used to create new objects; here the Animal datum becomes part of the prototype of lion and bird, and causes problems as it is shared. When using new the prototypal inheritance is explicit:
function Animal() {
this.traits = {};
}
function Lion() { }
Lion.prototype = new Animal();
function Bird() { }
Bird.prototype = new Animal();
var lion = new Lion();
lion.traits.legs = 4;
var bird = new Bird();
bird.traits.legs = 2;
alert(lion.traits.legs) // now shows 4
Regarding, the optional property attributes that are passed into Object.create(...), these can be added using Object.defineProperties(...).
Object.create is not yet standard on several browsers, for example IE8, Opera v11.5, Konq 4.3 do not have it. You can use Douglas Crockford's version of Object.create for those browsers but this doesn't include the second 'initialisation object' parameter used in CMS's answer.
For cross browser code one way to get object initialisation in the meantime is to customise Crockford's Object.create. Here is one method:-
Object.build = function(o) {
var initArgs = Array.prototype.slice.call(arguments,1)
function F() {
if((typeof o.init === 'function') && initArgs.length) {
o.init.apply(this,initArgs)
}
}
F.prototype = o
return new F()
}
This maintains Crockford prototypal inheritance, and also checks for any init method in the object, then runs it with your parameter(s), like say new man('John','Smith'). Your code then becomes:-
MY_GLOBAL = {i: 1, nextId: function(){return this.i++}} // For example
var userB = {
init: function(nameParam) {
this.id = MY_GLOBAL.nextId();
this.name = nameParam;
},
sayHello: function() {
console.log('Hello '+ this.name);
}
};
var bob = Object.build(userB, 'Bob'); // Different from your code
bob.sayHello();
So bob inherits the sayHello method and now has own properties id=1 and name='Bob'. These properties are both writable and enumerable of course. This is also a much simpler way to initialise than for ECMA Object.create especially if you aren't concerned about the writable, enumerable and configurable attributes.
For initialisation without an init method the following Crockford mod could be used:-
Object.gen = function(o) {
var makeArgs = arguments
function F() {
var prop, i=1, arg, val
for(prop in o) {
if(!o.hasOwnProperty(prop)) continue
val = o[prop]
arg = makeArgs[i++]
if(typeof arg === 'undefined') break
this[prop] = arg
}
}
F.prototype = o
return new F()
}
This fills the userB own properties, in the order they are defined, using the Object.gen parameters from left to right after the userB parameter. It uses the for(prop in o) loop so, by ECMA standards, the order of property enumeration cannot be guaranteed the same as the order of property definition. However, several code examples tested on (4) major browsers show they are the same, provided the hasOwnProperty filter is used, and sometimes even if not.
MY_GLOBAL = {i: 1, nextId: function(){return this.i++}}; // For example
var userB = {
name: null,
id: null,
sayHello: function() {
console.log('Hello '+ this.name);
}
}
var bob = Object.gen(userB, 'Bob', MY_GLOBAL.nextId());
Somewhat simpler I would say than Object.build since userB does not need an init method. Also userB is not specifically a constructor but looks like a normal singleton object. So with this method you can construct and initialise from normal plain objects.
TL;DR:
new Computer() will invoke the constructor function Computer(){} for one time, while Object.create(Computer.prototype) won't.
All the advantages are based on this point.
Sidenote about performance: Constructor invoking like new Computer() is heavily optimized by the engine, so it may be even faster than Object.create.
You could make the init method return this, and then chain the calls together, like this:
var userB = {
init: function(nameParam) {
this.id = MY_GLOBAL.nextId();
this.name = nameParam;
return this;
},
sayHello: function() {
console.log('Hello '+ this.name);
}
};
var bob = Object.create(userB).init('Bob');
Another possible usage of Object.create is to clone immutable objects in a cheap and effective way.
var anObj = {
a: "test",
b: "jest"
};
var bObj = Object.create(anObj);
bObj.b = "gone"; // replace an existing (by masking prototype)
bObj.c = "brand"; // add a new to demonstrate it is actually a new obj
// now bObj is {a: test, b: gone, c: brand}
Notes: The above snippet creates a clone of an source object (aka not a reference, as in cObj = aObj). It benefits over the copy-properties method (see 1), in that it does not copy object member properties. Rather it creates another -destination- object with it's prototype set on the source object. Moreover when properties are modified on the dest object, they are created "on the fly", masking the prototype's (src's) properties.This constitutes a fast an effective way of cloning immutable objects.
The caveat here is that this applies to source objects that should not be modified after creation (immutable). If the source object is modified after creation, all the clone's unmasked properties will be modified, too.
Fiddle here(http://jsfiddle.net/y5b5q/1/) (needs Object.create capable browser).
I think the main point in question - is to understand difference between new and Object.create approaches. Accordingly to this answer and to this video new keyword does next things:
Creates new object.
Links new object to constructor function (prototype).
Makes this variable point to the new object.
Executes constructor function using the new object and implicit perform return this;
Assigns constructor function name to new object's property constructor.
Object.create performs only 1st and 2nd steps!!!
In code example provided in question it isn't big deal, but in next example it is:
var onlineUsers = [];
function SiteMember(name) {
this.name = name;
onlineUsers.push(name);
}
SiteMember.prototype.getName = function() {
return this.name;
}
function Guest(name) {
SiteMember.call(this, name);
}
Guest.prototype = new SiteMember();
var g = new Guest('James');
console.log(onlineUsers);
As side effect result will be:
[ undefined, 'James' ]
because of Guest.prototype = new SiteMember();
But we don't need to execute parent constructor method, we need only make method getName to be available in Guest.
Hence we have to use Object.create.
If replace Guest.prototype = new SiteMember();
to Guest.prototype = Object.create(SiteMember.prototype); result be:
[ 'James' ]
Sometimes you cannot create an object with NEW but are still able to invoke the CREATE method.
For example: if you want to define a Custom Element it must derive from HTMLElement.
proto = new HTMLElement //fail :(
proto = Object.create( HTMLElement.prototype ) //OK :)
document.registerElement( "custom-element", { prototype: proto } )
The advantage is that Object.create is typically slower than new on most browsers
In this jsperf example, in a Chromium, browser new is 30 times as fast as Object.create(obj) although both are pretty fast. This is all pretty strange because new does more things (like invoking a constructor) where Object.create should be just creating a new Object with the passed in object as a prototype (secret link in Crockford-speak)
Perhaps the browsers have not caught up in making Object.create more efficient (perhaps they are basing it on new under the covers ... even in native code)
Summary:
Object.create() is a Javascript function which takes 2 arguments and returns a new object.
The first argument is an object which will be the prototype of the newly created object
The second argument is an object which will be the properties of the newly created object
Example:
const proto = {
talk : () => console.log('hi')
}
const props = {
age: {
writable: true,
configurable: true,
value: 26
}
}
let Person = Object.create(proto, props)
console.log(Person.age);
Person.talk();
Practical applications:
The main advantage of creating an object in this manner is that the prototype can be explicitly defined. When using an object literal, or the new keyword you have no control over this (however, you can overwrite them of course).
If we want to have a prototype The new keyword invokes a constructor function. With Object.create() there is no need for invoking or even declaring a constructor function.
It can Basically be a helpful tool when you want create objects in a very dynamic manner. We can make an object factory function which creates objects with different prototypes depending on the arguments received.
You have to make a custom Object.create() function. One that addresses Crockfords concerns and also calls your init function.
This will work:
var userBPrototype = {
init: function(nameParam) {
this.name = nameParam;
},
sayHello: function() {
console.log('Hello '+ this.name);
}
};
function UserB(name) {
function F() {};
F.prototype = userBPrototype;
var f = new F;
f.init(name);
return f;
}
var bob = UserB('bob');
bob.sayHello();
Here UserB is like Object.create, but adjusted for our needs.
If you want, you can also call:
var bob = new UserB('bob');
While Douglas Crockford used to be a zealous advocate of Object.create() and he is basically the reason why this construct actually is in javascript, he no longer has this opinion.
He stopped using Object.create, because he stopped using this keyword altogether as it causes too much trouble. For example, if you are not careful it can easily point to the global object, which can have really bad consequences. And he claims that without using this Object.create does not make sense anymore.
You can check this video from 2014 where he talks at Nordic.js:
https://www.youtube.com/watch?v=PSGEjv3Tqo0
new and Object.create serve different purposes. new is intended to create a new instance of an object type. Object.create is intended to simply create a new object and set its prototype. Why is this useful? To implement inheritance without accessing the __proto__ property. An object instance's prototype referred to as [[Prototype]] is an internal property of the virtual machine and is not intended to be directly accessed. The only reason it is actually possible to directly access [[Prototype]] as the __proto__ property is because it has always been a de-facto standard of every major virtual machine's implementation of ECMAScript, and at this point removing it would break a lot of existing code.
In response to the answer above by 7ochem, objects should absolutely never have their prototype set to the result of a new statement, not only because there's no point calling the same prototype constructor multiple times but also because two instances of the same class can end up with different behavior if one's prototype is modified after being created. Both examples are simply bad code as a result of misunderstanding and breaking the intended behavior of the prototype inheritance chain.
Instead of accessing __proto__, an instance's prototype should be written to when an it is created with Object.create or afterward with Object.setPrototypeOf, and read with Object.getPrototypeOf or Object.isPrototypeOf.
Also, as the Mozilla documentation of Object.setPrototypeOf points out, it is a bad idea to modify the prototype of an object after it is created for performance reasons, in addition to the fact that modifying an object's prototype after it is created can cause undefined behavior if a given piece of code that accesses it can be executed before OR after the prototype is modified, unless that code is very careful to check the current prototype or not access any property that differs between the two.
Given
const X = function (v) { this.v = v };
X.prototype.whatAmI = 'X';
X.prototype.getWhatIAm = () => this.whatAmI;
X.prototype.getV = () => this.v;
the following VM pseudo-code is equivalent to the statement const x0 = new X(1);:
const x0 = {};
x0.[[Prototype]] = X.prototype;
X.prototype.constructor.call(x0, 1);
Note although the constructor can return any value, the new statement always ignores its return value and returns a reference to the newly created object.
And the following pseudo-code is equivalent to the statement const x1 = Object.create(X.prototype);:
const x0 = {};
x0.[[Prototype]] = X.prototype;
As you can see, the only difference between the two is that Object.create does not execute the constructor, which can actually return any value but simply returns the new object reference this if not otherwise specified.
Now, if we wanted to create a subclass Y with the following definition:
const Y = function(u) { this.u = u; }
Y.prototype.whatAmI = 'Y';
Y.prototype.getU = () => this.u;
Then we can make it inherit from X like this by writing to __proto__:
Y.prototype.__proto__ = X.prototype;
While the same thing could be accomplished without ever writing to __proto__ with:
Y.prototype = Object.create(X.prototype);
Y.prototype.constructor = Y;
In the latter case, it is necessary to set the constructor property of the prototype so that the correct constructor is called by the new Y statement, otherwise new Y will call the function X. If the programmer does want new Y to call X, it would be more properly done in Y's constructor with X.call(this, u)
new Operator
This is used to create object from a constructor function
The new keywords also executes the constructor function
function Car() {
console.log(this) // this points to myCar
this.name = "Honda";
}
var myCar = new Car()
console.log(myCar) // Car {name: "Honda", constructor: Object}
console.log(myCar.name) // Honda
console.log(myCar instanceof Car) // true
console.log(myCar.constructor) // function Car() {}
console.log(myCar.constructor === Car) // true
console.log(typeof myCar) // object
Object.create
You can also use Object.create to create a new object
But, it does not execute the constructor function
Object.create is used to create an object from another object
const Car = {
name: "Honda"
}
var myCar = Object.create(Car)
console.log(myCar) // Object {}
console.log(myCar.name) // Honda
console.log(myCar instanceof Car) // ERROR
console.log(myCar.constructor) // Anonymous function object
console.log(myCar.constructor === Car) // false
console.log(typeof myCar) // object
I prefer a closure approach.
I still use new.
I don't use Object.create.
I don't use this.
I still use new as I like the declarative nature of it.
Consider this for simple inheritance.
window.Quad = (function() {
function Quad() {
const wheels = 4;
const drivingWheels = 2;
let motorSize = 0;
function setMotorSize(_) {
motorSize = _;
}
function getMotorSize() {
return motorSize;
}
function getWheelCount() {
return wheels;
}
function getDrivingWheelCount() {
return drivingWheels;
}
return Object.freeze({
getWheelCount,
getDrivingWheelCount,
getMotorSize,
setMotorSize
});
}
return Object.freeze(Quad);
})();
window.Car4wd = (function() {
function Car4wd() {
const quad = new Quad();
const spareWheels = 1;
const extraDrivingWheels = 2;
function getSpareWheelCount() {
return spareWheels;
}
function getDrivingWheelCount() {
return quad.getDrivingWheelCount() + extraDrivingWheels;
}
return Object.freeze(Object.assign({}, quad, {
getSpareWheelCount,
getDrivingWheelCount
}));
}
return Object.freeze(Car4wd);
})();
let myQuad = new Quad();
let myCar = new Car4wd();
console.log(myQuad.getWheelCount()); // 4
console.log(myQuad.getDrivingWheelCount()); // 2
console.log(myCar.getWheelCount()); // 4
console.log(myCar.getDrivingWheelCount()); // 4 - The overridden method is called
console.log(myCar.getSpareWheelCount()); // 1
Feedback encouraged.
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).
I know this will work:
function Foo() {};
Foo.prototype.talk = function () {
alert('hello~\n');
};
var a = new Foo;
a.talk(); // 'hello~\n'
But if I want to call
Foo.talk() // this will not work
Foo.prototype.talk() // this works correctly
I find some methods to make Foo.talk work,
Foo.__proto__ = Foo.prototype
Foo.talk = Foo.prototype.talk
Are there other ways to do this? I don’t know whether it is right to do so. Do you use class methods or static methods in your JavaScript code?
First off, remember that JavaScript is primarily a prototypal language, rather than a class-based language1. Foo isn't a class, it's a function, which is an object. You can instantiate an object from that function using the new keyword which will allow you to create something similar to a class in a standard OOP language.
I'd suggest ignoring __proto__ most of the time because it has poor cross browser support, and instead focus on learning about how prototype works.
If you have an instance of an object created from a function2 and you access one of its members (methods, attributes, properties, constants etc) in any way, the access will flow down the prototype hierarchy until it either (a) finds the member, or (b) doesn't find another prototype.
The hierarchy starts on the object that was called, and then searches its prototype object. If the prototype object has a prototype, it repeats, if no prototype exists, undefined is returned.
For example:
foo = {bar: 'baz'};
console.log(foo.bar); // logs "baz"
foo = {};
console.log(foo.bar); // logs undefined
function Foo(){}
Foo.prototype = {bar: 'baz'};
f = new Foo();
console.log(f.bar);
// logs "baz" because the object f doesn't have an attribute "bar"
// so it checks the prototype
f.bar = 'buzz';
console.log( f.bar ); // logs "buzz" because f has an attribute "bar" set
It looks to me like you've at least somewhat understood these "basic" parts already, but I need to make them explicit just to be sure.
In JavaScript, everything is an object3.
everything is an object.
function Foo(){} doesn't just define a new function, it defines a new function object that can be accessed using Foo.
This is why you can access Foo's prototype with Foo.prototype.
What you can also do is set more functions on Foo:
Foo.talk = function () {
alert('hello world!');
};
This new function can be accessed using:
Foo.talk();
I hope by now you're noticing a similarity between functions on a function object and a static method.
Think of f = new Foo(); as creating a class instance, Foo.prototype.bar = function(){...} as defining a shared method for the class, and Foo.baz = function(){...} as defining a public static method for the class.
ECMAScript 2015 introduced a variety of syntactic sugar for these sorts of declarations to make them simpler to implement while also being easier to read. The previous example can therefore be written as:
class Foo {
bar() {...}
static baz() {...}
}
which allows bar to be called as:
const f = new Foo()
f.bar()
and baz to be called as:
Foo.baz()
1: class was a "Future Reserved Word" in the ECMAScript 5 specification, but ES6 introduces the ability to define classes using the class keyword.
2: essentially a class instance created by a constructor, but there are many nuanced differences that I don't want to mislead you
3: primitive values—which include undefined, null, booleans, numbers, and strings—aren't technically objects because they're low-level language implementations. Booleans, numbers, and strings still interact with the prototype chain as though they were objects, so for the purposes of this answer, it's easier to consider them "objects" even though they're not quite.
You can achieve it as below:
function Foo() {};
Foo.talk = function() { alert('I am talking.'); };
You can now invoke "talk" function as below:
Foo.talk();
You can do this because in JavaScript, functions are objects as well.
Call a static method from an instance:
function Clazz() {};
Clazz.staticMethod = function() {
alert('STATIC!!!');
};
Clazz.prototype.func = function() {
this.constructor.staticMethod();
}
var obj = new Clazz();
obj.func(); // <- Alert's "STATIC!!!"
Simple Javascript Class Project: https://github.com/reduardo7/sjsClass
Here is a good example to demonstrate how Javascript works with static/instance variables and methods.
function Animal(name) {
Animal.count = Animal.count+1||1;// static variables, use function name "Animal"
this.name = name; //instance variable, using "this"
}
Animal.showCount = function () {//static method
alert(Animal.count)
}
Animal.prototype.showName=function(){//instance method
alert(this.name);
}
var mouse = new Animal("Mickey");
var elephant = new Animal("Haddoop");
Animal.showCount(); // static method, count=2
mouse.showName();//instance method, alert "Mickey"
mouse.showCount();//Error!! mouse.showCount is not a function, which is different from Java
In additions, now it is possible to do with class and static
'use strict'
class Foo {
static talk() {
console.log('talk')
};
speak() {
console.log('speak')
};
};
will give
var a = new Foo();
Foo.talk(); // 'talk'
a.talk(); // err 'is not a function'
a.speak(); // 'speak'
Foo.speak(); // err 'is not a function'
I use namespaces:
var Foo = {
element: document.getElementById("id-here"),
Talk: function(message) {
alert("talking..." + message);
},
ChangeElement: function() {
this.element.style.color = "red";
}
};
And to use it:
Foo.Talk("Testing");
Or
Foo.ChangeElement();
ES6 supports now class & static keywords like a charm :
class Foo {
constructor() {}
talk() {
console.log("i am not static");
}
static saying() {
console.log(this.speech);
}
static get speech() {
return "i am static method";
}
}
If you have to write static methods in ES5 I found a great tutorial for that:
//Constructor
var Person = function (name, age){
//private properties
var priv = {};
//Public properties
this.name = name;
this.age = age;
//Public methods
this.sayHi = function(){
alert('hello');
}
}
// A static method; this method only
// exists on the class and doesn't exist
// on child objects
Person.sayName = function() {
alert("I am a Person object ;)");
};
see #https://abdulapopoola.com/2013/03/30/static-and-instance-methods-in-javascript/
Just additional notes. Using class ES6, When we create static methods..the Javacsript engine set the descriptor attribute a lil bit different from the old-school "static" method
function Car() {
}
Car.brand = function() {
console.log('Honda');
}
console.log(
Object.getOwnPropertyDescriptors(Car)
);
it sets internal attribute (descriptor property) for brand() to
..
brand: [object Object] {
configurable: true,
enumerable: true,
value: ..
writable: true
}
..
compared to
class Car2 {
static brand() {
console.log('Honda');
}
}
console.log(
Object.getOwnPropertyDescriptors(Car2)
);
that sets internal attribute for brand() to
..
brand: [object Object] {
configurable: true,
enumerable: false,
value:..
writable: true
}
..
see that enumerable is set to false for static method in ES6.
it means you cant use the for-in loop to check the object
for (let prop in Car) {
console.log(prop); // brand
}
for (let prop in Car2) {
console.log(prop); // nothing here
}
static method in ES6 is treated like other's class private property (name, length, constructor) except that static method is still writable thus the descriptor writable is set to true { writable: true }. it also means that we can override it
Car2.brand = function() {
console.log('Toyota');
};
console.log(
Car2.brand() // is now changed to toyota
);
When you try to call Foo.talk, the JS tries to search a function talk through __proto__ and, of course, it can't be found.
Foo.__proto__ is Function.prototype.
Static method calls are made directly on the class and are not callable on instances of the class. Static methods are often used to
create utility function
Pretty clear description
Taken Directly from mozilla.org
Foo needs to be bound to your class
Then when you create a new instance you can call myNewInstance.foo()
If you import your class you can call a static method
When i faced such a situation, i have done something like this:
Logger = {
info: function (message, tag) {
var fullMessage = '';
fullMessage = this._getFormatedMessage(message, tag);
if (loggerEnabled) {
console.log(fullMessage);
}
},
warning: function (message, tag) {
var fullMessage = '';
fullMessage = this._getFormatedMessage(message, tag);
if (loggerEnabled) {
console.warn(fullMessage);`enter code here`
}
},
_getFormatedMessage: function () {}
};
so now i can call the info method as
Logger.info("my Msg", "Tag");
In your case, if you want to Foo.talk():
function Foo() {};
// But use Foo.talk would be inefficient
Foo.talk = function () {
alert('hello~\n');
};
Foo.talk(); // 'hello~\n'
But it's an inefficient way to implement, using prototype is better.
Another way, My way is defined as static class:
var Foo = new function() {
this.talk = function () {
alert('hello~\n');
};
};
Foo.talk(); // 'hello~\n'
Above static class doesn't need to use prototype because it will be only constructed once as static usage.
https://github.com/yidas/js-design-patterns/tree/master/class
Javascript has no actual classes rather it uses a system of prototypal inheritance in which objects 'inherit' from other objects via their prototype chain. This is best explained via code itself:
function Foo() {};
// creates a new function object
Foo.prototype.talk = function () {
console.log('hello~\n');
};
// put a new function (object) on the prototype (object) of the Foo function object
var a = new Foo;
// When foo is created using the new keyword it automatically has a reference
// to the prototype property of the Foo function
// We can show this with the following code
console.log(Object.getPrototypeOf(a) === Foo.prototype);
a.talk(); // 'hello~\n'
// When the talk method is invoked it will first look on the object a for the talk method,
// when this is not present it will look on the prototype of a (i.e. Foo.prototype)
// When you want to call
// Foo.talk();
// this will not work because you haven't put the talk() property on the Foo
// function object. Rather it is located on the prototype property of Foo.
// We could make it work like this:
Foo.sayhi = function () {
console.log('hello there');
};
Foo.sayhi();
// This works now. However it will not be present on the prototype chain
// of objects we create out of Foo
There are tree ways methods and properties are implemented on function or class objects, and on they instances.
On the class (or function) itself : Foo.method() or Foo.prop. Those are static methods or properties
On its prototype : Foo.prototype.method() or Foo.prototype.prop. When created, the instances will inherit those object via the prototype witch is {method:function(){...}, prop:...}. So the foo object will receive, as prototype, a copy of the Foo.prototype object.
On the instance itself : the method or property is added to the object itself. foo={method:function(){...}, prop:...}
The this keyword will represent and act differently according to the context. In a static method, it will represent the class itself (witch is after all an instance of Function : class Foo {} is quite equivalent to let Foo = new Function({})
With ECMAScript 2015, that seems well implemented today, it is clearer to see the difference between class (static) methods and properties, instance methods and properties and own methods ans properties. You can thus create three method or properties having the same name, but being different because they apply to different objects, the this keyword, in methods, will apply to, respectively, the class object itself and the instance object, by the prototype or by its own.
class Foo {
constructor(){super();}
static prop = "I am static" // see 1.
static method(str) {alert("static method"+str+" :"+this.prop)} // see 1.
prop="I am of an instance"; // see 2.
method(str) {alert("instance method"+str+" : "+this.prop)} // see 2.
}
var foo= new Foo();
foo.prop = "I am of own"; // see 3.
foo.func = function(str){alert("own method" + str + this.prop)} // see 3.