In a previous post we looked at template literals.
You might have glanced at the code in that post and thought: “gee, that’s useful”. Or, perhaps you are more the skeptical, security conscious type who thought “gee, new and easy ways to create injection vulnerabilities”.
Regardless of your initial take, an even more powerful feature in ES6 is the tagged template literal.
The tag is a function with the ability to interpret and process a template. The tag appears in front of the template, so in the following code the tag is upper.
var result = upper `${x} + ${y} is ${x+y}`;
The runtime will invoke the tag function and pass as a first argument an array containing the individual pieces of literal text from the template.
let test = function(literals, ...values) { expect(literals.length).toBe(2); expect(literals[0]).toBe("Hello, "); expect(literals[1]).toBe("!"); return "test"; }; let name = "Scott"; let result = test `Hello, ${name}!`; expect(result).toBe("test");
The template in the above code, `Hello, ${name}!`, generates an array of two values. The values contain only the literal text and no placeholders. The runtime will pass the evaluated expressions from any placeholders as individual arguments after the first array argument. It will be a common practice to capture the values using a rest parameter. Here is another code snippet showing all of the literals and values passed to the tag function.
let test = function(literals, ...values) { expect(literals.length).toBe(3); expect(literals[0]).toBe("Hello, "); expect(literals[1]).toBe(", "); expect(literals[2]).toBe("!"); expect(values.length).toBe(2); expect(values[0]).toBe("Allen"); expect(values[1]).toBe("Scott"); return "test"; }; let firstName = "Scott"; let lastName = "Allen"; let result = test `Hello, ${lastName}, ${firstName}!`; expect(result).toBe("test");
The general idea is that a tag function can build the result of a tagged template by concatenating strings. For each literal value, append the literal to the result and then append a value. However, a tag can interpret a template using any logic it desires, so if the tag simply wants to heedlessly return the string “test” regardless of the contents of the template, it can (as the code above is doing).
A more reasonable implementation of a tag might look like the following.
let upper = function(strings, ...values){ let result = ""; for(let i = 0; i < strings.length; i++){ result += strings[i]; if(i < values.length){ result += values[i]; } } return result.toUpperCase(); }; var x = 1; var y = 3; var result = upper `${x} + ${y} is ${x+y}`; expect(result).toBe("1 + 3 IS 4");
The tag upper builds a result that would look just like the normal evaluation of the template literal, but uses toUpperCase before returning the result to ensure the result uses all uppercase letters.
A tag’s ability to modify the output of a template is powerful. Imagine a tag that can build safe URLs by URL encoding a result, or a safehtml tag to build encoded HTML. Since JavaScript is often used to generate content (HTML, JSON, URLs, form encoded inputs, etc), a tag library that makes content generation safe and easy will be invaluable.
Even more interesting is the idea that the content inside of a template could be a language unto itself. The tag function could be the gateway to the interpreter for a domain specific language, which opens up many possibilities for the use (and abuse) of tagged template literals.
Want more? Watch JavaScript Fundamentals for ES6 on Pluralsight!
Template literals provide JavaScript with some basic string formatting capabilities. Just like many template technologies, template literals in JavaScript consist of literal text, and placeholders where the runtime can evaluate an expression to poke data into the text.
let name = "Scott"; let message = `Hello, ${name}!`; expect(message).toBe("Hello, Scott!");
Backtick characters (`) enclose the entire template literal, while $ and {} denote the substitutions. Inside a substitution, you can use identifiers and expressions.
let showTheMath = function(x,y ){ return `${x} + ${y} is ${x + y}`; }; let result = showTheMath(3,4); expect(result).toBe("3 + 4 is 7");
Template literals can even span multiple lines.
let message = `This is a short, but multi-line message`;
Note that message will contain a newline character because newlines (and trailing spaces) are significant inside of a template literal.
Template literals are a useful addition to the language. However, template literals become exceptionally interesting when using them with a tag. We’ll look at tagged template literals next week.
Want more? Watch JavaScript Fundamentals for ES6 on Pluralsight!
One of the reasons for Angular’s success is the flexibility in the building blocks the framework provides. There is a delicate balance between productivity and flexibility. A heavily opinionated framework can be make a team highly productive, but the opinions can also make it harder to mix in additional features that conflict with the opinions, or sit outside the vision for the framework. Angular strikes a nice balance.
When I first thought about mixing PhysicsJS into an AngularJS application, I couldn’t see how a library based on timer ticks, frame rates, and a canvas could work with a framework like Angular, with its digest cycle and directives.
But, after 30 minutes I discovered that not only could these two work together, but Angular was flexible enough to provide some nice enhancements to the PhysicsJS experience.
Go to PhysicsJS + AngularJS to see the following code in action. The code is based on the tutorial “Creating a scene of colliding polygons”.
The first order of business is wrapping PhysicsJS components with services. Physics is the primary export of PhysicsJS, and this object provides factory methods to create shapes and behaviors. We can inject Physics into other components of the application that need to create shapes, but we’ll also create some additional services that use Physics to setup the “game loop” ticker and the world that contains all the shapes and behaviors for a scene.
var app = angular.module("app", []); app.value("Physics", Physics); app.factory("world", function (Physics) { var world = Physics(); world.on("step", function () { world.render(); }); return world; }); app.factory("ticker", function (Physics, world) { var start = function () { Physics.util.ticker.on(function (time) { world.step(time); }); Physics.util.ticker.start() }; return { start: start }; });
Directives can transform a PhysicsJS scene from imperative code and into a declarative language. Here are a few simple directive definitions.
app.directive("physicsBehavior", function (Physics, world) { return { restrict: "E", scope: { name: "@" }, link: function (scope) { world.add(Physics.behavior(scope.name)); } }; }); app.directive("physicsBody", function (Physics, world) { return { restrict: "E", scope: { options: "=", body: "=", type: "@" }, link: function (scope) { scope.body = Physics.body(scope.type, scope.options); world.add(scope.body); } }; });
These types of directives will let us write markup like the following.
<physics-canvas width="500" height="500"> <physics-body type="rectangle" body="main.box1" options="{x:450, y:10, vy:-0.3, width:5, height:5}"> </physics-body> <physics-body type="rectangle" body="main.box2" options="{x:250, y:210, vy:-0.3, width:5, height:5}"> </physics-body> <physics-edge-detection min-x="0" min-y="0" max-x="500" max-y="500" restitution="0.3"> </physics-edge-detection> <physics-behavior name="constant-acceleration"></physics-behavior> <physics-behavior name="body-impulse-response"></physics-behavior> <physics-behavior name="body-collision-detection"></physics-behavior> <physics-behavior name="sweep-prune"></physics-behavior> </physics-canvas>
Controllers can build models that interact with objects in the PhysicsJS world. The API allows us to apply forces and change the geometry of objects. One difficulty I did have is seeing the updated appearance of a shape after changing attributes. The code needs to set the view property of a shape to null for changes to attributes like width and height to appear. PhysicsJS will recreate the view on the next tick.
model.kick = function () { model.box1.applyForce({x: 0.1, y: -0.2}); model.box2.applyForce({x: -0.1, y: -0.2}); }; model.grow = function () { model.box1.geometry.width *= 1.5; model.box1.geometry.height *= 1.5; model.box1.mass *= 1.5; model.box1.view = null; model.box1.recalc(); };
Anyone who has worked with jQuery widgets or native events knows that Angular needs to know when model data changes in order to update the DOM with new model values. Generally we accomplish this goal by wrapping code inside a scope’s $apply method.
The interesting thing about working with PhysicsJS is that the physics engine is constantly updating a canvas based on a timer, so it is not necessary for Angular to know about changes in shape properties, like position and acceleration. It just works.
Although there would be a lot more work needed to make a complete and general purpose wrapper for PhysicsJS, the integration with an Angular app works in a straightforward manner.
Update: this feature was dropped from C# 6.0.
In C# we’ve always had declaration statements for declaring variables, and expression statements to produce values.
In C# 6 we can mix a declarations with an expression to declare a new variable and produce a value.
The canonical example is the int.TryParse method, which requires an out parameter. In previous versions of C# the parameter would be declared in a distinct statement before the invocation of TryParse.
int result; if(int.TryParse(input, out result)) { return result; } return 0; // note: result still in scope
With C# 6.0, the same result is achievable with a declaration expression. The declaration statement also limits the scope of the variable passed as an out parameter.
if (int.TryParse(input, out var result)) { return result; } return 0; // result is out of scope
We could also transform the above code into a one-liner. . .
return int.TryParse(input, out var result) ? result : 0;
. . . and then package it into an extension method for string.
public static int ParseIntSafe(this string input, int @default = 0) { return int.TryParse(input, out var result) ? result : @default; }
With declaration expressions we can also declare variables inside if statements . . .
if ((var address = user.HomeAddress) != null) { // work with address ... return address.City; }
. . . and the various looping statements.
int result = 0; foreach (var n in var odd = numbers.Where(n => n % 2 == 1).ToList()) { result += n + odd.Count(); } return result;
Declaration are a small addition to the C# language, but will come in useful in a few scenarios.
To destructure an object is to dismantle or tear apart an object.
In ES6, a destructuring assignment allows us to tear apart an array or object into individual pieces that we can assign to variables. The square brackets [ and ] are used to destructure an array, while { and } will destructure an object.
The following code will destructure an array so that x contains 22 and y contains 44.
let values = [22, 44]; let [x, y] = values; expect(x).toBe(22); expect(y).toBe(44);
You can think of [ and ] in the first line of code as the symbols used to construct an array. The [ and ] on the second line of code tear apart the array and declare two variables to hold the pieces.
Destructuring objects follows the same pattern, but will use { and }.
var person = { firstName: "Scott", lastName: "Allen" }; var {firstName, lastName} = person; expect(firstName).toBe("Scott"); expect(lastName).toBe("Allen");
You do not need to use let or var with destructuring to create new variables, you can also destructure into existing variables.
let x = 10, y = 20; // swap!! [x,y] = [y,x]; expect(x).toBe(20); expect(y).toBe(10);
You can also destructure arrays and objects returned from a function call.
var doWork = function() { return [1, 3, 2]; }; let [, x, y, z] = doWork(); expect(x).toBe(3); expect(y).toBe(2); expect(z).toBeUndefined();
Note a couple special properties in the destructuring of doWork’s result. First, the opening comma will skip the first array element, and you can use additional commas anywhere to skip additional elements. Secondly, if there are not enough array elements to satisfy all the variables required by the destructuring, the extra variables will receive the value undefined.
You can also destructure in a function parameter list.
let doWork = function({firstName, lastName, role="developer"}) { return role + " " + firstName + " " + lastName; }; let person = {firstName: "Scott", lastName: "Allen"}; let result = doWork(person); expect(result).toBe("developer Scott Allen");
The above example also uses a default parameter value to assign “developer” to the role parameter in case the incoming object does not have a role property (otherwise, role would receive the value undefined). Default parameters are not restricted to function declarations when using destructuring.
let address = { state:"Maryland" }; let { state="New York", country="USA"} = address; expect(state).toBe("Maryland"); expect(country).toBe("USA");
Rest parameters can also capture the remaining elements of an array.
let odds = [1,3,5,7,9]; let [first, second, ...rest] = odds; expect(first).toBe(1); expect(second).toBe(3); expect(rest).toEqual([5,7,9]);
Destructuring can also drill into complex objects, even objects with collections inside.
let employee = { firstName: "Scott", address: { state: "Maryland", country: "USA" }, favoriteNumbers: [45,55,32,13] }; let { firstName, address: {state}, favoriteNumbers: [,second]} = employee; expect(firstName).toBe("Scott"); expect(state).toBe("Maryland"); expect(second).toBe(55);
One area where destructuring will lead to more maintainable code is in the use of configuration objects, like the configuration objects you typically pass to HTTP communication methods like jQuery’s ajax method. Finding the available options and their defaults is often difficult when using such a method, and maintaining the options and defaults can be tricky as an author. With destructuring, configuration options and defaults become more explicit.
let httpPost = function( url, { cache = true, contentType = "application/json", timeout = 2500, headers = {}, // ... }) { // ... };
We’ll also see other uses for destructuring as we move through additional features of ES6, like modules.
Want more? Watch JavaScript Fundamentals for ES6 on Pluralsight!
AngularJS provides protection against cross-site scripting attacks by default. Let’s look at some examples.
Consider the following controller which maintains a collection of strings with HTML inside. Perhaps the strings arrived in the controller as the result of an HTTP call, or perhaps the controller built the strings dynamically. In either case, the controller wants the links to display as clickable navigation links in a browser.
app.controller("mainController", function() { var main = this; main.links = [ "<a href='http://google.com'>Google</a>", "<a href='https://odetocode.com'>OdeToCode</a>", "<a href='http://twitter.com'>Twitter</a>", ]; });
In the view, we’ll use a {{bind expression}} to display the links.
<section ng-controller="mainController as main"> <nav> <ul> <li ng-repeat="link in main.links">{{link}}</li> </ul> </nav> </section>
The links will appear as inert text (see the figure to the right), because interpolation with ngBind will produce encoded text.
Technically, this isn’t because of any special code inside of the ngBind directive, but because ngBind uses jqLite’s .text method, which ultimately sets the textContent property of the associated element.
Instead of using ngBind, the view can use ngBindHtml to render the links as real, clickable anchor tags.
<ul> <li ng-repeat="link in main.links" ng-bind-html="link"> </li> </ul>
However, making only this change in the view will result in an error.
Error: [$sce:unsafe] Attempting to use an unsafe value in a safe context.
Angular will only render “safe” HTML into the DOM. If you are looking for a quick fix to this error, just read the “Sanitized HTML” section below.
From a developer’s perspective, there are two general categories of “safe” HTML in Angular.
Let’s look at #2 first.
Synonyms for sanitize include “sterilize”, “disinfect”, “clean”, “cleanse”, and “purify”. All of these synonyms are capable words for describing the process of making HTML “safe” for display. Being “safe” means the HTML won’t carry script code into the DOM, because script code is dangerous if the script comes from the wrong place.
AngularJS includes a $sanitize service that will parse an HTML string into tokens and only allow safe and white-listed markup and attributes to survive, thus sterilizing a string so the markup contains no scripting expressions or dangerous attributes.
Angular will consider HTML processed by $sanitize as trusted.
The ngBindHtml directive will use the $sanitize service implicitly, however, the $sanitize service is not part of the core ng module, so an additional script needs to be added into the page.
<script src="angular.js"></script> <script src="angular-sanitize.js"></script> <script src="app.js"></script>
Then when registering the application module, the code must list ngSantize as a dependency.
var app = angular.module("app", ["ngSanitize"]);
With these changes in place, the app will now render proper links.
So what was sanitized?
One way to see how and when $sanitize works is to decorate the $sanitize service (which is a function object).
var app = angular.module("app", ["ngSanitize"]); app.config(function($provide){ $provide.decorator("$sanitize", function($delegate, $log){ return function(text, target){ var result = $delegate(text, target); $log.info("$sanitize input: " + text); $log.info("$sanitize output: " + result); return result; }; }); });
Now let’s use the following link collection inside the controller. Notice each link has some attribute present.
app.controller("mainController", function() { var main = this; main.links = [ "<a onmouseover='...' href='http://google.com'>Google</a>", "<a class='...' href='https://odetocode.com'>OdeToCode</a>", "<a ng-click='...' href='http://twitter.com'>Twitter</a>" ]; });
With the decorator, we can see exactly what goes into $sanitize, and what comes out. The mouseover attributes disappear, as does the ng-click directive.
$sanitize input: <a onmouseover='...' href='http://google.com'>Google</a> $sanitize output: <a href="http://google.com">Google</a> $sanitize input: <a class='...' href='https://odetocode.com'>OdeToCode</a> $sanitize output: <a class="..." href="https://odetocode.com">OdeToCode</a> $sanitize input: <a ng-click='...' href='http://twitter.com'>Twitter</a> $sanitize output: <a href="http://twitter.com">Twitter</a>
While $sanitize can provide trusted HTML for Angular to render, it does so by modifying the HTML. If we really want to render HTML without encoding and without sanitization, we have to turn to what I referred to as category #1 earlier – explicitly marking the HTML as “trusted”.
When you want Angular to render model data as HTML with no questions asked, the $sce service is what you’ll need. $sce is the Strict Contextual Escaping service – a fancy name for a service that can wrap an HTML string with an object that tells the rest of Angular the HTML is trusted to render anywhere.
In the following version of the controller, the code asks for the $sce service and uses the service to transform the array of links into an array of trusted HTML objects using $sce.trustAsHtml.
app.controller("mainController", function($sce) { var main = this; main.links = [ "<a onmouseover='alert(\"careful!\")' href='http://google.com'>Google</a>", "<a href='https://odetocode.com'>OdeToCode</a>", "<a href='http://twitter.com'>Twitter</a>" ]; for (var i = 0; i < main.links.length; i++) { main.links[i] = $sce.trustAsHtml(main.links[i]); } });
The only difference between this version of the controller code and the previous version is the for loop to mark the strings as trusted. When binding to each trusted link using ngBindHtml, the HTML will no longer go through the $sanitize service. This means the first link will now enter the DOM with an onmouseover attribute and carry along executable JavaScript code. Be careful!
Instead of using onmouseover or onclick attributes, let’s say we have some strings on our controller that want to follow the “Angular Way” and use ngClick or ngMouseover.
app.controller("mainController", function($sce, $log) { var main = this; main.links = [ "<a ng-click='main.go(\"google\")' href=''>Google</a>", "<a ng-click='main.go(\"otc\")' href=''>OdeToCode</a>", "<a ng-click='main.go(\"twitter\")' href=''>Twitter</a>" ]; for (var i = 0; i < main.links.length; i++) { main.links[i] = $sce.trustAsHtml(main.links[i]); } main.go = function(name){ $log.info("Goto: " + name); }; });
If these links pass through the $sanitize service, the sanitizer will remove ng-click and other attribute directives. Fortunately, the controller marks the HTML as trusted so they will render with ngClick. However, clicking will not work since Angular doesn’t compile the markup after it enters the DOM with ngBindHtml.
The solution is to use a custom directive in combination with $sce and trusted HTML.
app.directive("compileHtml", function($parse, $sce, $compile) { return { restrict: "A", link: function (scope, element, attributes) { var expression = $sce.parseAsHtml(attributes.compileHtml); var getResult = function () { return expression(scope); }; scope.$watch(getResult, function (newValue) { var linker = $compile(newValue); element.append(linker(scope)); }); } } });
Now the view looks like:
<ul> <li ng-repeat="link in main.links" compile-html="link"> </li> </ul>
The spread operator shares the same syntax we saw with rest parameters, a series of three dots (...). However, a rest parameter will collect individual parameters into an array when you use the dots in a function parameter definition, while the spread operator expands an array into individual parameters when using the dots in a function call.
let doWork = function(x, y, z) { return x + y + z; } var result = doWork(...[1, 2, 3]); expect(result).toBe(6);
In the above code, the spread operator will “spread” the array of three values across the parameters x, y, and z.
The spread operator can also expand an array to create individual elements in an array literal.
var a = [4, 5, 6]; var b = [1, 2, 3, ...a, 7, 8, 9]; expect(b).toEqual([1,2,3,4,5,6,7,8,9]);
Although the examples here are all using the spread operator with an array, the spread operator also works with any iterable object. We’ll look at iterable objects in a future post.
Before rest parameters and the spread operator came along, Function.apply and the implicit arguments variable were widely used to accept an unknown number of arguments to a function and pass the arguments along to another function, like in the example below.
var doWork = function(x, y, z){ return x + y + z; } var doSomething = function(){ return doWork.apply(null, arguments); } var result = doSomething(...[1,2,3,4,5]); expect(result).toBe(6);
The implementation of doSomething is cleaner and more obvious when using a rest parameter and the spread.
var doWork = function(x, y, z){ return x + y + z; } var doSomething = function(...args){ return doWork(...args); } var result = doSomething(...[1,2,3,4,5]); expect(result).toBe(6);
Notice that when using the spread (or apply), you can have more values in the array than the destination function requires. The spread will start from the beginning of the array to populate parameters, so in the above example, doWork will see the first three values in the array.
Want more? Watch JavaScript Fundamentals for ES6 on Pluralsight!