Reputation: 109
Methods(Object's function) can refer to object's variable using the "this" keyword.
Can function's properties refer to function variables?
Eg:-
function foo()
{
var x=5;
}
foo.help = {o1:x};// o1 is not initialized to x.
//Using o1:this.x also doesn't help. Why? Explain please.
Is there anyway to initialize o1 to x?
Example 9-1. A simple JavaScript class
// range.js: A class representing a range of values.
// This is a factory function that returns a new range object.
function range(from, to) {
// Use the inherit() function to create an object that inherits from the
// prototype object defined below. The prototype object is stored as
// a property of this function, and defines the shared methods (behavior)
// for all range objects.
var r = inherit(range.methods);
// Store the start and end points (state) of this new range object.
// These are noninherited properties that are unique to this object.
r.from = from;
r.to = to;
// Finally return the new object
return r;
}
// This prototype object defines methods inherited by all range objects.
range.methods = {
// Return true if x is in the range, false otherwise
// This method works for textual and Date ranges as well as numeric.
includes: function(x) { return this.from <= x && x <= this.to; },
// Invoke f once for each integer in the range.
// This method works only for numeric ranges.
foreach: function(f) {
for(var x = Math.ceil(this.from); x <= this.to; x++) f(x);
},
// Return a string representation of the range
toString: function() { return "(" + this.from + "..." + this.to + ")"; }
};
// Here are example uses of a range object.
var r = range(1,3); // Create a range object
r.includes(2); // => true: 2 is in the range
r.foreach(console.log); // Prints 1 2 3
console.log(r); // Prints (1...3)
What I understand : Range is a function with variable from and to. Range.methods is Range's property.It is defined outside Range() but it can still access from and to (using this.from and this.to ). How? Thank you.
Upvotes: 1
Views: 181
Reputation: 26716
this answer is based on edited question -- original answer is below
Your understanding is a little backwards.
The function doesn't have from
and to
in the way you think it does.
If I built this a different way, to get almost all of the same functionality, but be much, much easier for a person who is new to JS to understand, I would write it like this:
// my `makeRange` function makes an object
// then it gives it all of the things a range object needs
// then it returns the new object
var makeRange = function (min, max) {
// there are cleaner more-compact ways of doing this
// I'm writing this out in long-form to show you exactly what's going on
var rangeObject = {};
rangeObject.from = min;
rangeObject.to = max;
rangeObject.includes = includes;
rangeObject.foreach = foreach;
rangeObject.toString = toString;
return rangeObject;
};
// these are all of the functions inside of `range.methods`
// they don't have to be attached to the function ***AT ALL***, for ***ANY REASON***
// other than the author wanted them to be there for the sake of organization
// Here, I'm just putting them out on their own, for sake of clarity
var includes = function (x) { return this.from <= x && x <= this.to; },
foreach = function (func) {
var min = this.from,
max = this.to,
i = 0;
for (i = min; i <= max; i += 1) { func(i); }
},
toString = function () { return "(" + this.from + "..." + this.to + ")"; };
var range_3_to_5 = makeRange(3, 5),
range_6_to_12 = makeRange(6, 12);
range_3_to_5.from; // 3
range_6_to_12.includes(8); // true
range_6_to_12.foreach(function (i) { console.log(i); }); // [logs:] 6,7,8,9,10,11,12
The methods
on range
in the example aren't a part of the function.
They're methods which are given to the objects, as they are constructed.
In the example you gave, this is happening inside of the r = inherit(range.methods);
call, which isn't explained in that block of code.
The this
doesn't refer to the function at all.
It refers to the final object which uses the methods, at the time the method is called.
My range_3_to_5
and range_6_to_12
are both using the same copy of includes
.
When range_3_to_5.includes(6);
is called, this
is set to range_3_to_5
, and then the function uses this.from
and this.to
to determine if x
is in the range.
There's no complex magic here.
We're just calling a function which "makes" something in a specific way, like a factory assembly-line, and then passes the finished version out.
It's attaching shared functions to each copy on the assembly line, and those shared functions use this
to figure out which copy they're dealing with at the time.
var car = { license : "a32 vx98" },
truck = { license : "vdx 2000" },
jeep = { license : "mkv 3a2b" };
var read_license = function () { console.log(this.license); };
car.read_license = read_license;
truck.read_license = read_license;
car.read_license(); // [logs:] a32 vx98
truck.read_license(); // [logs:] vdx 2000
I can even call the function on its own, using the function's .call
or .apply
method to manually set this
.
read_license.call(jeep); // [logs:] mkv 3a2b
Or use .bind
to save a version of the function which ALWAYS uses the same value for this
.
var read_car_license = read_license.bind(car);
read_car_license(); // a32 vx98
previous answer below
Not even remotely.
Variables live inside of the functions that they're created in:
var myFunction = function () {
var myValue = 23;
console.log(myValue);
};
myFunction(); // [log:] 23
console.log(myValue); // undefined
Values can live inside of functions further in:
var myFunction = function () {
var myValue = 23,
sayValue = function () {
console.log(myValue);
};
sayValue(); // will log 23 when you call `myFunction`
}
myFunction(); // [log:] 23
But if you want your variable to live OUTSIDE of the function (instead of further inside), then you either need to return the value to something, or set it to something, directly, from inside of the function.
var myOutsideValue = 42,
myFunction = function () {
var myValue = 23;
myOutsideValue = myValue;
};
console.log(myOutsideValue); // 42
myFunction();
console.log(myOutsideValue); // 23
Or returned...
var myReturnedValue = 0,
myFunction = function () {
var myValue = 23;
return myValue;
};
myReturnedValue = myFunction();
console.log(myReturnedValue); // [log:] 23
Or you can pass in an array or object to modify:
var myObject = {},
myFunction = function (obj) {
var myValue = 23;
obj.value = myValue;
};
myFunction(myObject);
console.log(myObject.value); // [log:] 23
Functions CAN reference themselves.
And because in JavaScript, functions are objects (and can have their own properties and methods), you can add things to them the same way you'd add properties to any {}
object.
var myFunc = function () {
var myValue = 23;
myFunc.properties = {};
myFunc.properties.value = myValue;
};
myFunc();
console.log(myFunc.properties.value); // [logs:] 23
None of this has anything to do with this
.
this
is used for the opposite of what you're looking for.
It's for when you're inside a function which is attached to an object, and you want to read other properties/run other methods that are on that object.
var myObject = {
x : 23,
y : 42,
sayX : function () { console.log(this.x); },
sayY : function () { console.log(this.y); }
};
myObject.sayX(); // [logs:] 23
this
is used in a couple of other spots, but really, that's it's primary role: accessing or setting values/methods on the object which the function is attached to (either through dot-property access obj.func()
, or through manual setting, using .call
/.apply
/.bind
), with the other very regular situation being the creation of new objects, using the new
keyword.
So the way to get your x
to work isn't to figure out this
, it's to set it within the function, itself, or, more-appropriately, pass x
out (return x
) to another variable, outside, and then set the value yourself.
var foo = function () {
var x = "x";
return x;
},
variable; // === undefined
foo.help = { o1 : 0 };
variable = foo(); // variable === "x"
foo.help.o1 = variable;
// or shorter: foo.help.o1 = foo();
Alternative:
var help = { o1 : 0 },
foo = function (obj) {
var x = "x";
obj.o1 = x;
};
foo(help);
foo.help = help;
this
only works inside of functions
var obj = {};
obj.x = 12;
obj.y = this.x + 5; // DOESN'T WORK
If this
works in the last example, it's only because it's using this
from inside of a function which would be referring to the FUNCTION'S this
, and not to obj
. And if you're calling a function which isn't attached to an object (obj.func();
or func.call(obj)
or new_func = func.bind(obj);
), then this
will point to window
.
Upvotes: 3
Reputation: 191819
In the context foo.help = {o1: x}
, you are not in the same lexical scope as the definition of x
, which would be inside of the foo
function scope. This also applies to this.x
(which apply in object scope).
function foo() {
var x = 5;
this.help = x;
}
Upvotes: 0