Mixing datatypes, functions and objects - javascript

When you use require and loads a module, you seems capable of create a function with properties or a object that can be invoked as a function.
console.log(require('events').EventEmitter);
//{ [Function: EventEmitter] defaultMaxListeners: 10, listenerCount: [Function] }
I have done this before* using the require module so I can replicate it. But I want to create more manually. I have some questions in this regards:
Is possible replicate this manually, harcoded without require?
Is possible to create any type of property like getters or setters?
Is posible to create one of these 'objects' when you use a constructor?
Thanks in advance.
*Or I remember that, I have a terrible memory
Edited:
To be clear: I'm not talking about prototype. In my example you can see that, for example, defaultMaxListeners dont come from prototype. In code:
EventEmitter.defaultMaxListeners // 10
EventEmitter.prototype.defaultMaxListeners // undefined
EventEmitter() //No error

Is possible replicate this manually, harcoded without require? Is
possible to create any type of property like getters or setters? Is
posible to create one of these 'objects' when you use a constructor?
Yes
In JS, functions are also objects. You can attach properties to them like any other object. Also, in JS, functions can be used as both functions as well as object constructors.
The following example shows what you can do to a function. I'm using Classical OOP terms, since I don't know what they call them in JS.
function SomeConstructor(){
this.instanceProperty = 'foo';
}
// Instance Method
SomeConstructor.prototype.method = function(){
console.log('method');
}
// Static Method
SomeConstructor.staticMethod = function(){
console.log('static');
}
var test = new SomeConstructor();
test.method();
SomeConstructor.staticMethod();

Related

Static method instead of Prototype method Javascript

When instance function are called in a class each instance of object get own copy of function but in prototype method and static method no copy is created , they belong to class, so if they both doesn't create a copy of their function, so why do we have static function if we can simply use prototype method if we don't want to copy??
I am a little bit confuse, if anyone can explain it will be a great help
In order to use a prototype/instance method, you need to either have an instance of an object or specifically access the type's .prototype. For methods that don't require an instance, a static method provides simpler syntax. Think of the String.fromCharCode() method as an example. It wouldn't make sense to say:
let str = "dummy string".fromCharCode(127);
The extra string instance there is just a distraction from what you're really trying to do:
let str = String.fromCharCode(127);
This applies good programming practices of reduced coupling (not requiring an instance in order to invoke a method that doesn't need it) and information hiding (by not exposing a method on instances of objects which doesn't pertain to those specific objects).
A static method does not exist on instances. Prototype methods do. So, if you want to call someArr.filter(x => x > 5) that would be an instance method that works on the given array.
An example of astatic method is Array.isArray(someArr). It makes very little sense to make the static method an instance method because you'd need an instance before calling it. That would lead to code like someArr.isArray(someArr) which is illogical - you need an array to check if something is an array. And that can very easily be fail spectacularly if someArr is not in fact an array:
const someArr = {
isArray() { return true; },
filter() { return "I am not an array"; },
};
console.log(someArr.isArray(someArr));
console.log(someArr.filter(x => x > 5));
Yes, that example is indeed highly illogical in order to highlight why it is weird. Assuming .isArray() was an instance method, you could create a new array in order to use it to call [].isArray(someArr). But that method does not require any instance data. The object created exists only to give you access to the method and is discarded immediately afterwards. That design is still not sensible.
Both static methods and prototype methods exist independent from any instances. The difference is that a prototype method expects to be called on an instance, i.e. to have an instance passed as the this argument, whereas the static method does not require an instance and expects none.
Even without placing them anywhere on the class, we can see this distinction in the following example:
function myStaticMethod(arg) {
console.log('Doing something with '+arg);
}
function myMethod(arg) {
console.log('Doing something with '+this+' and '+arg);
}
const myInstance = new MyClass();
myStaticMethod('value');
myMethod.call(myInstance, 'value');
Now the .call() syntax is not very ergonomic, we prefer myInstance.myMethod('value'), so that is why we place the method on the prototype object of the class, having it inherited by all instances.
For static methods, this is not necessary. They don't need an instance, we don't want to call them on an instance, we want to call them as MyClass.myStaticMethod('value') so that is where we place them. We could put them on the prototype as well, but that would lead to confusion (myInstance.myStaticMethod()), name collisions, and unncessarily long invocations (MyClass.prototype.myStaticMethod()). It's imaginable to write new MyClass().myStaticMethod(), but there you would unnecessarily create an instance that is not required (and it might not even be possible to create).

How do I mock dependencies to return specific data?

Coming from Moq in C# where you can do the following:
someMock
.Setup(toBeMocked => toBeMocked.MockedMethod(It.IsAny<Something>()))
.Returns(something);
Then in the unit test when I call
toBeMocked.MockedMethod()
It returns something. How do I do this with sinonjs?
Sinon works a bit differently than Moq, largely because C# is a much different language than JS. Moq creates sub-classes to inject fake methods, while sinon is able to inject them by assigning them directly onto objects.
Most basic pattern would be, assuming toBeMocked is an object with an instance method MockedMethod:
sinon.stub(toBeMocked, 'MockedMethod').returns(something);
This assigns the stub method to the MockedMethod property of the toBeMocked object. As such, it only affects that object, even if MockedMethod is a prototype method.
If you want to replace a method for all instances of a constructor, you can do that instead. Assuming MockedClass is the constructor you used to create the toBeMocked object, it'd look like this:
sinon.stub(MockedClass.prototype, 'MockedMethod').returns(something);
Then later in your teardown code:
MockedClass.prototype.MockedMethod.restore();
You need to restore it like this because that prototype is not created anew between tests, so your stub will pollute your other test code if you don't.
From the documentation https://sinonjs.org/releases/v7.2.2/stubs/ :
const fakeMethod = () => something;
const stub = sinon.stub(toBeMocked , 'MockedMethod');
stub.callsFake(fakeMethod);
UPDATE : example jsfiddle

Constructor taking object without duplicating the object

I want to turn a plain JavaScript object into one with a prototype etc, without cloning the object. Is this possible?
Essentially, instead of this:
var MyClass = function(fromObj) {
this.propA = fromObj.propA;
this.propB = fromObj.propB;
...
}
inherit (SuperClass, MyClass);
I would like to:
var MyClass = function(fromObj) {
this = fromObj;
}
inherit (SuperClass, MyClass);
To be extra clear: I would like the object returned from the constructor to be the same object that was passed in (not a duplicate, not a clone).
Is there a way to achieve this? Or a better way to describe what I'm asking for? :)
I'd like this for two reasons:
We're loading a lot of objects, and speed and memory may start to matter.
There are lots of places where the "plain old javascript objects" are used, and it may be hard to make sure they all point to the new instantiated object.
I guess you want to do this so that the objects created by JSON.parse are instances of something other than Object.
One option is to assign a new [[Prototype]] that is from the specified constructor using Object.setPrototypeOf, however there are performance warnings for this on MDN (I have no idea on the validity of the claims).
A more efficient solution might be to create "wrapper" objects and attach those created by JSON as a property. This approach is used by a number of DOM libraries and avoids the possibility of property names from the JSON data clashing with method names of the object (e.g. the DOM libraries can use methods with the same name and characteristics as DOM methods, but don't overwrite or clash with them).
Data could be held in a closure so that only getters and setters defined by the constructor can access it.

Reference type values and initialization

I'm not a guru at JS. Today I was told during a code review that for the following code below, Reference type values need to be initialized in the constructor which means change this somehow referring to the constraints: {}
define(["dojo/_base/declare",
"dijit/form/CurrencyTextBox",
"xxxx/util/currencyUtil",
"./_InputWidgetMixin",
"../secure/_SecureWidgetMixin"
],
function (declare, xxxTextBox, xxxUtil, _InputWidgetMixin, _SecureWidgetMixin) {
return declare("xxx.widget.input.xxxTextBox", [xxxTextBox, _InputWidgetMixin, _SecureWidgetMixin], {
constraints: {},
reset: function () {
this._set("value", this.resetValue);
},
not sure what this means and why I need to move this and if it's a Dojo thing or plain JS thing to worry about and why.
I would say this is a dojo thing, it's to do with how dojo implements a class-like system. To understand why this is important, take a look at this recent question : Dojo instances of same widgets are not saparated.
As mentioned there, arrays and objects are shared across instances, so if you don't want this behaviour, you should initialize them in your constructor. Dojo docs on declare
Your constraints will be a shared object across all instances of xxxTextBox unless in your constructor you assign a new object to constraints:
this.constraints = {};
This is because the constraints value is part of a prototype object and therefore this is a javascript thing. Once you assign this.constraints you obscure the reference to the shared constraints with the objects own local copy.

mimicking jQuery plugins with plain javascript or coffeescript

Without using jQuery, I'd like to know how to mimik a jQuery plugin
For example, maybe $('div.x').plugin() attaches an onclick to divs, and increments and displays an internal value.
Where does jQuery actually store the object with the internal variable?
Does an object get explicitly created somewhere and associated with each node?
I get lost trying to explain to myself why there is no explicit object creation in the main application listing.... must happen within the plugin somehow?
(PS: I am less concerned with the query engine side... just the plugin side :)
thanks
Normally you define a function like plugin() by writing
$.fn.plugin = ...
As discussed here, $.fn is actually just a shortcut for jQuery.prototype. When you attach a method to a constructor's prototype, JavaScript automatically attaches it to all instances created from that constructor with the new keyword, which jQuery does internally when you write something like $('li'). See http://javascriptweblog.wordpress.com/2010/06/07/understanding-javascript-prototypes/.
So here's a simple example of creating a library called kQuery in CoffeeScript that allows you to 1) create named instances and 2) add plugins:
instances = {}
kQuery = (name) ->
K = (name) ->
return instances[name] if instances[name]
instances[name] = new kQuery name
K.fn = kQuery.prototype
That's it! Now if someone were to write
K.fn.plugin = -> console.log 'foo'
K('whatev').plugin()
they'd see foo on their console. Note that the reason for the separate kQuery and K functions is that if you called new K from within the K function, you'd get an infinite loop (which would resolve to an error).

Categories