I'm trying to make private functions in Javascript. Here is my code:
function Person() {
this.id = 5;
};
Person.prototype = {
getId: function() {
return this.id;
},
walk: function() {
alert("i am private");
},
eat: function() {
alert("i am public");
}
};
I want to make walk function private one and eat function is public .
There is no constructions in JavaScript to define real private methods for class, but you can do so:
var Person = (function () {
var Person = function () {
this.id = 5;
};
var walk = function () {
alert("i am private");
};
Person.prototype = {
constructor: Person,
getId: function (){
return this.id;
},
eat: function () {
alert("i am public");
}
};
return Person;
}());
Related
I'm trying to use the revealing module pattern with inheritance. I seem to have it working fine, but it uses "__proto__", which I understand it's considered deprecated. Is there a better was to create the inheritance with out using "__proto__"?
var Person = (function() {
var _name;
var api = {
init: init,
getName: getName
}
return api;
function init(name) {
_name = name;
}
function getName() {
return _name;
}
}())
var Teacher = (function() {
var _subject = "Math";
var api = {
getSubject: getSubject,
say: say
}
api.__proto__ = Person;
return api;
function getSubject() {
return _subject;
}
function say() {
console.log("I am " + this.getName() + " and I teach " + _subject)
}
}());
Teacher.init("Bob");
Teacher.say() // I am Bob and I teach math
https://plnkr.co/edit/XbGx38oCyvRn79xnn2FR?p=preview
The direct equivalent – setting the prototype, still a bad idea – is Object.setPrototypeOf:
Object.setPrototypeOf(api, Person);
The normal way of creating an object based on a prototype with Object.create and then adding properties to it works fine here, though:
var api = Object.create(Person);
api.getSubject = getSubject;
api.say = say;
but ideally you would just use constructors:
class Person {
constructor(name) {
this._name = name;
}
getName() {
return this._name;
}
}
class Teacher extends Person {
constructor(name) {
super(name);
this._subject = 'Math';
}
getSubject() {
return this._subject;
}
say() {
console.log(`I am ${this.getName()} and I teach ${this.getSubject()}`);
}
}
var teacher = new Teacher('Bob');
teacher.say() // I am Bob and I teach math
without ES6:
function Person(name) {
this._name = name;
}
Person.prototype.getName = function () {
return this._name;
};
function Teacher(name) {
Person.call(this, name);
this._subject = 'Math';
}
Teacher.prototype = Object.create(Person.prototype);
Teacher.prototype.getSubject = function () {
return this._subject;
};
Teacher.prototype.say = function () {
console.log('I am ' + this.getName() + ' and I teach ' + this.getSubject());
};
var teacher = new Teacher('Bob');
teacher.say(); // I am Bob and I teach math
I've got two object prototypes like this:
function Tag(name, description) {
this.name = name;
this.description = description || null;
}
function Category(name, description) {
this.name = name;
this.description = description || null;
}
Both of them are exactly the same, which seems awkward. Is it possible to merge them both into an object named 'Entity', and refer to them both by different names (the original 'Tag' and 'Category')?
This may be further complicated by the fact I need to refer to the current prototype name inside the prototype.
Tag.prototype.toJSON = function() {
return {
__type: 'Tag',
name: this.name,
description: this.description
};
};
How can I apply the same 'toJSON' extension to the 'Entity' object, but make sure it returns 'Tag' or 'Category' in the '__type' field, dependent on which object is being used?
I would do something like this:
Dummy = function () {};
Entity = function (name) {
this.name = name;
};
Entity.prototype.toString = function () {
return "My name is " + this.name + ".";
};
A = function () {
Entity.call(this, 'A');
};
Dummy.prototype = Entity.prototype;
Dummy.prototype.constructor = A;
A.prototype = new Dummy();
B = function () {
Entity.call(this, 'B');
};
Dummy.prototype = Entity.prototype;
Dummy.prototype.constructor = B;
B.prototype = new Dummy();
document.body.innerHTML = ""
+ (new A()) + "<br />"
+ (new B());
Here is a small function to make things cleaner (hopefully):
function Nothing () {};
function extend (Sup, proto) {
function Class () {
if (this.init) {
this.init.apply(this, arguments);
}
}
Nothing.prototype = Sup.prototype;
Nothing.prototype.constructor = Sup;
Class.prototype = new Nothing();
delete Nothing.prototype;
for (var k in proto) {
Class.prototype[k] = proto[k];
}
return Class;
}
Here is how to use it:
Entity = extend(Nothing, {
init: function (name) {
this.name = name;
},
toString: function () {
return "My name is " + this.name + ".";
}
});
A = extend(Entity, {
init: function () {
var sup = Entity.prototype;
sup.init.call(this, 'A');
}
});
B = extend(Entity, {
init: function () {
var sup = Entity.prototype;
sup.init.call(this, 'B');
}
});
I'm working on making performance updates on my javascript code.
In Firefox I got this warning:
mutating the [[Prototype]] of an object will cause your code to run very slowly; instead create the object with the correct initial [[Prototype]] value using Object.create
I wrote some scripts to prove this, and the results are great: without mutation a simple script runs 66% faster.
But I have trouble converting my code without mutation, I can't write the getters:
This is what I have now:
// Class
function FooBar(options) {
this.options = options;
}
// Prototype
FooBar.prototype = {
// Getters
get a() {
return this.options.a;
},
get b() {
return this.options.b;
},
get ab() {
return this.options.a + this.options.b;
},
// Methods
displayOptions: function() {
console.log(this.options);
}
};
// Code
var options = {
a: 'foo',
b: 'bar'
};
var fooBar = new FooBar(options);
console.log(fooBar.a);
console.log(fooBar.b);
console.log(fooBar.ab);
fooBar.displayOptions();
The getters as a prototype using the this keyword in their return are the problem.
If I use Object.defineProperty the this keyword is wrong, unless I do it inside the constructor, but it would recreate the property on each instance of the class and slow my code down even further.
This works (I just messed up the syntax in my previous attempt):
// Class
function FooBar (options) {
this.options = options;
}
//Prototype getters
Object.defineProperty(FooBar.prototype, 'a', {
get: function() {
return this.options.a;
}
});
Object.defineProperty(FooBar.prototype, 'b', {
get: function() {
return this.options.b;
}
});
Object.defineProperty(FooBar.prototype, 'ab', {
get: function() {
return this.options.a + this.options.b;
}
});
// Methods
FooBar.prototype.displayOptions = function() {
console.log(this.options);
};
// Code
var options = {
a:'foo',
b:'bar'
};
var fooBar = new FooBar (options);
console.log(fooBar.a);
console.log(fooBar.b);
console.log(fooBar.ab);
fooBar.displayOptions();
For those who are curious about the benefits of converting scripts like this to run faster: Run following code and look to your output in the console (Chrome - 66% faster, Firefox - no difference (curious, since I got the warning from Firefox)):
// WITHOUT PROTOTYPING
var Person1 = function() {
this.name = 'myName';
this.changeName = function(name) {
this.name = name;
};
this.changeName2 = function(name) {
this.name = name;
};
this.changeName3 = function(name) {
this.name = name;
};
this.changeName4 = function(name) {
this.name = name;
};
}
// WITH PROTOTYPING, WITH MUTATION
var Person2 = function() {
this.name = 'myName';
}
Person2.prototype = {
changeName: function(name) {
this.name = name;
},
changeName2: function(name) {
this.name = name;
},
changeName3: function(name) {
this.name = name;
},
changeName4: function(name) {
this.name = name;
}
};
// WITH PROTOTYPING, WITHOUT MUTATION
var Person3 = function() {
this.name = 'myName';
}
Person3.prototype.changeName = function(name) {
this.name = name;
};
Person3.prototype.changeName2 = function(name) {
this.name = name;
};
Person3.prototype.changeName3 = function(name) {
this.name = name;
};
Person3.prototype.changeName4 = function(name) {
this.name = name;
};
// DO THE TEST
var i=0, len=1000000;
// TEST1
window.performance.mark('mark_test_start');
for(i=0;i<len;i++) {
p = new Person1();
p.changeName('myName2');
}
window.performance.mark('mark_test_end');
window.performance.measure('no-prototyping', 'mark_test_start', 'mark_test_end');
// TEST2
window.performance.mark('mark_test2_start');
for(i=0;i<len;i++) {
p = new Person2();
p.changeName('myName2');
}
window.performance.mark('mark_test2_end');
window.performance.measure('prototyping-with-mutation', 'mark_test2_start', 'mark_test2_end');
// TEST3
window.performance.mark('mark_test3_start');
for(i=0;i<len;i++) {
p = new Person2();
p.changeName('myName2');
}
window.performance.mark('mark_test3_end');
window.performance.measure('prototyping-without-mutation', 'mark_test3_start', 'mark_test3_end');
// OUTPUT tests
var items = window.performance.getEntriesByType('measure');
for (var i = 0; i < items.length; ++i) {
var req = items[i];
console.log(req.name + ': ' + req.duration.toFixed(2));
}
In the BusMonitor object, "this" refers to window object thats why "name" property become global for entire script when I call BaseFunction.call(this) on BusMonitor object. I just want the BaseFunction's properties only available to BusMonitor object. How to do that ?
function BaseFunction() {
this.name = "test";
}
var BusMonitor = function () {
BaseFunction.call(this);
return {
init: function () {
}
}
}();
I can do it by the way below but I dont want to create object like this.
function BusMonitor () {
BaseFunction.call(this);
return {
init: function () {
}
}
};
var busMonitor = new BusMonitor();
busMonitor.init();
You can, if it's possible of course, create object first and then pass it to BaseFunction
function BaseFunction() {
this.name = "test";
}
var BusMonitor = function () {
var obj = {
init: function () { }
};
BaseFunction.call(obj);
return obj;
}();
You can define a localScope in BusMonitor to hold name value, like this:
function BaseFunction() {
this.name = "test";
}
var BusMonitor = function () {
var localScope = {};
BaseFunction.call(localScope);
console.log("local name:" + localScope.name);
return {
init: function () {
}
}
}();
console.log("global name: " + name);
I need to use logic like visitor pattern and I've created new
sample which failed in visitor.visit(self); and I got error undefined is not a function,
any idea what am I missing?
var Entity = function (file,name) {
var self = this;
var name;
var type;
var log = {};
this.setName = function (name) {
this.name = name;
};
this.accept = function (visitor) {
visitor.visit(self);
};
this.getName = function () {
return name;
};
this.getType = function () {
return type;
};
this.getLog = function () {
return log;
};
};
//Start using visitor
var verifyFile = function () {
this.visit = function (file) {
alert("test");
};
};
function test(){
var file = new Entity();
file.accept(verifyFile);
};
You are injecting a function that defines a function, but your code is looking for an object that contains a function - see below
var Entity = function(file, name) {
var self = this;
var name;
var type;
var log = {};
this.setName = function(name) {
this.name = name;
};
this.accept = function(visitor) {
visitor.visit(self);
};
this.getName = function() {
return name;
};
this.getType = function() {
return type;
};
this.getLog = function() {
return log;
};
};
//Start using visitor
var verifyFile = {
visit : function(file) {
alert("test");
}
};
function test() {
var file = new Entity();
file.accept(verifyFile);
};
test()