Why should I use 'underbar(_)' for getting my function done? - javascript

I was studying inheritance of javascript and made a function to test it.
Here is the code:
function subClass(obj) {
const parent = (this === window) ? Function : this;
const F = function() {};
const child = function() {
const _parent = child.parent;
if(_parent && _parent !== Function) {
_parent.apply(this, arguments);
}
if(child.prototype._init) {
child.prototype._init.apply(this, arguments);
}
};
F.prototype = parent.prototype;
child.prototype = new F();
child.prototype.constructor = child;
child.parent = parent;
child.subClass = arguments.callee;
for (let i in obj) {
if (obj.hasOwnProperty(i)) {
child.prototype[i] = obj[i];
}
}
return child;
}
Then I made a sample object to adapt the function subClass. :
const person_obj = {
_init: function() {
console.log("person init");
},
getName: function() {
return this.name;
},
setName: function(name) {
this.name = name;
}
};
Finally, here is the output code. :
const Person = subClass(person_obj);
const person = new Person();
person.setName("dorae");
console.log(person.getName());
Here is the question.
What I want as a result for console.log(person.getName()); is dorae,
but instead empty space comes out as a result.
However, when I change two 'this.name's in person_obj to 'this._name',
the exact result 'dorae' comes out.
Even though I came up to the result what I wanted,
I couldn't get the reason why I got the result.
I would appreciate if you let me know the reason why I get the answer only
when I use the underbar in front of the variable.
Thank you.

Related

How to create a JS object within constructor and "parent object" as constructors argument?

The question might sound a bit confusing so I'll let the code explain:
function Foo(arg) {
const argument = arg;
const fooPart = new FooPart(this);
this.printArg = function() {
console.log(argument);
}
}
function FooPart(foo) {
this.parent = foo;
this.parent.printArg();
}
let foo = new Foo("this is the argument");
This is not working for me. How can I solve this problem or better - what would be the correct approach for this?
Thanks
function Foo(arg) {
this.argument = arg;
this.fooPart = new FooPart(this);
}
Foo.prototype.printArg = function() {
console.log(this.argument);
}
function FooPart(foo) {
this.parent = foo;
this.parent.printArg();
}
let foo = new Foo("this is the argument");
You should call FooPart after printArg definition
You should use this.parent to access parent
The problem is that you define printArg after trying to call it.
The traditional way to define a "class" which doesn't have this problem would be:
function Foo(arg) {
this.argument = arg;
this.fooPart = new FooPart(this);
}
Foo.prototype.printArg = function() {
console.log(this.argument);
}
function FooPart(foo) {
this.parent = foo;
this.parent.printArg();
}
let foo = new Foo("this is the argument");
The more modern version to define an "actual" class is:
class Foo {
constructor(arg) {
this.argument = arg;
this.fooPart = new FooPart(this);
}
printArg() {
console.log(this.argument);
}
}
class FooPart {
constructor(foo) {
this.parent = foo;
this.parent.printArg();
}
}
let foo = new Foo("this is the argument");

Javascript Privilege Function Inheritance

I have spent the past few weeks doing a ton of research on Javascript inheritance. Firstly, I want to say that I am NOT trying to implement class-based inheritance in Javascript, however, I am trying to mimic inheritance CORRECTLY using Javascript's prototypal nature. This may be beating a dead horse, but here goes my question:
I have two simple functions:
function Animal(arg) {
var a = arg;
//privileged function has access to private variable
this.sayHi = function(name) {
// can access a here if needed
console.log('Hi: ' + name);
}
}
and:
function Person(arg) {
this.sayHi = function(name) {
super.sayHi(name + '!!!');
};
}
Person.inheritsFrom(Animal);
The following would be the expected result:
var animal = new Animal('cow');
animal.sayHi('John'); // Hi: John
var person = new Person('adult');
person.sayHi('Fred'); // Hi: Fred!!!
The "inheritsFrom()" method that I'm using for inheritance looks like:
Function.prototype.inheritsFrom = function(parent) {
if(parent.constructor == Function) { //Normal Inheritance
this.prototype = new parent;
this.prototype.constructor = this;
this.prototype.parent = parent.prototype;
} else { //Pure Virtual Inheritance
this.prototype = parent;
this.prototype.constructor = this;
this.prototype.parent = parent;
}
return this;
}
These are some of my references:
http://phrogz.net/JS/classes/OOPinJS2.html
http://www.crockford.com/javascript/inheritance.html
https://medium.com/javascript-scene/common-misconceptions-about-inheritance-in-javascript-d5d9bab29b0a
Lots of good info, still can't figure out how to inherit "privileged" methods as shown above. I'm able to call the privileged method of the parent class. Please see the following JS Fiddle: https://jsfiddle.net/jxjk5hm9/
Any guidance on inheriting privileged methods is greatly appreciated, thanks!
There is no pretty solution to this. First off,
this.prototype = new parent;
is not a good way to establish inheritance. Rather use
this.prototype = Object.create(parent.prototype);
See Benefits of using `Object.create` for inheritance for more info.
Inside the child constructor, you'd have to call the parent constructor, applying it to the current instance:
function Person(arg) {
Animal.call(this, arg);
}
then you have to iterate over all methods that have been attached to this by Animal and keep a reference to them:
function Person(arg) {
Animal.call(this, arg);
var privilegedSuper = Object.keys(this)
.filter(function(prop) { return typeof this[prop] === 'function'; }.bind(this))
.reduce(function(obj, prop) { return (obj[prop] = this[prop]), obj; }.bind(this));
}
which you can then reference in the overridden methods:
function Person(arg) {
Animal.call(this, arg);
var privilegedSuper = Object.keys(this)
.filter(function(prop) { return typeof this[prop] === 'function'; }.bind(this))
.reduce(function(obj, prop) { return (obj[prop] = this[prop]), obj; }.bind(this));
this.sayHi = function(name) {
privilegedSuper.sayHi.call(this, name + '!!!');
};
}
Is it worth the effort and the complexity? I don't think so.
Function.prototype.inheritsFrom = function(parent) {
if (parent.constructor == Function) { //Normal Inheritance
this.prototype = Object.create(parent.prototype);
this.prototype.constructor = this;
this.prototype.parent = parent.prototype;
} else { //Pure Virtual Inheritance
this.prototype = parent;
this.prototype.constructor = this;
this.prototype.parent = parent;
}
return this;
}
function Animal(arg) {
var a = arg;
//privileged function has access to private variable
this.sayHi = function(name) {
// can access a here if needed
console.log('Hi: ' + name + ' (and here is a: ' + a + ')');
}
}
function Person(arg) {
Animal.call(this, arg);
var privilegedSuper = Object.keys(this)
.filter(function(prop) {
return typeof this[prop] === 'function';
}.bind(this))
.reduce(function(obj, prop) {
return (obj[prop] = this[prop]), obj;
}.bind(this), {});
this.sayHi = function(name) {
privilegedSuper.sayHi.call(this, name + '!!!');
};
}
Person.inheritsFrom(Animal);
var animal = new Animal('cow');
animal.sayHi('John'); // Hi: John
var person = new Person('adult');
person.sayHi('Fred'); // Hi: Fred!!!

Write getters as a prototype

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

Javascript Object-Oriented-Programming

I found a Module pattern in JS:
<script>
var MODULENAME = (function(my, $) {
my.publicVar = "5";
my.publicFn = function() {};
return my;
}(MODULENAME || {}, jQuery));
</script>
However I cannot perform instantiation. Does the module pattern allow for that?
Instantiantion means basically that you'll run a function using new.
So maybe you're looking for this?
var Some = function (param) {
var somePrivateVar = 'private';
this.somePublicVar = 'public';
this.method = function () {
return param;
};
};
var some = new Some('abla');
console.log(some.method());
// some.somePrivateVar === undefined
// some.somePublicVar === 'public'
In your case MODULENAME is an object (object, not a function) with publicVar and publicFn. It's not meant to be instantiated the same way you wouldn't call new jQuery().
Your module object can contain anything. Perhaps you're looking for including a constructor in it:
var MODULENAME = (function(my, $) {
var privateVar = 10;
my.SomeConstructor = function() {
this.publicVar = 5;
}
my.SomeConstructor.prototype.someMethod = function() {};
my.SomeConstructor.prototype.getPrivate = function() { return 10; };
return my;
}(MODULENAME || {}, jQuery));
var instance = new MODULENAME.SomeConstructor();
instance.publicVar; // 5
instance.privateVar; // undefined
instance.getPrivate(); // 10
You can do this also with prototype Inheritance :
var MyClass = function(name)
{
//sharing name within the whole class
this.name = name;
}
MyClass.prototype.getName = function(){
return this.name;//now name is visible to getName method too
}
MyClass.StaticMethod = function()
{
console.log("Im Static");
// and since is not in prototype chain, this.name is not visible
}
var myclass = new MyClass("Carlos");
console.log(myclass.getName())//print "Carlos"
MyClass.StaticMethod()// print "Im Static"
myclass.StaticMethod() // error
Se all this article

Super in Backbone

When I override the clone() method of a Backbone.Model, is there a way to call this overriden method from my implantation? Something like this:
var MyModel = Backbone.Model.extend({
clone: function(){
super.clone();//calling the original clone method
}
})
You'll want to use:
Backbone.Model.prototype.clone.call(this);
This will call the original clone() method from Backbone.Model with the context of this(The current model).
From Backbone docs:
Brief aside on super: JavaScript does not provide a simple way to call
super — the function of the same name defined higher on the prototype
chain. If you override a core function like set, or save, and you want
to invoke the parent object's implementation, you'll have to
explicitly call it.
var Note = Backbone.Model.extend({
set: function(attributes, options) {
Backbone.Model.prototype.set.apply(this, arguments);
...
}
});
You can also use the __super__ property which is a reference to the parent class prototype:
var MyModel = Backbone.Model.extend({
clone: function(){
MyModel.__super__.clone.call(this);
}
});
Josh Nielsen found an elegant solution for this, which hides a lot of the ugliness.
Just add this snippet to your app to extend Backbone's model:
Backbone.Model.prototype._super = function(funcName){
return this.constructor.prototype[funcName].apply(this, _.rest(arguments));
}
Then use it like this:
Model = Backbone.model.extend({
set: function(arg){
// your code here
// call the super class function
this._super('set', arg);
}
});
Working from the answers given by geek_dave and charlysisto, I wrote this to add this._super(funcName, ...) support in classes that have multiple levels of inheritance. It's worked well in my code.
Backbone.View.prototype._super = Backbone.Model.prototype._super = function(funcName) {
// Find the scope of the caller.
var scope = null;
var scan = this.__proto__;
search: while (scope == null && scan != null) {
var names = Object.getOwnPropertyNames(scan);
for (var i = 0; i < names.length; i++) {
if (scan[names[i]] === arguments.callee.caller) {
scope = scan;
break search;
}
}
scan = scan.constructor.__super__;
}
return scan.constructor.__super__[funcName].apply(this, _.rest(arguments));
};
A year later I've fixed some bugs and made things faster. Below is the code that I use now.
var superCache = {};
// Hack "super" functionality into backbone.
Backbone.View.prototype._superFn = Backbone.Model.prototype._superFn = function(funcName, _caller) {
var caller = _caller == null ? arguments.callee.caller : _caller;
// Find the scope of the caller.
var scope = null;
var scan = this.__proto__;
var className = scan.constructor.className;
if (className != null) {
var result = superCache[className + ":" + funcName];
if (result != null) {
for (var i = 0; i < result.length; i++) {
if (result[i].caller === caller) {
return result[i].fn;
}
}
}
}
search: while (scope == null && scan != null) {
var names = Object.getOwnPropertyNames(scan);
for (var i = 0; i < names.length; i++) {
if (scan[names[i]] === caller) {
scope = scan;
break search;
}
}
scan = scan.constructor.__super__;
}
var result = scan.constructor.__super__[funcName];
if (className != null) {
var entry = superCache[className + ":" + funcName];
if (entry == null) {
entry = [];
superCache[className + ":" + funcName] = entry;
}
entry.push({
caller: caller,
fn: result
});
}
return result;
};
Backbone.View.prototype._super = Backbone.Model.prototype._super = function(funcName) {
var args = new Array(arguments.length - 1);
for (var i = 0; i < args.length; i++) {
args[i] = arguments[i + 1];
}
return this._superFn(funcName, arguments.callee.caller).apply(this, args);
};
Then given this code:
var A = Backbone.Model.extend({
// className: "A",
go1: function() { console.log("A1"); },
go2: function() { console.log("A2"); },
});
var B = A.extend({
// className: "B",
go2: function() { this._super("go2"); console.log("B2"); },
});
var C = B.extend({
// className: "C",
go1: function() { this._super("go1"); console.log("C1"); },
go2: function() { this._super("go2"); console.log("C2"); }
});
var c = new C();
c.go1();
c.go2();
The output in the console is this:
A1
C1
A2
B2
C2
What's interesting is that class C's call to this._super("go1") scans the class hierarchy until it gets a hit in class A. Other solutions do not do this.
P.S. Uncomment the className entries of the class definitions to enable caching of the _super lookup. (The assumption is that these class names will be unique in the application.)
If you want just to call this._super(); without passing the function name as an argument
Backbone.Controller.prototype._super = function(){
var fn = Backbone.Controller.prototype._super.caller, funcName;
$.each(this, function (propName, prop) {
if (prop == fn) {
funcName = propName;
}
});
return this.constructor.__super__[funcName].apply(this, _.rest(arguments));
}
Better use this plugin:
https://github.com/lukasolson/Backbone-Super
I believe you can cache the original method (although not tested):
var MyModel = Backbone.Model.extend({
origclone: Backbone.Model.clone,
clone: function(){
origclone();//calling the original clone method
}
});
backbone._super.js, from my gists: https://gist.github.com/sarink/a3cf3f08c17691395edf
// Forked/modified from: https://gist.github.com/maxbrunsfeld/1542120
// This method gives you an easier way of calling super when you're using Backbone in plain javascript.
// It lets you avoid writing the constructor's name multiple times.
// You still have to specify the name of the method.
//
// So, instead of having to write:
//
// var Animal = Backbone.Model.extend({
// word: "",
// say: function() {
// return "I say " + this.word;
// }
// });
// var Cow = Animal.extend({
// word: "moo",
// say: function() {
// return Animal.prototype.say.apply(this, arguments) + "!!!"
// }
// });
//
//
// You get to write:
//
// var Animal = Backbone.Model.extend({
// word: "",
// say: function() {
// return "I say " + this.word;
// }
// });
// var Cow = Animal.extend({
// word: "moo",
// say: function() {
// return this._super("say", arguments) + "!!!"
// }
// });
(function(root, factory) {
if (typeof define === "function" && define.amd) {
define(["underscore", "backbone"], function(_, Backbone) {
return factory(_, Backbone);
});
}
else if (typeof exports !== "undefined") {
var _ = require("underscore");
var Backbone = require("backbone");
module.exports = factory(_, Backbone);
}
else {
factory(root._, root.Backbone);
}
}(this, function(_, Backbone) {
"use strict";
// Finds the next object up the prototype chain that has a different implementation of the method.
var findSuper = function(methodName, childObject) {
var object = childObject;
while (object[methodName] === childObject[methodName]) {
object = object.constructor.__super__;
}
return object;
};
var _super = function(methodName) {
// Keep track of how far up the prototype chain we have traversed, in order to handle nested calls to `_super`.
this.__superCallObjects__ || (this.__superCallObjects__ = {});
var currentObject = this.__superCallObjects__[methodName] || this;
var parentObject = findSuper(methodName, currentObject);
this.__superCallObjects__[methodName] = parentObject;
// If `methodName` is a function, call it with `this` as the context and `args` as the arguments, if it's an object, simply return it.
var args = _.tail(arguments);
var result = (_.isFunction(parentObject[methodName])) ? parentObject[methodName].apply(this, args) : parentObject[methodName];
delete this.__superCallObjects__[methodName];
return result;
};
// Mix in to Backbone classes
_.each(["Model", "Collection", "View", "Router"], function(klass) {
Backbone[klass].prototype._super = _super;
});
return Backbone;
}));
In the case that you don't know what the parent class is exactly (multiple inheritance or you want a helper function) then you can use the following:
var ChildModel = ParentModel.extend({
initialize: function() {
this.__proto__.constructor.__super__.initialize.apply(this, arguments);
// Do child model initialization.
}
});
With helper function:
function parent(instance) {
return instance.__proto__.constructor.__super__;
};
var ChildModel = ParentModel.extend({
initialize: function() {
parent(this).initialize.apply(this, arguments);
// Do child model initialization.
}
});
Pass the parent class as an option during instantiation:
BaseModel = Backbone.Model.extend({
initialize: function(attributes, options) {
var self = this;
this.myModel = new MyModel({parent: self});
}
});
Then in your MyModel you can call parent methods like this
this.options.parent.method();
Keep in mind this creates a retain cycle on the two objects. So to let the garbage collector do it's job you would need to manually destroy the retain on one of the objects when finished with it. If you're application is pretty large. I would encourage you to look more into hierarchal setups so events can travel up to the correct object.
2 functions below, one requires you pass in the function name, the other can "discover" which function we want the super version of
Discover.Model = Backbone.Model.extend({
_super:function(func) {
var proto = this.constructor.__super__;
if (_.isUndefined(proto[func])) {
throw "Invalid super method: " + func + " does not exist in prototype chain.";
}
return proto[func].apply(this, _.rest(arguments));
},
_superElegant:function() {
t = arguments;
var proto = this.constructor.__super__;
var name;
for (name in this) {
if (this[name] === arguments.callee.caller) {
console.log("FOUND IT " + name);
break;
} else {
console.log("NOT IT " + name);
}
}
if (_.isUndefined(proto[name])) {
throw "Super method for: " + name + " does not exist.";
} else {
console.log("Super method for: " + name + " does exist!");
}
return proto[name].apply(this, arguments);
},
});
Here is how I would do this:
ParentClassName.prototype.MethodToInvokeName.apply(this);
so for your example this is:
Model.prototype.clone.apply(this)

Categories