Amit0191
Amit0191

Reputation: 109

JavaSCript Example (Oreilly book)

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

Answers (2)

LetterEh
LetterEh

Reputation: 26716

EDIT

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

Explosion Pills
Explosion Pills

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

Related Questions