Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I've seen a few other developers talk about binding scope in JavaScript but it has always seemed to me like this is an inaccurate phrase. The Function.prototype.call and Function.prototype.apply don't pass scope around between two methods; they change the caller of the function - two very different things. For example:

function outer()
{
    var item = { foo: 'foo' };
    var bar = 'bar';
    inner.apply(item, null);
}

function inner()
{
    console.log(this.foo); //foo
    console.log(bar);      //ReferenceError: bar is not defined
}

If the scope of outer was really passed into inner, I would expect that inner would be able to access bar, but it can't. bar was in scope in outer and it is out of scope in inner. Hence, the scope wasn't passed. Even the Mozilla docs don't mention anything about passing scope:

Calls a function with a given this value and arguments provided as an array.

Am I misunderstanding scope or specifically scope as it applies to JavaScript? Or is it these other developers that are misunderstanding it?

share|improve this question
2  
from the sounds of it, it's them. you seem to have a descent grasp on this. Side Note: It's nice to see some people still RTFD :) –  rlemon Sep 18 '12 at 17:12
add comment

3 Answers

up vote 3 down vote accepted

You are correct. It's better to think in terms of object context than scope with call and apply. However, this following example might be seen as making a scope accessible to another object context:

function objFactory(){
    var someProperty = 'a property of some sort';
    this.getSomeProperty = function(){ return someProperty; };
}

var someObj = new objFactory(),
somePlainObj = {};

'a property of some sort' === someObj.getSomeProperty.apply(somePlainObj);//true

I may not have the exact details right but I think JS objects built from function constructors are basically just functions that are copied (along with their scopes - js scopes are function only), executed, and then simply never garbage collect (so all values are persistent) and assigned to a namespace you can access their internally defined properties via altered 'this' rules when you invoke with the 'new' keyword. But the internal vars aren't really private properties exactly (although we tend to think of them that way). They're function constructor properties accessed by the methods via closure.

But the first part of the process is still like a function firing. That makes the internal var accessed via closure which is like a copy of the scope at the moment the constructor was finished with the function execution step.

share|improve this answer
add comment

When you call inner.apply(item, null) you are calling inner() as though it were a method of the item object which has foo defined on it. That sets the this object in inner() to be item. You aren't really exposing the scope of the outer() function to the inner() function. You are passing the object (and can therefore access its attributes). You are not passing the lexical scope of the function which defined that object.

share|improve this answer
    
That's what I thought. I had forgotten the phrase lexical scope since my days in college. Looking that up seems to have a few good resources on the different types of scopes that are available. Thanks. –  Jeff Sep 18 '12 at 18:02
add comment

Look at http://howtonode.org/, the series of articles "Learning JavaScript with Object Graphs". apply and call are the most magical thing in JS (probably along with closure scoping), you cannot fully understand it unless you understand the basics.

share|improve this answer
    
Thanks herby. I'll check that out. If you asked me, I would say I understand the basics. On a quick scan of the first part of that series, I didn't see anything to contradict my position that I explained in my question. Do you have a direct answer to my question or were you just recommending a few good articles? –  Jeff Sep 18 '12 at 17:59
    
GlenPeterson said it right. apply and call are about setting this for a call; there is no way to pass scopes at all. But you must take into account that functions are in fact lexical closures so they take hold of their scope for their lifetime. The articles aim to show this, that is why I recommended them. –  herby Sep 18 '12 at 18:03
    
Thanks for the clarification. I'm sure I can learn a few good things from these articles. For example, I've never written a JavaScript function that returns a function. I guess since functions can be passed around and functions maintain their own scope, then one can say that the scope is being passed around as well - but I dont think that is what the articles that I referenced had intended. –  Jeff Sep 18 '12 at 18:06
    
Sort of. I said it can't be "passed" because by passing I meant giving it to someone else to manipulate. But it is not passed in that sense, it is just "brought with" the closure - only the code inside the closure can see/manipulate it. But these are the details (the devil is in the details ;-) ). BTW, functions returning functions are pretty common stuff in JavaScript; usage of closures to "simulate private variables" etc. are common patterns which all base upon closures (returned from other functions) having lexical scope. –  herby Sep 18 '12 at 18:12
    
tnx for the link to how to node. –  MebAlone Sep 19 '12 at 5:01
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.