What is the scope of variables in JavaScript?

554,474

Solution 1

TLDR

JavaScript has lexical (also called static) scoping and closures. This means you can tell the scope of an identifier by looking at the source code.

The four scopes are:

  1. Global - visible by everything
  2. Function - visible within a function (and its sub-functions and blocks)
  3. Block - visible within a block (and its sub-blocks)
  4. Module - visible within a module

Outside of the special cases of global and module scope, variables are declared using var (function scope), let (block scope), and const (block scope). Most other forms of identifier declaration have block scope in strict mode.

Overview

Scope is the region of the codebase over which an identifier is valid.

A lexical environment is a mapping between identifier names and the values associated with them.

Scope is formed of a linked nesting of lexical environments, with each level in the nesting corresponding to a lexical environment of an ancestor execution context.

These linked lexical environments form a scope "chain". Identifier resolution is the process of searching along this chain for a matching identifier.

Identifier resolution only occurs in one direction: outwards. In this way, outer lexical environments cannot "see" into inner lexical environments.

There are three pertinent factors in deciding the scope of an identifier in JavaScript:

  1. How an identifier was declared
  2. Where an identifier was declared
  3. Whether you are in strict mode or non-strict mode

Some of the ways identifiers can be declared:

  1. var, let and const
  2. Function parameters
  3. Catch block parameter
  4. Function declarations
  5. Named function expressions
  6. Implicitly defined properties on the global object (i.e., missing out var in non-strict mode)
  7. import statements
  8. eval

Some of the locations identifiers can be declared:

  1. Global context
  2. Function body
  3. Ordinary block
  4. The top of a control structure (e.g., loop, if, while, etc.)
  5. Control structure body
  6. Modules

Declaration Styles

var

Identifiers declared using var have function scope, apart from when they are declared directly in the global context, in which case they are added as properties on the global object and have global scope. There are separate rules for their use in eval functions.

let and const

Identifiers declared using let and const have block scope, apart from when they are declared directly in the global context, in which case they have global scope.

Note: let, const and var are all hoisted. This means that their logical position of definition is the top of their enclosing scope (block or function). However, variables declared using let and const cannot be read or assigned to until control has passed the point of declaration in the source code. The interim period is known as the temporal dead zone.

function f() {
    function g() {
        console.log(x)
    }
    let x = 1
    g()
}
f() // 1 because x is hoisted even though declared with `let`!

Function parameter names

Function parameter names are scoped to the function body. Note that there is a slight complexity to this. Functions declared as default arguments close over the parameter list, and not the body of the function.

Function declarations

Function declarations have block scope in strict mode and function scope in non-strict mode. Note: non-strict mode is a complicated set of emergent rules based on the quirky historical implementations of different browsers.

Named function expressions

Named function expressions are scoped to themselves (e.g., for the purpose of recursion).

Implicitly defined properties on the global object

In non-strict mode, implicitly defined properties on the global object have global scope, because the global object sits at the top of the scope chain. In strict mode, these are not permitted.

eval

In eval strings, variables declared using var will be placed in the current scope, or, if eval is used indirectly, as properties on the global object.

Examples

The following will throw a ReferenceError because the namesx, y, and z have no meaning outside of the function f.

function f() {
    var x = 1
    let y = 1
    const z = 1
}
console.log(typeof x) // undefined (because var has function scope!)
console.log(typeof y) // undefined (because the body of the function is a block)
console.log(typeof z) // undefined (because the body of the function is a block)

The following will throw a ReferenceError for y and z, but not for x, because the visibility of x is not constrained by the block. Blocks that define the bodies of control structures like if, for, and while, behave similarly.

{
    var x = 1
    let y = 1
    const z = 1
}
console.log(x) // 1
console.log(typeof y) // undefined because `y` has block scope
console.log(typeof z) // undefined because `z` has block scope

In the following, x is visible outside of the loop because var has function scope:

for(var x = 0; x < 5; ++x) {}
console.log(x) // 5 (note this is outside the loop!)

...because of this behavior, you need to be careful about closing over variables declared using var in loops. There is only one instance of variable x declared here, and it sits logically outside of the loop.

The following prints 5, five times, and then prints 5 a sixth time for the console.log outside the loop:

for(var x = 0; x < 5; ++x) {
    setTimeout(() => console.log(x)) // closes over the `x` which is logically positioned at the top of the enclosing scope, above the loop
}
console.log(x) // note: visible outside the loop

The following prints undefined because x is block-scoped. The callbacks are run one by one asynchronously. New behavior for let variables means that each anonymous function closed over a different variable named x (unlike it would have done with var), and so integers 0 through 4 are printed.:

for(let x = 0; x < 5; ++x) {
    setTimeout(() => console.log(x)) // `let` declarations are re-declared on a per-iteration basis, so the closures capture different variables
}
console.log(typeof x) // undefined

The following will NOT throw a ReferenceError because the visibility of x is not constrained by the block; it will, however, print undefined because the variable has not been initialised (because of the if statement).

if(false) {
    var x = 1
}
console.log(x) // here, `x` has been declared, but not initialised

A variable declared at the top of a for loop using let is scoped to the body of the loop:

for(let x = 0; x < 10; ++x) {} 
console.log(typeof x) // undefined, because `x` is block-scoped

The following will throw a ReferenceError because the visibility of x is constrained by the block:

if(false) {
    let x = 1
}
console.log(typeof x) // undefined, because `x` is block-scoped

Variables declared using var, let or const are all scoped to modules:

// module1.js

var x = 0
export function f() {}

//module2.js

import f from 'module1.js'

console.log(x) // throws ReferenceError

The following will declare a property on the global object because variables declared using var within the global context are added as properties to the global object:

var x = 1
console.log(window.hasOwnProperty('x')) // true

let and const in the global context do not add properties to the global object, but still have global scope:

let x = 1
console.log(window.hasOwnProperty('x')) // false

Function parameters can be considered to be declared in the function body:

function f(x) {}
console.log(typeof x) // undefined, because `x` is scoped to the function

Catch block parameters are scoped to the catch-block body:

try {} catch(e) {}
console.log(typeof e) // undefined, because `e` is scoped to the catch block

Named function expressions are scoped only to the expression itself:

(function foo() { console.log(foo) })()
console.log(typeof foo) // undefined, because `foo` is scoped to its own expression

In non-strict mode, implicitly defined properties on the global object are globally scoped. In strict mode, you get an error.

x = 1 // implicitly defined property on the global object (no "var"!)

console.log(x) // 1
console.log(window.hasOwnProperty('x')) // true

In non-strict mode, function declarations have function scope. In strict mode, they have block scope.

'use strict'
{
    function foo() {}
}
console.log(typeof foo) // undefined, because `foo` is block-scoped

How it works under the hood

Scope is defined as the lexical region of code over which an identifier is valid.

In JavaScript, every function-object has a hidden [[Environment]] reference that is a reference to the lexical environment of the execution context (stack frame) within which it was created.

When you invoke a function, the hidden [[Call]] method is called. This method creates a new execution context and establishes a link between the new execution context and the lexical environment of the function-object. It does this by copying the [[Environment]] value on the function-object, into an outer reference field on the lexical environment of the new execution context.

Note that this link between the new execution context and the lexical environment of the function object is called a closure.

Thus, in JavaScript, scope is implemented via lexical environments linked together in a "chain" by outer references. This chain of lexical environments is called the scope chain, and identifier resolution occurs by searching up the chain for a matching identifier.

Find out more.

Solution 2

Javascript uses scope chains to establish the scope for a given function. There is typically one global scope, and each function defined has its own nested scope. Any function defined within another function has a local scope which is linked to the outer function. It's always the position in the source that defines the scope.

An element in the scope chain is basically a Map with a pointer to its parent scope.

When resolving a variable, javascript starts at the innermost scope and searches outwards.

Solution 3

Variables declared globally have a global scope. Variables declared within a function are scoped to that function, and shadow global variables of the same name.

(I'm sure there are many subtleties that real JavaScript programmers will be able to point out in other answers. In particular I came across this page about what exactly this means at any time. Hopefully this more introductory link is enough to get you started though.)

Solution 4

Old school JavaScript

Traditionally, JavaScript really only has two types of scope :

  1. Global Scope : Variables are known throughout the application, from the start of the application (*)
  2. Functional Scope : Variables are known within the function they are declared in, from the start of the function (*)

I will not elaborate on this, since there are already many other answers explaining the difference.


Modern JavaScript

The most recent JavaScript specs now also allow a third scope :

  1. Block Scope : Identifiers are "known" from the top of the scope they are declared within, but they cannot be assigned to or dereferenced (read) until after the line of their declaration. This interim period is called the "temporal dead zone."

How do I create block scope variables?

Traditionally, you create your variables like this :

var myVariable = "Some text";

Block scope variables are created like this :

let myVariable = "Some text";

So what is the difference between functional scope and block scope?

To understand the difference between functional scope and block scope, consider the following code :

// i IS NOT known here
// j IS NOT known here
// k IS known here, but undefined
// l IS NOT known here

function loop(arr) {
    // i IS known here, but undefined
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here

    for( var i = 0; i < arr.length; i++ ) {
        // i IS known here, and has a value
        // j IS NOT known here
        // k IS known here, but has a value only the second time loop is called
        // l IS NOT known here
    };

    // i IS known here, and has a value
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here

    for( let j = 0; j < arr.length; j++ ) {
        // i IS known here, and has a value
        // j IS known here, and has a value
        // k IS known here, but has a value only the second time loop is called
        // l IS NOT known here
    };

    // i IS known here, and has a value
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here
}

loop([1,2,3,4]);

for( var k = 0; k < arr.length; k++ ) {
    // i IS NOT known here
    // j IS NOT known here
    // k IS known here, and has a value
    // l IS NOT known here
};

for( let l = 0; l < arr.length; l++ ) {
    // i IS NOT known here
    // j IS NOT known here
    // k IS known here, and has a value
    // l IS known here, and has a value
};

loop([1,2,3,4]);

// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS NOT known here

Here, we can see that our variable j is only known in the first for loop, but not before and after. Yet, our variable i is known in the entire function.

Also, consider that block scoped variables are not known before they are declared because they are not hoisted. You're also not allowed to redeclare the same block scoped variable within the same block. This makes block scoped variables less error prone than globally or functionally scoped variables, which are hoisted and which do not produce any errors in case of multiple declarations.


Is it safe to use block scope variables today?

Whether or not it is safe to use today, depends on your environment :

  • If you're writing server-side JavaScript code (Node.js), you can safely use the let statement.

  • If you're writing client-side JavaScript code and use a browser based transpiler (like Traceur or babel-standalone), you can safely use the let statement, however your code is likely to be anything but optimal with respect to performance.

  • If you're writing client-side JavaScript code and use a Node based transpiler (like the traceur shell script or Babel), you can safely use the let statement. And because your browser will only know about the transpiled code, performance drawbacks should be limited.

  • If you're writing client-side JavaScript code and don't use a transpiler, you need to consider browser support.

    These are some browsers that don't support let at all :

    • Internet explorer 10 and below
    • Firefox 43 and below
    • Safari 9 and below
    • Android browser 4 and below
    • Opera 27 and below
    • Chome 40 and below
    • ANY version of Opera Mini & Blackberry Browser

enter image description here


How to keep track of browser support

For an up-to-date overview of which browsers support the let statement at the time of your reading this answer, see this Can I Use page.


(*) Globally and functionally scoped variables can be initialized and used before they are declared because JavaScript variables are hoisted. This means that declarations are always much to the top of the scope.

Solution 5

Here's an example:

<script>

var globalVariable = 7; //==window.globalVariable

function aGlobal( param ) { //==window.aGlobal(); 
                            //param is only accessible in this function
  var scopedToFunction = {
    //can't be accessed outside of this function

    nested : 3 //accessible by: scopedToFunction.nested
  };

  anotherGlobal = {
    //global because there's no `var`
  }; 

}

</script>

You'll want to investigate closures, and how to use them to make private members.

Share:
554,474
lYriCAlsSH
Author by

lYriCAlsSH

for (i =o; i &lt; 24; i++) { window.document.write("It's midnight..."); } will edit when sun rises...

Updated on July 08, 2022

Comments

  • lYriCAlsSH
    lYriCAlsSH almost 2 years

    What is the scope of variables in javascript? Do they have the same scope inside as opposed to outside a function? Or does it even matter? Also, where are the variables stored if they are defined globally?

  • Kenan Banks
    Kenan Banks over 15 years
    I'm afraid to even begin answering this question. As a Real Javascript Programmer, I know how quickly the answer could get out of hand. Nice articles.
  • Jon Skeet
    Jon Skeet over 15 years
    @Triptych: I know what you mean about things getting out of hand, but please add an answer anyway. I got the above just from doing a couple of searches... an answer written by someone with actual experience is bound to be better. Please correct any of my answer which is definitely wrong though!
  • Kenan Banks
    Kenan Banks over 15 years
    Not even close to being comprehensive, but this is maybe the must-know set of Javascript scope tricks one needs to effectively even READ modern javascript.
  • lYriCAlsSH
    lYriCAlsSH over 15 years
    Considering your remark on 'ranking', i guess i'll start reading more on this sort of thing. But its not as bad as i thought, i understood the logic behind it rather well. Although, about the object properties, if i declare it globally will it be referenced by object.prototype?
  • IgorGanapolsky
    IgorGanapolsky over 13 years
    Yeah, but is it safe to use? I mean would I realistically choose this implementation if my code will run in WebKit?
  • kennytm
    kennytm over 13 years
    @Python: No, WebKit doesn't support let.
  • 000
    000 about 13 years
    Thanks, what i want to add is if you file is undefined try using new Array or new String an so on
  • marta.joed
    marta.joed almost 12 years
    Very helpful! I always keep in mind that JavaScript is NOT JAVA, especially when it comes to scope! Remember Javascript's functional heritage any time you have to think about scope
  • RobG
    RobG over 11 years
    A highly rated answer, not sure why. It's just a bunch of examples without proper explanation, then seems to confuse prototype inheritance (i.e. property resolution) with the scope chain (i.e. variable resolution). A comprehensive (and accurate) explanation of scope and property resolution is in the comp.lang.javascript FAQ notes.
  • Kenan Banks
    Kenan Banks over 11 years
    @RobG It is highly rated because it is useful and comprehensible to a wide range of programmers, minor catachresis notwithstanding. The link you have posted, while useful to some professionals, is incomprehensible to most people writing Javascript today. Feel free to fix any nomenclature issues by editing the answer.
  • RobG
    RobG over 11 years
    @triptych—I only edit answers to fix minor things, not major. Changing "scope" to "property" will fix the error, but not the issue of mixing inheritance and scope without a very clear distinction.
  • GazB
    GazB over 11 years
    I guess the only valid use for this would be if you knew all the clients would be using a Mozilla browser like for a companies internal system.
  • Igor Mukhin
    Igor Mukhin almost 11 years
    Another interesting case: for (var n = 4; false; ) { } alert(n); will output "4" (not "undefined" as you may expect);
  • MordechayS
    MordechayS almost 11 years
    If you define a variable in the outer scope, and then have an if statement define a variable inside the function with the same name, even if that if branch isn't reached it is redefined. An example - jsfiddle.net/3CxVm
  • Gerard ONeill
    Gerard ONeill over 10 years
    Or if you are programming using the XUL framework, Mozilla's interface framework where you build using css, xml, and javascript.
  • Benjamin Gruenbaum
    Benjamin Gruenbaum over 10 years
    You have some mistakes here, for one JavaScript does have forms of block scoping.
  • Gerard ONeill
    Gerard ONeill over 10 years
    My ears (eyes) are open, Benjamin -- My statements above are how I've been treating Javascript scoping, but they are not based on reading the spec. And I hope you aren't referring to the with statement (which is a form of object scoping), or Mozilla's special 'let' syntax.
  • Benjamin Gruenbaum
    Benjamin Gruenbaum over 10 years
    Well, with statement is a form of block scoping but catch clauses are a much more common form (Fun fact, v8 implements catch with a with) - that's pretty much the only forms of block scoping in JavaScript itself (That is, function, global, try/catch , with and their derivatives), however host environments have different notions of scoping - for example inline events in the browser and NodeJS's vm module.
  • Gerard ONeill
    Gerard ONeill over 10 years
    Benjamin -- from what I can see, both with and catch only introduce the object into the current scope (and thus the properties), but then after the respective block ends, the variables are reset. But for example, a new variable introduced in a catch will have the scope of the enclosing function / method.
  • Benjamin Gruenbaum
    Benjamin Gruenbaum over 10 years
    Which is exactly what block scoping means :)
  • Gerard ONeill
    Gerard ONeill over 10 years
    I think at this point we'd enter into a semantic argument. But I'm glad to know about that little nuance anyway (even if it has never come up for me..)
  • GibboK
    GibboK over 10 years
    Try out this learning quiz, it can help to understand variable scope in JS madebyknight.com/javascript-scope
  • buzzsawddog
    buzzsawddog over 10 years
    @GazB even that is a horrid idea! So today you know that your clients are using Mozilla then out comes a new memo stating that now they are using something else. I.E. the reason our pay system sucks... You must use IE8 and never IE9 or IE10 or Firefox or Chrome because it flat out wont work...
  • GazB
    GazB over 10 years
    @buzzsawddog I agree and hate systems that are limited to one browser but unforchantly it does happen and I was only saying that's at that time as far as I can see this was the only valid use for this. :)
  • Kevin Meredith
    Kevin Meredith over 10 years
    @Triptych (thanks). For this fiddle (jsfiddle.net/H4LYm/3), does a 1 print out since a within function Seven is, by default, global?
  • New Alexandria
    New Alexandria about 10 years
    Scope chains are another term for [memory] Closures... for those reading here to learn / get into javascript.
  • mplwork
    mplwork about 10 years
    Doesn't work for me with Firefox 26. I paste code or load a file, click execute and nothing happens.
  • Muhammad Umer
    Muhammad Umer about 10 years
    is this not true for functions...if i define function inside a function the this still refers to window object but it's accessible in windows object.
  • rkulla
    rkulla almost 10 years
    The closure example isn't the big picture because it's not required to have a local variable declaration in order to close over a variable. In example 5 you could put the 'var foo = 6' outside of all functions and still close over it. jsfiddle.net/Us56g
  • Gerard ONeill
    Gerard ONeill almost 10 years
    Massive edit on the post -- my misunderstanding was actually with how properties work. I also simplified what I was thinking about block scope to names defined just for the block.
  • blgt
    blgt almost 10 years
    Re. the last edit (example 8): This is exactly the same behaviour as example 2, function 2. You're simply attempting to use a local variable before you've assigned a value to it.
  • RobG
    RobG almost 10 years
    @MuhammadUmer—each execution context (e.g. global, function, eval) has its own this parameter that is set by how the function is called or the use of bind. It has nothing to do with where or how the function is defined.
  • Oriol
    Oriol over 9 years
    EcmaScript 6 draft introduces let, so other browsers will implement it. However, ES6 let behaves a bit different than mozilla's one.
  • SwiftMango
    SwiftMango about 9 years
    Not sure why this is not the accepted answer. There is actually just functional scope (prior to ECMA6 there was no "local scope") and global bindings
  • dz210
    dz210 over 8 years
    Can someone explain the last one, #9? Shouldn't the catch variable e shadow the original variable and print out the error?
  • thetrystero
    thetrystero over 8 years
    why is #4 called "object property". did you mean "method"? but there is not object anywhere in that example. I see that "this" === "global" but this has nothing to do with objects. can someone please explain? EDIT: I think you mean to use it as a constructor, as in var b = new five() not to invoke it on its own. is that right? in that case i see that "this" === "b". so I guess b is the object. but it still has no properties attached to it.
  • Oriol
    Oriol over 7 years
    "IS NOT known" is misleading, because the variable is declared there due to hoisting.
  • softwarematter
    softwarematter over 7 years
    5. Closure example is not correct. Unless six() is called, the alert doesn't get executed.
  • Kenan Banks
    Kenan Banks over 7 years
    @devnull - did you try it? It's correct as written (the function self-executes).
  • Bob
    Bob about 7 years
    (long time since answer posted ) Block scope ;developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
  • Huang C.
    Huang C. about 7 years
    @Triptych In point 6, // Won't get reached, because 'a' is set in the constructor above. seven.prototype.a = -1; However, I think it's not that the statement won't get reached, but even although it executes, the this.a = 7 in constructor function will override the value of a to 7 because this.a = 7 executes after copying values from prototype.
  • Kenan Banks
    Kenan Banks over 6 years
    Somehow Jon Skeet is responsible for MY most popular answer on Stack Overflow.
  • zakir
    zakir over 6 years
    The above example is misleading, variables 'i' and 'j' are not known outside the block. 'Let' variables has scope only in that particular block not outside of the block. Let has other advantages as well, you can't redeclare the variable again and it's hold the lexical scope.
  • John Slegers
    John Slegers over 6 years
    @Oriol : Finally got to improving my answer and address hoisting. Thanks for pointing out my answer needed improvement. I made a few other improvements as well.
  • John Slegers
    John Slegers over 6 years
    @zakir : Variables declared with let (block scope) are not known outside the block they're declared in. Variables declared with var (functional or global scope) are known outside the block they're declared in buth not known outside the function they're declared in, if they're declared inside a function. I thought I was pretty clear on that. Anyway, I added more info on differences in behavior with respect to hoisting and with respect to multiple declarations of the same variable within the same scope. Thanks for pointing that out.
  • deniz
    deniz about 6 years
    This was helpful, thanks! I think it would be even more helpful to be specific about what you mean by "Modern JavaScript" and "Old school JavaScript"; I think these correspond to ECMAScript 6 / ES6 / ECMAScript 2015, and to earlier versions, respectively?
  • John Slegers
    John Slegers about 6 years
    @JonSchneider : Correct! Where I say "old school JavaScript", I'm ineed talking about ECMAScript 5 and where I'm refering to "modern JavaScript", I'm taking about ECMAScript 6 (aka ECMAScript 2015). I didn't think it was really that important to go into detail here, though, as most people just want to know (1) what's the difference between block scope and functional scope, (2) what browsers support block scope and (3) whether it's safe to use block scope today for whatever project they're working on. So I focused my answer on addressing those issues.
  • John Slegers
    John Slegers about 6 years
    @JonSchneider : (continued) Nevertheless, I just added a link to a Smashing Magazine article on ES6 / ES2015 for those who want to learn more about which features have been added to JavaScript during the last couple of years... of anyone else who might be wondering what I mean with "modern JavaScript".
  • overexchange
    overexchange about 6 years
    If the scoping rules are not precise/concise using var keyword, then do not use it. Use const or let keyword
  • foxt7ot
    foxt7ot almost 6 years
    @Triptych Appreciate your answer but don't you think that this answer needs to be updated as with the advent of let block level of scope is introduced in javascript and in point 3 you'd mentioned that "No such thing as block scope in JavaScript ". Please check this blog as well javascriptissexy.com/…
  • Ayush Jain
    Ayush Jain about 5 years
    Basically, Javascript uses Lexical Scoping (Also known as Static Scoping) which says a variable defined in one part of your program may not be accessible to the other parts of the program. A variable declared in this fashion is sometimes called as a private variable. The opposite to this is Dynamic Scoping which is not at all used by Javascript. fullstackgeek.blogspot.com/2019/01/…
  • Ben Aston
    Ben Aston about 4 years
    Scope and inheritance are two difference things.
  • iAmOren
    iAmOren almost 4 years
    The question was about vars as in "variables"! You have included crap like let and const that destroy javascript and users of those are writing javastrict... var rules!
  • iAmOren
    iAmOren almost 4 years
    The question was about var - true javascript. your answer refers to the pollution of js with "let". at least you didn't refer to the much worse "const". these are limitation borrowed for no reason from other languages and will never be used by me...
  • iAmOren
    iAmOren almost 4 years
    Question about vars. "const" and "let" are a crappy subtraction from/burden on- javascript.
  • iAmOren
    iAmOren almost 4 years
    question about var. "const" and "let" = the destroyers of javascript, are not in the question and should not be in javascript...
  • iAmOren
    iAmOren almost 4 years
    const and let are not part of the question. why bring them up? personally, they don't belong in javascript...
  • iAmOren
    iAmOren almost 4 years
    const and let are not in the question. why would you bring them up? the question was about vars... const and let are annoying and destroying javascript.
  • Gibolt
    Gibolt almost 4 years
    Your opinion does not change the validity of the answer. Question is about scoping. const and let are the modern replacements for var which define scope. Neither existed when the question was asked
  • supercat
    supercat over 3 years
    Was Javascript really inspired by Hypertalk? I don't recall Hypertalk having such interesting scoping, but the inspiration would perhaps explain Javascript's bizarre operator overloading where 10=="10.0" and 10=="10", but "10.0"!="10". Though Hypertalk's operators behaved even more interestingly.
  • Travis J
    Travis J over 3 years
    @supercat - Yessir. Around this time I had been researching the origins of Internet Explorer (which dates back to Mosaic), trying to figure out why IE10 was such a security issue and had sent part of that research on to Jonathan Sampson. Perhaps by coincidence they went on the develop Edge soon after, with many of the suggested security issues removed. This post is actually slightly dated though, because the recent iteration on EcmaScript and the inclusion of microtasks, have created a slightly more involved model with regards to memory management behind the scenes in certain scenarios.
  • Travis J
    Travis J over 3 years
    @supercat - For some still available references to that, "I started looking at languages like Logo and Smalltalk and Self and HyperTalk which was Bill Atkinson’s language for HyperCard" -Brendan Eich, "JavaScript (whose creator, Brendan Eich, was inspired by HyperTalk[32])" -Wiki citing his book. Here is the email I wrote to Jonathan at microsoft: jsfiddle.net/fwchpvrj
  • supercat
    supercat over 3 years
    There may have been some conceptual inspiration, but having worked with both Hypertalk and Javascript, I don't see any design commonality between them. The ability of Hypercard stacks to directly affect the containing system was a result of the fact that upon encountering an unfamiliar command or function, Hypercard would search for a resource with type XCMD or (if memory serves) XFCN whose name matched that of the unfamiliar command or function, and--if one was found--load it into memory as a code resource and call it. By design, any resources that were within the...
  • supercat
    supercat over 3 years
    ...current document would be found by such a search. This made it possible for Hypercard stacks to do things that would not otherwise be possible in the language, but meant that stacks were not sandboxed in any meaningful way. By contrast, web browsers were supposed to provide a sandboxed environment for processing removely-received content; the failure to adequately sandbox was due to bugs, while the fact that Hypercard's didn't sandbox things was a result of a design decision not to restrict the range of tasks stacks could perform.
  • Travis J
    Travis J over 3 years
    @supercat - It is there. The more you look, the more you will find. Here is a direct reference from Eich himself on one of the many overlaps, "I imitated HyperCard event names, e.g. click (Used with the on keyword: on click ... in HyperTalk):" Brendan Eich
  • supercat
    supercat over 3 years
    The HyperTalk event handler for mouse clicks was "On mouseUp", which would only be fired on a button if the mouse had been clicked on the button and released on the same button, without an intervening release elsewhere. Mr. Eich may have been trying to imitate what he thought he remembered about HyperTalk, but a search through a non-ftp copy of "Hypertalk Beginner's Guide" finds no reference to "on click" nor "onClick".
  • supercat
    supercat over 3 years
    A more important difference between function and block scopes arises with closures. If a block contains both a let and a function that uses the variable created thereby, each time the block is executed will yield a different function with its own variable; using var would result in all of the functions using the same variable. Interestingly, at least in node.js, function definitions appear to use let semantics rather than var semantics; I'm not sure if that was always the case.
  • supercat
    supercat over 3 years
    I don't wish to contradict you, but Brendan Eich isn't describing how Hypercard/Hypertalk actually works. Have you ever used them? A major design difference between Hypertalk and Javascript is that each control in Hypertalk has its own "script" property, which may be edited separately. If a control's script contains an "on mouseUp" handler, that will fire when the control is clicked. If Hypertalk allowed reassignment of event handlers by setting individual properties, or allowed closures, I think my programming languages class would have used that language as an example of such things.
  • Travis J
    Travis J over 3 years
    @supercat - I will refrain from engaging in the rude tone you strike and so seek to elicit. The fact that JavaScript was inspired by HyperTalk is well documented by Eich himself. In writing the Foreward for the JavaScript Bible by Danny Goodman (a book sitting on the shelf next to me), Eich repeatedly mentions the influence that HyperCard and HyperTalk had during the creation of JavaScript.
  • Travis J
    Travis J over 3 years
    "Danny didn't know at the time how much inspiration I found in his HyperCard Book, but it was on my desk throughout the development of JavaScript in 1995"; "Although the natural language syntax of HyperTalk was fresh in my mind, the Next Big Thing weighed heavier, especially in light of another goal: scripting Java applets"; "Although not initially as flexible as HyperCard's messages (whose handlers inspired the onEvent naming convention), JavaScript events let HTML authors take control of user interactions from remove servers and respond quickly to user gestures and browser actions".
  • supercat
    supercat over 3 years
    I wasn't trying to be rude, but merely try to ascertain what concrete design aspects of Javascript, if any, are inherited from Hypertalk, since almost nothing I remembered about Hypertalk bore any relationship to anything in Javascript. Many things that were wacky in Hypertalk are also wacky in Javascript, but in different ways. For example, in Hypertalk, a comparison between two values will behave as a numeric comparison if both values can be parsed as numbers, or as a string comparison otherwise; in Javascript, a comparison between a string and a number will always behave as though...
  • supercat
    supercat over 3 years
    ...the string is converted to a number, even if the result of that comparison would be "NaN". Eich may have taken substantial conceptual inspiration from Hypertalk, but I can't identify any particular aspects of the design of Javascript which are borrowed from Hypertalk. In Hypertalk, undeclared identifiers within a script default to local; in Javascript they default to global. Based upon the sources you provided, it seems the "inspiration" was conceptual only.
  • Travis J
    Travis J over 3 years
    @supercat - Eich himself states that he used HyperCard and HyperTalk for ideas, and some of those ideas such as event handlers, scoping (inspired by container stacks which is the reference in this answer, whereby there is a global "background card" and a stack of containers on top of that.... as explained in the answer), a lack of classes, implicit type coercion, and so much more, are present in JavaScript. That they aren't exactly implemented is no surprise, he created Mocha in 10 days.
  • supercat
    supercat over 3 years
    In a way, the time schedule makes the lack of resemblance between Javascript and Hypercard more surprising. Hypertalk uses a fixed topology where every stack has a flat list of cards, each of which has precisely two layers, each of which has a flat list of buttons and fields, each of which has a code blob which may statically define events, and I would have expected that someone trying to hastily throw together a language to control the launching of Java applets would have used a similar fixed topology rather than making everything dynamic. Not that I'm faulting the decision...
  • supercat
    supercat over 3 years
    ...to make things dynamic. Quite the opposite, in fact. But the design of Javascript neither seems to imitate Hypertalk's design decisions, nor use the unfortunate aspects of Hypertalk's design as examples of what not to do. I'm not sure how different JS would be if Eich hadn't looked at Hypercard.
  • Sebastian Simon
    Sebastian Simon about 2 years
    This answer was already outdated when it was posted and didn’t add anything new to the existing answers.
  • Sebastian Simon
    Sebastian Simon about 2 years
    @iAmOren Of course they are part of the question, and yes, they do belong in JavaScript. The thing that should be abolished, if anything, is var, but this is neither feasible nor relevant here.