I was doing some testing and I got no clue why if using call I inherit from another object like, const objC = funcB.call(objA,'Erades') I got an object, but if I inherit from a function I got a function with wired (to me) behavior.
I don't understand why to get method B I have to do funcC.getLastName()
If anybody can help me to understand this...
TIA
// testing Call to inherit objects / functions
// -------------------------------------------
// we declare our first function
const funcA = function(firstName) {
this.firstName = firstName;
this.getFirstName = function() {
return 'My name is ' + this.firstName;
};
return this;
};
// Create an object out of that function
const objA = new funcA('Rodrigo');
// declare second function
const funcB = function (lastName) {
this.lastName = lastName;
this.getLastName = function() {
return 'My last name is ' + this.lastName;
};
return this;
};
// Create an Object from funcB and ObjectA
const objC = funcB.call(objA,'Erades');
// We get an object
console.log("TYPE OF: ", typeof objC)
console.log('raw:', objC);
console.log('method A: ', objC.getFirstName());
console.log('prop A: ', objC.firstName);
console.log('method B: ', objC.getLastName());
console.log('prop B: ', objC.lastName);
console.log('------------');
// if we don't want to create an object out of a function and an object,
// we could also inherit two functions, but the result really surprise me
const funcC = funcB.call(funcA,'Alonso');
// We get a function !!!!!
console.log("TYPE OF: ", typeof funcC);
console.log('raw:', funcC);
// To get result we need to do this:
console.log('method ==>: ', funcC('Rui'));
console.log('method A: ', funcC('Rui').getFirstName());
console.log('prop A: ', funcC('Maria').firstName);
console.log('method B: ', funcC.getLastName()); // looks like static method ???
console.log('prop B: ', funcC.lastName);
console.log('------------');
You're not inheriting when you use call this way. You are passing an instance in and getting the same instance out with some modifications:
const funcA = function(firstName) {
this.firstName = firstName;
this.getFirstName = function() {
return 'My name is ' + this.firstName;
};
return this;
};
const objA = new funcA('Rodrigo');
const funcB = function (lastName) {
this.lastName = lastName;
this.getLastName = function() {
return 'My last name is ' + this.lastName;
};
return this;
};
const objC = funcB.call(objA,'Erades');
// ObjC IS ObjaA
console.log(objC === objA)
When you use call the object passed in becomes the this of the function. You then add some properties and return this which is the same object you just passed in.
Passing a function to call() is no different. When you write:
funcB.call(funcA,'Alonso');
you are calling the function funcB with Alonso as an argument. Inside that function this will refer to funcA. So you will set a lastName property on funcA and getLastName property pointing to a function, then return funcA which is then assigned to the variable funcC. funcC and funcA point to exactly the same function.
const funcA = function(firstName) {
this.firstName = firstName;
this.getFirstName = function() {
return 'My name is ' + this.firstName;
};
return this;
};
const funcB = function (lastName) {
this.lastName = lastName;
this.getLastName = function() {
return 'My last name is ' + this.lastName;
};
return this;
};
const funcC = funcB.call(funcA,'Alonso');
// the same reference
console.log(funcC === funcA)
// but when you called funcB with it, it added some properties:
console.log("funC lastname:", funcC.lastName)
// they are the same object so this also works:
console.log("also funcA lastname:", funcC.lastName)
Related
function User() {
this.firstname = null;
get getFirst() {
return this.firstname;
}
}
JavaScript console gives me an error saying "Unexpected Identifier" on line 12
var Jake = new User();
Jake.firstname = "Jake";
document.write(Jake.getFirst);
That's just not the syntax you use to define a getter. You'd use it in an object literal, like this:
var foo = {
get bar() {
return 42;
}
};
foo.bar; // 42
...but that's not where your get is.
To define it where your get is, you'd use defineProperty:
function User() {
this.firstname = null;
Object.defineProperty(this, "first", {
get: function() {
return this.firstname;
}
});
}
Note I called it first, not getFirst, because it's an accessor function, which looks like a direct property access, and so is traditionally not given a name in a verb form:
var u = new User();
u.firstname = "Paul";
u.first; // "Paul"
If you wanted to create a function called getFirst, just get rid of the get keyword:
this.getFirst = function() {
return firstname;
};
// ...
var u = new User();
u.firstname = "Paul";
u.getFirst(); // "Paul"
I believe the issue is that you are using get with a function rather than the object literal as outlined in the documentation.
var User = {
firstName: 'Darren',
get getFirst() { return this.firstName; }
}
alert(User.getFirst);
https://jsfiddle.net/ecao51n0/
get is intended to be called within an object, not a function constructor. If you want to declare getFirst as a function on User, then here's one way you could do it:
function User() {
this.firstname = null;
this.getFirst = function() {
return this.firstname;
}
}
Then you would also need to call getFirst as a function:
var Jake = new User();
Jake.firstname = "Jake";
document.write(Jake.getFirst());
This is what I have:
var Person = function(fname, lname) {
this.fname = fname;
this.lname = lname;
};
Person.prototype = {
getFullName: function() {
return this.fname + " " + this.lname;
},
doStuff: function(stuff) {
return stuff();
}
};
var john = new Person("John", "Doe");
The doStuff function works with other functions, but doing the following returns undefined undefined:
console.log(john.doStuff(john.getFullName));
What's wrong with what what I have and how can I change it to make it work?
Thanks.
It's because this doesn't refer to the object.
You could use the .bind() method in order to set the value of this:
john.doStuff(john.getFullName.bind(john));
However, that's not very flexible, therefore you could just bind it within the doStuff method:
doStuff: function(stuff) {
return stuff.apply(this);
}
If you know foo.doStuff's arg always wants to be called on foo, you can write this in doStuff
// ...
doStuff: function (stuff) {
return stuff.apply(this, Array.prototype.slice.call(arguments, 1));
}
I'd like to be able to do the following:
person('male');
person.age(34);
As you can see, I want the person object to be both a function as an object. What I mean is that doing so:
function person(gender){
this.gender = gender || 'unknown';
}
excludes me from doing so:
person.gender; // undefined
unless I create a new object from the person function, like so:
var me = new person();
me.gender; // 'unknown'
which I do not want, as I still want to be able to set other properties, like so:
person.age = 34;
Is this even possible? Of am I trying to accomplish the impossible?
To clarify: I don't want to need to create instances. The key is that I just want to be able to both call the function person as call a function.property().
EDIT: Perhaps I've confused many (including myself) by using a wrong example. A simpler question would be: How would I be able to call a function and a 'property' of that function, like so:
car();
car.start();
both at the same time without the need to create an instance of car?
We might be able to give a better answer if you would explain the motivation behind what you want to do. However, yes, what you describe is possible. In JavaScript, functions are just another type of object. That means that you could define a function, then set properties on it like so:
var person = function () {
return "Hi, I am a person!";
};
person.species = "human";
person.foo = 42;
console.log( person() ); // prints: Hi, I am a person!
console.log( person.species ): // prints: human
console.log( person.foo ); // prints: 42
Or working from your second example:
var car = function () {
return {
model: "Focus",
make: "Ford",
year: 2010
};
};
car.start = function () {
return "Vroom!";
};
console.log ( car.make ); // prints: Ford
console.log ( car.start() ); // prints Vroom!
By the way, this is not the same as a function that returns an object. That might look like this:
var person = function () {
return {
species: "human",
name: "Bob",
age: 27
};
};
var bob = person();
bob.occupation = "cubicle drone";
console.log( bob.name ); // prints: Bob
console.log( bob.occupation ); // prints: cubicle drone
console.log( person.occupation ); // prints: undefined
console.log( bob == person ); // prints: false
Variables bob and person both hold objects, but not the same object, not even the same type of object.
Instead of using this inside your function, which refers to the Object instance created when running this function as a constructor by invoking it with the new operator you can use arguments.callee to refer to the function itself
function person(gender){
arguments.callee.gender = gender || 'unknown';
}
If you want to ensure that a function is always used as a constructor even if invoked without the new operator, you can do it by implicitly invoking it.
function person(gender){
if(!(this instanceof person)){ return new person(gender); }
this.gender = gender || 'unknown';
}
In all other regards functions can do anything regular objects can, that's why they are often described as "first class objects".
You can simply assign them properties like objects, or methods like
function car(){
}
car.start = function(){
}
You can also let them inherit methods from a function using the __proto__ property.
function bird(){}
function platypus(){}
bird.layEggs = function(){};
platypus.__proto__ = bird;
platypus.layEggs() // now you know
a small example using the instanceof way that #Winchestro is using
on jsfiddle:http://jsfiddle.net/47EEr/
'use strict';
function person(gender, age, name) {
if (!(this instanceof person)) {
return new person(gender, age, name);
}
var props = { gender: '', age: 0, name: '' }, fnCreateProp = function(prop, value) {
Object.defineProperty(this, prop, {
get: function() {
return props[prop];
},
set: function(val) {
console.log('setting prop ' + prop + ' to ' + val);
props[prop] = val;
}
});
}.bind(this);
for (var prop in props) {
if (!props.hasOwnProperty(prop)) {
continue;
}
fnCreateProp(prop, props[prop]);
}
this.gender = gender;
this.age = age;
this.name = name;
this.toString = function(element) {
var str = '[Person=(';
for (var prop in props) {
if (!props.hasOwnProperty(prop)) {
continue;
}
if (str.indexOf('(') !== str.length-1) {
str += ',';
}
str += prop +': ' + props[prop];
}
str += ')]';
if (typeof element !== 'undefined') {
var el = document.getElementById(element);
if (el) {
el.innerHTML = str;
}
}
return str;
};
this.birthday = function() {
this.age++;
};
}
var p1 = person('male', 33, 'male 1');
var p2 = new person();
p2.age = 32; p2.gender = 'female'; p2.name = 'female 1';
p1.toString('person1');
p2.toString('person2');
p2.birthday();
p2.toString('person2birthday');
You can also do:
function person(gender){
return {
gender: gender || 'unknown'
};
}
var p = person('male');
p.age = 34;
p.name = 'John';
etc...
No "new" is used and you can still re-use the person function.
Your edit:
EDIT: Perhaps I've confused many (including myself) by using a wrong example. A simpler question would be: How would I be able to
call a function and a 'property' of that function, like so:
car();
car.start();
both at the same time without the need to create an instance of car?
Is this what you are looking for?
function car() {
console.log("car called");
car.start = function() {
console.log("car.start called");
}
}
car();
car.start();
/**** output:****
car called
car.start called
*/
I have a simple singleton object and am having problems when a method calls another method that returns an object property.
var Customer = (function () {
var instance;
function init() {
this.firstName = "";
this.lastName = "";
function _myGetFirstName() {
return this.firstName;
}
function _myGetLastName() {
return this.lastName;
}
function _myGetFullName() {
return _myGetFirstName() + ' ' + _myGetLastName();
}
function _mySetFirstName(p) {
this.firstName = p;
}
function _mySetLastName(p) {
this.lastName = p;
}
return {
setFirstName: _mySetFirstName,
setLastName: _mySetLastName,
getFirstName: _myGetFirstName,
getLastName: _myGetLastName,
getFullName: _myGetFullName,
};
};
return {
getInstance: function () {
if (!instance) {
instance = init();
}
return instance;
}
};
})();
I'm using the object like this:
var cust = Customer.getInstance();
cust.setFirstName('FOO');
cust.setLastName('BAR');
console.log(cust.getFirstName()); // displays FOO - OK
console.log(cust.getLastName()); // displays BAR - OK
console.log(cust.getFullName()); // displays nothing
This is a pattern I've seen on the web multiple times, but I just can't get it to work. What am I doing wrong with the "_myGetFullName" method? When I get the individual first and last names, it works fine. Thanks
The instance you return is a new Object containing a few methods known to it. The local methods are not within the scope of instance. You should call the instance methods, so:
function _myGetFullName() {
return this.getFirstName() + ' ' + this.getLastName();
}
or call the function within the context of the current instance
function _myGetFullName() {
return _myGetFirstName.call(instance) + ' ' +
_myGetLastName.call(instance);
}
or, ofcourse
function _myGetFullName() {
return this.firstName + ' ' + this.lastName;
}
Anyway, you code is a bit odd. You can only derive one instance of Customer. Didn't you mean something like this?
My question is precisely the same as this one Javascript revealing module pattern, public properties
In that thread, the answer was given but not the "why". Here's the same question restated with my own example:
myApp.User = function () {
var firstName = 'Default',
lastName = 'Default';
function setFirstName(name) {
firstName = name;
}
function setLastName(name) {
lastName = name;
}
function getFirstName() {
return firstName;
}
function getLastName() {
return lastName;
}
return {
getLastName: getLastName,
**getFirstName: getFirstName**,
setLastName: setLastName,
setFirstName: firstName
};
};
In this scenario, User().getFirstName always evals to "Default" -- even if I change it to some other value via the setFirstName function.
If I replace with setFirstName like:
return {
getLastName: getLastName,
**getFirstName: getFirstName**,
setLastName: setLastName,
setFirstName: firstName
};
I am able to access the changed value. I understand that the var firstName is passed by value which is why the updated values are not reflected. I don't understand what is special about the function. Where is the pointer to the value within the function living? Why do all the functions "magically" get access to the update(s)?
Where is the pointer to the value within the function living?
In the scope of the function - which contains all the variables it has access to. This access makes the function a closure actually.
Why do all the functions "magically" get access to the update(s)?
Because all the functions share the variables declared in a higher scope.
They don't "magically" get access to the update. They are inside myApp.User that's why they can access the variable location.
When you do myApp.User().getFirstName(), because getFirstName is inside the function (scope), it will be able to access variables declared both inside this function and outside this function.
function a(){
var b = "hello";
return {
setB: function(c){ b = c; },
getB: function(){ return b; }
};
}
var obj = new a();
obj.getB(); //hello
obj.setB("new");
obj.getB(); //new
In the example above, getB and setB both live inside your object, and they can access all variables inside the a() scope.
look at what you did here in your first example
setFirstName: firstName
setFirstName is not a reference to the function "setFirstName" but rather the variable 'firstName'... you don't have access to the function 'setFirstName'. That function is still unavailable to you, so you can't modify firstName, like you want.
It is out of scope - you didn't return it, so that it is available to the outside world, so to speak. It is not available "outside" of the scope of the function. Return the function (), and apply the "setFirstName", as shown below.
try this;
myApp.User = function () {
var firstName = 'Default',
lastName = 'Default';
function setFirstName(name) {
firstName = name;
}
function setLastName(name) {
lastName = name;
}
function getFirstName() {
return firstName;
}
function getLastName() {
return lastName;
}
return {
getLastName: getLastName,
getFirstName: getFirstName,
setLastName: setLastName,
setFirstName: setFirstName
};
}();
myApp.User.setFirstName('bill');
myApp.User.getFirstName();
var User = function () {
var firstName = 'Default',
lastName = 'Default';
return {
getLastName: function() { return lastName; },
getFirstName: function() { return firstName; },
setLastName: function(name) { lastName = name; },
setFirstName: function(name) { firstName = name; },
getName: function() { return firstName + ' ' + lastName; }
};
};
var u = User(),
v = User();
console.log( u.getName() + ' - ' + v.getName() );
// Outputs: 'Default Default - Default Default'
u.setFirstName( 'Alice' );
u.setLastName( 'Bob' );
console.log( u.getName() + ' - ' + v.getName() );
// Outputs: 'Alice Bob - Default Default'