how i can access to parent variable on exports module?
function ThunderClient(key){//my class
this.key = key //i want have access to this variable
}
ThunderClient.prototype.users = require('./modules/users')(route_rest,this.key); //this.key are key of ThunderClient
ThunderClient.prototype.address = require('./modules/address')(route_rest,this.key);//this.key are key of ThunderClient
require('./modules/address')(route_rest,this.key);
this.key is a key of ThunderClient (on construct i fill this variable).
On my module users i want have access to this.key of ThunderClient but if i use "this.key" on require doesn't work, how i can this?
Have your imported functions at the top:
var users = require('./modules/users');
var address = require('./modules/address');
Then just wrap those imported functions:
ThunderClient.prototype.users = function(){ return users(route_rest, this.key); }
ThunderClient.prototype.address = function(){ return address(route_rest, this.key); }
If you want to have instance specific users assigned at creation then you'll need to add them to the created instance inside your constructor and not in the prototype.
function ThunderClient(key){
this.key = key;
this.users = users(route_rest, this.key);
this.address = address(route_rest, this.key);
}
The lines ThunderClient.prototype.users = require('...') and ThunderClient.prototype.address are being executed in the global scope, instead of an instance of your ThunderClient module.
for example: ThunderClient.prototype.users = require('./modules/users')(route_rest,this.key);
In a Web Browser, this would be window, meaning you are checking window.key instead of doing something like this:
ThunderClient.prototype.getKey = function() {
return this.key; // here, 'this' is definitely our module instance
};
var client = new ThunderClient('abc');
console.log(client.getKey); // abc
Related
If I have some base factory that has a bunch of methods I want to extend to a bunch of other factories such as
function TestFactory() {
var service = {};
service.name = null
service.lastname = null
service.screech = function() {
alert(service.name + service.lastname)
}
return service;
}
And I want to extend that functionality to another service such as
function NewFactory() {
var service = angular.copy(TestFactory)
service.name = 'Cool'
service.lastname = 'Guy'
return service;
}
I would expect NewFactory.screech() to alert "CoolGuy", but it appears it is calling the screech method in the scope of the original TestFactory where name and lastname are null.
How can I accomplish this pattern?
I have also tried using angular.extend but had the same result.
Change service to this inside the definition of service.screech:
service.screech = function() {
alert(this.name + this.lastname)
}
It didn't work because when you referred to service inside the function, due to closure, service was hard-coded to the service object at the time of definition. The reference was not updated when you made the copy. this, on the other hand, is dynamic and always refers the the object that the function is being called on, e.g. with service.screech().
Also, you need to set service to a copy of the object resulting from the TestFactory, not to a copy of the TestFactory itself:
var service = angular.copy(TestFactory())
Change service variable to this. Closure will bind the service variable to the function instead service should be using scope of the object so that it can be inherited.
All functions inside the factory should be using this to refer the object.
function TestFactory() {
var service = {};
service.name = null
service.lastname = null
service.screech = function() {
alert(this.name + this.lastname)
}
return service;
}
Also change the following code to return the factory object not the Factory Function
function NewFactory() {
var service = angular.copy(TestFactory())
service.name = 'Cool'
service.lastname = 'Guy'
return service;
}
How do I add properties to a constructor function in JavaScript? For example. If I have the following function.
function Hotel(name)
{
this.name = name;
};
var hotel1 = new Hotel('Park');
can I add a "local" variable that can be used locally within the class as if it were private with the same notation using the keyword "this". Of course it would not be private since objects created will be able to use it correct?
Can I do something like this. Do I use the this keyword or do I use the var keyword
which one is it? I have example 2 on the function constructor on the bottom
1. var numRooms = 40;
2. this.numRooms = 40;
3. numRooms : 40,
function Hotel(name)
{
this.name = name;
this.numRooms = 40;
};
I know that if I want a function within the object constructor I need to use the this word. Will that work as well for normal variables as I have asked above.
function Hotel(name)
{
this.name = name;
this.numRooms = 40;
this.addNumRoomsPlusFive = function()
{
return this.numRooms + 5;
}
};
You can simple add a private variable to your constructor:
function Hotel(name) {
var private = 'private';
this.name = name;
};
But if you will use your Hotel function without a new operator, all properties and functions which was attached to this will become global.
function Hotel(name) {
var private = 'private';
this.name = name;
};
var hotel = Hotel('test');
console.log(name); // test
It is good idea to return an object in constructor function:
function Hotel(name) {
var
private_var = 'private',
private_func = function() {
// your code
};
retur {
name: 'name',
public_func: private_func
}
};
var hotel = Hotel('test');
console.log(name); // undefined
So if you will use Hotel constructor without new operator no global variable will be created. This is possible only if the return value is an object. Otherwise, if you try to return anything that is not an object, the constructor will proceed with its usual behaviour and return this.
can I add a "local" variable that can be used locally within the class as if it were private with the same notation using the keyword "this".
Yes we can:
// API implementation in the library
function Hotel(name) {
// only our library code knows about the actual value
const numRooms = 'privateNoRoomsVar';
this.name = name;
this[numRooms] = 40;
this.addNumRoomsPlusFive = function() {
return this[numRooms] + 5;
}
};
// from the library user's perspective
const hotel = new Hotel('Transylvania');
console.log('rooms+5 =', hotel.addNumRoomsPlusFive());
console.log('hotel.numRooms =', hotel.numRooms); // undefined
// also, users don't have access to 'numRooms' variable so they can't use hotel[numRooms].
If a user looks at the source code and finds out the value privateNoRoomsVar, then they can misuse the API.
For that we need to use symobls:
// API implementation in the library
function Hotel(name) {
// no one can duplicate a symbol so the variable is really private
const numRooms = Symbol();
this.name = name;
this[numRooms] = 40;
this.addNumRoomsPlusFive = function() {
return this[numRooms] + 5;
}
};
// from the library user's perspective
const hotel = new Hotel('Transylvania');
console.log('rooms+5 =', hotel.addNumRoomsPlusFive());
console.log('hotel.numRooms =', hotel.numRooms); // undefined
// there is no way users will get access to the symbol object so the variable remains private.
Private class features, #privateField, are supported by all the browsers so we don’t have to worry about this anymore.
// API implementation in the library
class Hotel {
// private field
#numRooms = 40;
constructor(name) {
this.name = name;
}
addNumRoomsPlusFive() {
return this.#numRooms + 5;
}
};
// from the library user's perspective
const hotel = new Hotel('Transylvania');
console.log('rooms+5 =', hotel.addNumRoomsPlusFive());
console.log('hotel.numRooms =', hotel.numRooms); // undefined
//console.log('hotel.numRooms =', hotel.#numRooms); // throws error
Javascript historically creates objects from prototypes of other objects. It was a result of EMCA2015, that you have a distinct syntax of a class that specifies an object. As an aside, if you mouse over the table in that link it gives dates of when the feature was implemented.
A javascript object created by the new operator is more or less a combination of an associative array ( what you make with let avar={}; ) that can access the function level scopes it is defined in. The keys of the array are its properties. According to its creator, Javascript was created to be an easy to use program language without a hierarchy of types. One of the ways it accomplished this is by more or less considering its mapping type to be equivalent to the prototypical Object which object oriented programming languages describe.
Adding properties in 2022
function AProtoype(arg1, arg2, arg3){
//this defines a property
this.pa=arg1;
/* unicorns in this section */
let x = 1;
/*
a getter which has the same syntax as a property
but returns x from the scope which it references and
not the object.
*/
get getx() => x;
}
let object = new AProtoype(2,3,4);
Is equivalent to the following code for the purposes of data access but not inheritance and typing. The new operator also sets variables on an object that are used for these purposes.
function NewObject(arg1, arg2, arg3){
let prototype = {};
/*dragons in this section, as you are not using the this keyword to accomplish things*/
prototype.pa = arg1;
Object.defineProperty(prototype, "getx", {get:()=>x});
return prototype;
}
//If you do this instead of using the new operator it is an anti-pattern.
//And like all anti-patterns: "But it works!"
let object = NewObject(2,3,4);
The relevant property defining methods where in some sense supported as early as 2010, 2011. I do not have a contemporary source to that time to confirm if you could pull off what I'm doing though, and you'd only want to if all else failed and it needed to run on Internet Explorer 9. In the event all else is failing, you may want to read the documentation for Object.create, which is also of interest because more or less provides an api to make new objects.
Now, for a fun time and horror, you can also define a function that returns this, and get an object back with an equivalent binding of that function. The horror comes when it is an object in global scope, and you rename a property of that object; as Javascript will resolve the name collision by happily writing on whatever it finds if it can. You can then use this to re-implement the prototype pattern that javascripts new operator is built off of conceptually, for the sake of science.
When you use a "constructor function" in Javascript, any properties defined on the instance using the this keyword become public. This is unavoidable, because Javascript objects have no concept of private properties - if it exists, it can be accessed directly as object.property.
For example, if you tried to do as in the following snippet, mimicking a typical getter/setter pattern with a private variable in Java or C# (note that even if this worked, this is not idiomatic Javascript):
function MyObject(privateVar) {
this.privateVar = privateVar;
}
MyObject.prototype.getVar = function() {
return this.privateVar;
};
MyObject.prototype.setVar = function(newVal) {
this.privateVar = newVal;
};
then while you can indeed use the getter and setter to do as you expect, you can also just access and set the private variable directly! Demonstration:
function MyObject(privateVar) {
this.privateVar = privateVar;
}
MyObject.prototype.getVar = function() {
return this.privateVar;
};
MyObject.prototype.setVar = function(newVal) {
this.privateVar = newVal;
};
var obj = new MyObject(1);
// using public getter/setter
console.log(obj.getVar()); // 1
obj.setVar(2);
console.log(obj.getVar()); // 2
// using private variable directly - not intended to work
console.log(obj.privateVar); // 2
obj.privateVar = 3;
console.log(obj.getVar()); // 3 (using public API to get it to show that the direct update to the private variable also affects the intended public methods)
There is though a way to mimic the effect of private variables. They're not actually object properties - because, as I have just demonstrated, such are intrinsically public - but the same can be mimicked by:
not using a "constructor function" at all, but a regular function that happens to return an object. This is all a constructor function really does, anyway - the difference in JS is only syntactic, that you do not need to use the new keyword when you call the function. (Although you still can, if you really prefer - any function that returns an object can be called with new and behave in the same way as without it, although performance will likely suffer a little as the function would then construct a brand new object and throw it away. See MDN for a justification of these statements, particularly step 4.)
inside this function, using a regular variable as the private variable. This variable will be completely inaccessible from outside by the simple rules of scope, but you can still have the returned object retain access to it by the "magic" of closures.
Here is the above getter/setter example translated to this procedure, as well as demonstrations of it working. (I hasten to add again though, that this wouldn't be considered idiomatic code in Javascript.)
function makeObjectWithPrivateVar(privateVar) {
function getPrivateVar() {
return privateVar;
}
function setPrivateVar(newVal) {
privateVar = newVal;
}
return { getPrivateVar, setPrivateVar };
}
var obj = makeObjectWithPrivateVar(1);
// getter
console.log(obj.getPrivateVar()); // 1
// setter
obj.setPrivateVar(2);
// getter again to observe the change
console.log(obj.getPrivateVar()); // 2
// but how could we access the private var directly??
// answer, we can't
console.log(obj.privateVar); // undefined
console.log(privateVar); // ReferenceError, privateVar is not in scope!
Note finally though that it's rare in modern Javascript to use the function-based constructors in this style, since the class keyword makes it easier to mimic traditional class-based languages like Java if you really want to. And in particular, more recent browsers support private properties directly (you just have to prefix the property name with a #), so the initial code snippet translated into a class and using this feature, will work fine:
class MyObject {
#privateVar
constructor(privateVar) {
this.#privateVar = privateVar;
}
getVar() {
return this.#privateVar;
}
setVar(newVal) {
this.#privateVar = newVal;
}
}
var obj = new MyObject(1);
// using public getter/setter
console.log(obj.getVar()); // 1
obj.setVar(2);
console.log(obj.getVar()); // 2
// using private variable directly - now doesn't work
console.log(obj.privateVar); // undefined, it doesn't exist
// console.log(obj.#privateVar); // error as it's explicitly private, uncomment to see error message
Usually it's performed using closures:
var Hotel = (function() {
var numrooms=40; // some kind of private static variable
return function(name) { // constructor
this.numrooms = numrooms;
this.name = name;
};
}());
var instance = new Hotel("myname");
I have the following code...
spa.factory("linkService", function() {
var currentLink = null;
return {currentLink:};
});
var cssController = spa.controller("cssController", function(linkService, currentLink) {
this.fileName = linkService.currentLink;
});
var navigationController = spa.controller("navigationController", function(linkService, currentLink) {
this.setLink = function(setValue) {
linkService.currentLink = setValue;
};
this.checkCurrent = function(checkValue) {
return linkService.currentLink == checkValue;
}
});
I've created this code from a snippet I wrote in another question, and fixed the things I was told were wrong with my first attempt. That question can be found here. This is a more specific case, and is therefore not a duplicate.
After checking the console, I believe the problem with this script lies in the factory.
The attempted function of the linkService factory is to provide a variable, currentLink which can be accessed and changed dynamically by more than one controller. The variable inside the factory I believe should be accessed by injecting the factory as a dependency into the controller function, as well as the variable.
What is the issue here?
Your linkService factory returns an object with the slot 'currentLink' and its value undefined.
You have to return the variable directly or you can return an object which references your variable or you can return an object which includes getter and setters to your variables.
The last variant has the advantage of having a nice interface defined in place.
Your code will be better readable.
spa.factory("linkService", function() {
var currentLink = "/myLink.html";
/* accessor for currentLink */
var getLink = function(){
return currentLink;
};
return {get: getLink}; // service interface
});
--- update
Some more details:
currentLink is the variable which should be accessed and which is present in the context of the linkService only
the factory returns the object "{get: getLink}" as the service. So if a controller injects the linkService, it gets this object.
Using linkService.get(); you can access the variable currentLink.
getLink is a local function only. It serves as an accessor.
The factory should return objects/methods as such:
spa.factory("linkService", function() {
var linkServiceFactory = {};
var _currentLink = null;
linkServiceFactory.currentLink = _currentLink;
return linkServiceFactory;
});
In the controller to inject it with the factory name to get its sub-parts.:
var cssController = spa.controller("cssController", function(linkService) {
this.fileName = linkService.currentLink;
});
Similarly,
var navigationController = spa.controller("navigationController", function(linkService) {
// other code.
});
i need to create a javascript function with a private variable that has setter and getter methods. i tried:
function createSecretHolder(secret) {
this._secret = secret;
var getSecret = function(){
return this._secret;
}
var setSecret = function(secret){
this._secret = secret;
}
}
and a version with:
this.getSecret = function()...
and
this.seSecret = function()...
it is not passing the test suite on code wars. something like
var obj = createSecretHolder(secret);
obj.getSecret();
obj.setSecret(newSecret);
and others which are hidden. I get an error TypeError: Cannot read property 'getSecret' of undefined and another cannot call method setSecret
createSecretHolder() doesn't return a value so createSecretHolder(secret) returns undefined.
So var obj = createSecretHolder(secret); sets obj to undefined. Hence the error "Cannot read property 'getSecret' of undefined" when you try to access obj.getSecret().
Even if it returned an object, you have declared getSecret using var inside a function. Variables described that way are scoped to the function. So when you try to access it outside the function, as you do in obj.getSecret(), that won't work.
You also seem to misunderstand how this works. It will not create a private variable.
There are a number of ways to do this. Here's one:
function createSecretHolder(mySecret) {
var secret = mySecret;
return {
getSecret: function(){
return secret;
},
setSecret: function (mySecret){
secret = mySecret;
}
};
}
When you use a Constructor to create an object you need to use the new keyword.
Inside your constructor you set a property with this._secret = secret. This is accessible from outside. It should be var _secret = secret.
Also you create local functions inside your object to get/set _secret. They should be methods of the object. See below.
// object constructor
function createSecretHolder(secret) {
// local variable. it isn't accessible from outside
var _secret = secret;
// method to get the secret
this.getSecret = function() {
return _secret;
}
// method to set the secret
this.setSecret = function(secret){
_secret = secret;
}
}
// create new "createSecretHolder" object
var secret = new createSecretHolder("secret 1");
secret.getSecret(); // returns "secret 1"
secret.setSecret("secret 2");
secret.getSecret(); // returns "secret 2"
Look into prototypejs OO programming.
If you can't use prototypejs because of jQuery conflicts, there is a version of it only with OO support here: https://github.com/Prescia/Prototypejslt
Your could would look like:
createSecretHolder= Class.create();
createSecretHolder.prototype = {
_secret: 0,
othervariable: true,
initialize: function(inSecret) { // this is the constructor on prototypejs
this._secret = inSecret;
}
}
// Create instance:
var myInstance = new createSecretHolder(5);
// so this should alert "5":
alert(myInstance._secret);
I can't live without prototypejs Object Orientation, so I often use this light version that won't conflict with other stuff
So I know that I can fix the scope of my module class below using bind as in this answer.
The only thing is that I use a slightly diffrerent syntax for my module and I am not quite sure how to apply it?
My question is then, how do I apply bind to my function correctly so that the context of this is my module?
Code:
var module = (function () {
var module = function (name) {
this.getName= function() {
return name;
}
};
module.prototype = {
something: function () {
// my function needs to access getName from here...
}
};
return module;
})();
Usage:
var foo = module('nameValue');
foo.something();
Are you sure using apply rather than bind in this case wouldn't be a better implementation?
If you just want to make the class properties available for access in a modular setup, you'll need to expose them in the class function declaration. Then they'll be available for public access using those methods.
var module = (function () {
function module (name) {
// public method exposing *name* variable with "privileged" access
this.getName= function() {
return name;
}
// publicly exposing *name* variable itself (ahh! It's naked!)
// this.name = name; // use only for read+write access to variable
};
// only setting one prototype parameter here so let's save some lines...
module.prototype.something = function () {
return this.getName(); // or
// return this.name // for direct variable exposure
};
return module;
})();
Then you can create your instances:
var mod1 = new module("bar");
var mod2 = new module("foo");
var mod3 = new module("win");
And apply a bind later on...
Though by using apply, you can do this:
var getNameOfModule = function(){ return this.getName(); }
getNameOfModule.apply(mod1); // bar
getNameOfModule.apply(mod2); // foo
getNameOfModule.apply(mod3); // win
This would depend entirely on the structure of your setup.
Also, it's good practice to start class names with a capital (as in Module vs. module).
You may want to create first an anonymous function and then set the others, and then call getName() using a self reference to the module object.
var module = function () {
var module = function(){};
module.getName = function (name) {
return name;
};
var self = module;
module.prototype.something = function () {
alert(self.getName('myName'));
};
return module;
};
var myMod = module();
myMod.prototype.something();
Here's the live example http://jsfiddle.net/ybfjB/