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.
If I create an Object A:
let A = {};
And want to mix in methods from another Object B:
let B = {
foo() {
alert("Boo!");
}
};
Normally I would call:
Object.assign(A, B);
Then I change my function foo:
Object.assign(B, {
foo() {
alert("Hooray!");
}
});
After that I call foo:
A.foo(); // Actual output: "Boo!"
But I want that output to be "Hooray!".
So far I found out, that Object.assign only copies methods in the target, but it doesn't link them.
About inheritance and composition I found useful blogposts here:Why prototypical inheritance matters and most dominantly here: Understanding Prototypes, Delegation & Composition
I want to mix a method in an Object, but not copy the methods, much more rather I want an assignment to the definition of the mixed in function.
How is this possible?
Prototype inheritance comes to your rescue:
var A = Object.create(B);
A.foo();
B.foo = …;
A.foo(); // something else
Of course, this is not strictly a "mixin" any more, and you can only inherit via the prototype link from one other object only (though you can build an inheritance chain).
If you are looking to mix multiple independent objects into your existing A object, then that is not possible. Sorry.
either, you call assign again. or you can do something like this: (there are no pointers in javascript, however: objects are always passed by reference (in contrast to normal values like numbers, strings,.. which are passed by value).
Hence:
var my = {
f: function() { return "haa" }
}
var o1 = {};
Object.assign(o1, {my: my}); // this is the crucial point, you are assigning a reference to my
o1.my.f() // "haa";
my.f = function() { return "hoooo" };
o1.my.f() // "hoooo";
After some research, I found something much simpler:
var my = {
f: function() { return "haa" }
}
var o1 = new Object(my); // create an object of the prototype my;
o1.f(); // haa;
my.f = function() { return "hoooo" };
o1.f() // hoooo
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.
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.
sometimes we loss the new keyword when define new object,
obj = new Clazz(); //correct
obj = Clazz(); //wrong, but no syntax error, hard to debug.
I want to write a function to help me create Class and make it new safe.
var Class = function(){
var constructor = arguments[0];
var superClasses = arguments[1..n];
function clazz(){
if(! this instanceof clazz){
return new clazz()//pass clazz arguments,not Class arguments
}
constructor();//pass clazz arguments
}
//clazz inherit from superClasses
return clazz;
}
var MyClazz = Class(function(name){
this.name = name
}, SuperClazz1, SuperClass2 )
MyClazz.extend({
show: function(){console.log(this.name)}
})
obj1 = new MyClazz("name1");
obj2 = MyClazz("name2");
// obj1 should same as obj2
Is it possible, any exists module?
sometimes we loss the new keyword...
All about coding discipline and testing... anyways, moving on to your question.
To find out whether your function was called as a constructor use instanceof:
function Foo() {
console.log(this instanceof Foo);
}
Foo(); // false
new Foo(); // true
When calling a function as a constructor this refers to the newly created object, otherwise this refers to the object the function was called on, in case it wasn't called on anything this will refer to the global object.
Update
Passing variable arguments to a constructor is not possible. new clas.call(....) will yield an error that call is not an constructor.
You can do two things:
Instead of returning the Class function itself from your class factory method, return a function that creates a new instance, sets up all the needed stuff and then returns that instance (this will make inheritance waaaay more complicated)
Just use the new keyword.
I've written my own Class thingy, and I've tried to support both new and () syntax for creating instances. The whole inheritance stuff etc. is complicated enough, making it even more magic just to save 4 more characters... not worth the effort. Use new and write tests.
Another Update
OK I couldn't resist to hack around more and I made it work:
function is(type, obj) {
return Object.prototype.toString.call(obj).slice(8, -1) === type;
}
function clas(args) {
if (is('Object', this)) {
ctor.apply(this, is('Arguments', args) ? args : arguments);
} else {
return new clas(arguments);
}
}
This will do the magic, at least in my case.
Sorry for the late submission on this answer but I believe it directly answers your question. My solution is to check the type of the constructed object and act accordingly.
You can see my solution here:
http://mikepackdev.com/blog_posts/9-new-scope-safe-constructors-in-oo-javascript
I hope this helps!