The Strange World of Directory Scope

存储架构 2016-06-04

04 June 2016

Most languages today use lexical scope
. A few older languages use dynamic scope
. Imagine my surprise this week, when debugging a Handlebars
template, finding a totally new approach to scope!

What if we required programmers to access scopes explicitly? Sound crazy? In Handlebars, this is a reality!

Handlebars does not let you access variables in outer scopes
. Suppose we have the following context:

var context = {user: "Alice",
               friends: ["Bob", "Charlie", "Diane"]};

We can access user
in the top-level scope:

This user is {{user}}.

renders as:

This user is Alice.

However, we cannot access user
from #each
blocks:

{{#each friends}}
{{user}} is friends with {{this}}.
{{/each}}

renders as:

is friends with Bob.
is friends with Charlie.
is friends with Diane.

Handlebars provides filesystem style syntax
to access the parent scope:

{{#each friends}}
{{../user}} is friends with {{this}}.
{{/each}}

renders as:

Alice is friends with Bob.
Alice is friends with Charlie.
Alice is friends with Diane.

Wow! I’d believed there was nothing beyond dynamic and lexical scoping. I’m not aware of a name for this style of scope, so I’m going to call it ‘directory scope’ for the sake of this post.

Directory scope does have its downsides. It makes refactoring more difficult, because templates are very sensitive to context. If you introduce a new block, or move code around, you may need to change how you access your variables.

It has a number of benefits too though. You never need to worry about shadowing variables. You can still access variables in outer scopes, even if they have the same name! No namespacing required.

If you’re not worried about shadowing, then writing new control structures, lisp-style, is easy. A lisp macro author would worry about hygiene in blocks, because they could end up shadowing user-defined variables.

A Handlebars block author can inject variables with gay abandon. Suppose we defined a #with-user
block. This could inject a user
variable without breaking any of our code examples above.

The syntax choice is also clever. You can probably guess what ./foo
means (access the variable in the current scope) and what ../../foo
means (access the variable in the grandparent scope).

This illustrates the value of regularly learning new languages. Starting from a bug — why isn’t my variable in scope? — I ended up a exploring a radically different approach to scoping with a fresh set of tradeoffs.

您可能感兴趣的

JavaScript spec gets strung out on padding ECMAScript 2017 , the latest edition of the specification upon which JavaScript is based, plugs a gap left by awkward extinction of some Node.js ...
Where can I put image files, css&com... Where is it acceptable to put css folders and image file folders? I was thinking inside the view folder? However the controller always reroutes the pa...
数组中头尾元素的插入与删除 JS中的方法: 一、向数组头部插入元素的方法 1.unshift() unshift()向数组的开头添加一个或多个元素,原数组被改变并返回数组的长度。 2.Splice() 删除元素并向数组添加新元素,会改变原数组。 语法:arrayObject.splice(index,...
JavaScript Performance Optimization Tips: An Overv... In this post, there’s lots of stuff to cover across a wide and wildly changing landscape. It’s also a topic that covers everyone’s favorite: The JS Fr...
The Cost of Adtech As a result of the GDPR going into effect, USA Today is—presumably temporarily—running a special version of their site for those in the European Un...