chapter2 JAVASCRIPT: AN OVERVIEW

 

INTRODUCTION

JAVASCRIPT IS A prototype-based, object-oriented, loosely-typed dynamic scripting anguage. It has powerful features from the functional world, such as closures and higher-order functions, that are of special interest here.

JavaScript is technically an implementation of the ECMAScript language standard. It’s important to know that with Node, because of v8, you’ll be primarily dealing with an implementation that gets close to the standard, with the exception of a few extra features. This means that the JavaScript you’re going to be dealing with has some important diferences with the one that earned the language its bad reputation in the browser world.

In addition, most of the code you’ll write is in compliance with the “good parts” of JavaScript that Douglas Crockford enounced in his famous book, JavaScript: The Good Parts.

This chapter is divided into two parts:

1.  Basic JavaScript. The fundamentals of the language. They apply everywhere: node, browser, and standards committee.

2.  v8 JavaScript. Some features used in v8 are not available in all browsers, especially Internet Explorer, because they’ve recently been standardized. Others are nonstandard, but you still use them because they solve fundamental problems.

In addition, the next chapter covers the language extensions and features exclusively available in Node.

BASIC JAVASCRIPT

This chapter assumes that you’re somewhat familiar with JavaScript and its syntax. It goes over some fundamental concepts you must understand if you want to work with Node.js.

TYPES

You can divide JavaScript types into two groups: primitive and complex. When one of the primitive types is accessed, you work directly on its value. When a complex type is accessed,you work on a reference to the value.

1.  The primitive types are number, boolean, string, null, and undefined.

2.  The complex types are array, function, and object.

To illustrate:

//primitives
var a = 5;
var b = a;
b = 6;
a; // will be 5
b; // will be 6
// complex
var a = ['hello', 'world'];
var b = a;
b[0] = 'bye';
a[0]; // will be ’bye’
b[0]; // will be ‘bye’

 In the second example, b contains the same reference to the value as a does. Hence, when you access the frst member of the array, you alter the original, so a[0] === b[0].

TYPE HICCUPS

Correctly identifying the type of value a certain variable holds remains a challenge in JavaScript.

Because JavaScript has constructors for most primitives like in other languages with object-oriented features, you can create a string in these two ways:

var a = 'woot';
var b = new String('woot');
a + b; // ‘woot woot’

 If you use the typeof and instanceof operators on these two variables, however, things get interesting:

typeof a; // ‘string’
typeof b; // ‘object’
a instanceof String; // false
b instanceof String; // true

 However, both are defnitely strings that have the same prototypical methods:

a.substr == b.substr; // true

 And they evaluate in the same way with the == operator but not with ===:

a == b; // true
a === b; // false

 Considering these discrepancies, I encourage you to always defne your types in the literal way, avoiding new.

It’s important to remember that certain values will be evaluate to false in conditional expressions: null, undefined, ‘’, 0:

var a = 0;
if (a) {
  // this will never execute
}
a == false; // true
a === false; // false

 Also noteworthy is the fact that typeof doesn’t recognize null as its own type:

typeof null == 'object'; // true, unfortunately

 And the same goes for arrays, even if defned with [], as shown here:

typeof [] == 'object'; // true

 You can be thankful that v8 provides a way of identifying an array without resorting to hacks.In browsers, you typically inspect the internal [[Class]] value of an object: Object.prototype.toString.call([]) == ‘[object Array]’. This is an immutable property of objects that has the beneft of working across diferent contexts (for example, browser frames), whereas instanceof Array is true only for arrays initialized within that particular context.

FUNCTIONS

Functions are of utmost importance in JavaScript.

They’re first class: they can be stored in variables as references, and then you can pass them around as if they were any other object:

var a = function () {}
console.log(a); // passing the function as a parameter

 All functions in JavaScript can be named. It’s important to distinguish between the function name and the variable name:

var a = function a () {
  'function' == typeof a; // true
};

 THIS, FUNCTION#CALL, AND FUNCTION#APPLY

When the following function is called, the value of this is the global object. In the browser, that’s  window:

 

function a () {
  window == this; // true;
};
a();
 

 

By using the .call and .apply methods, you can change the reference of this to a diferent object when calling the function:

 

function a () {
  this.a == ‘b’; // true
}
a.call({ a: ‘b’ });
 

 

The diference between call and apply is that call takes a list of parameters to pass to the function following, whereas apply takes an array:

 

function a (b, c) {
  b == ‘first’; // true
  c == ‘second’; // true
}
a.call({ a: ‘b’ }, ‘first’, ‘second’)
a.apply({ a: ‘b’ }, [‘first’, ‘second’]);
 FUNCTION ARITY

 

An interesting property of a function is its arity, which refers to the number of arguments that the function was declared with. In JavaScript, this equates to the length property of a function:

 

var a = function (a, b, c);
a.length == 3; // true
 

 

Even though less common in the browser, this feature is important to us because it’s leveraged by some popular Node.JS frameworks to offer diferent functionality depending on the number of parameters the functions you pass around take.

CLOSURES

In JavaScript, every time a function is called, a new scope is defned.

Variables defned within a scope are accessible only to that scope and inner scopes (that is, scopes defned within that scope):

 

var a = 5;
function woot () {
  a == 5; // false
  var a = 6;
  function test () {
    a == 6; // true
  }
  test();
};
woot();
 

 

Self-invoked functions are a mechanism by which you declare and call an anonymous function where your only goal is defning a new scope:

 

var a = 3;
(function () {
  var a = 5;
})();
a == 3 // true;
 

 

Tese functions are very useful when you want to declare private variables that shouldn’t be exposed to another piece of code.

CLASSES

In JavaScript, there’s no class keyword. A class is defned like a function instead:

 

function Animal () { }
 

 

To defne a method on all the instances of Animal that you create, you set it on the prototype:

Animal.prototype.eat = function (food) {

  // eat method

}

It’s worth mentioning that within functions in the prototype, this doesn’t refer to the global object like regular functions, but to the class instance instead:

 

function Animal (name) {
  this.name = name;
}
Animal.prototype.getName () {
  return this.name;
};
var animal = new Animal(‘tobi’);
a.getName() == ‘tobi’; // true
 INHERITANCE

 

JavaScript has prototypical inheritance. Traditionally, you simulate classical inheritance as follows.

You define another constructor that’s going to inherit from Animal:

 

function Ferret () { };
 

 

To defne the inheritance chain, you initialize an Animal object and assign it to the Ferret.prototype.

 

// you inherit
Ferret.prototype = new Animal();
 

 

You can then define methods and properties exclusive to your subclass:

 

// you specialize the type property for all ferrets
Ferret.prototype.type = ‘domestic’;
To override methods and call the parent, you reference the prototype:

 

 

Ferret.prototype.eat = function (food) {
  Animal.prototype.eat.call(this, food);
  // ferret-specific logic here
}
 

 

This technique is almost perfect. It’s the best performing across the board (compared to the alternative functional technique) and doesn’t break the instanceof operator:

 

var animal = new Animal();
animal instanceof Animal // true
animal instanceof Ferret // false
var ferret = new Ferret();
ferret instanceof Animal // true
ferret instanceof Ferret // true
 

 

Its major drawback is that an object is initialized when the inheritance is declared (Ferret.prototype = new Animal), which might be undesirable. A way around this problem is to include a conditional statement in the constructor:

function Animal (a) {
  if (false !== a) return;
  // do constructor stuff
}
Ferret.prototype = new Animal(false)

 

Another workaround is to define a new, empty constructor and override its prototype:

function Animal () {
  // constructor stuff
}
function f () {};
f.prototype = Animal.prototype;
Ferret.prototype = new f;

 

Fortunately, v8 has a cleaner solution for this, which is described later in this chapter.

TRY {} CATCH {}

try/catch allows you to capture an exception. The following code throws one:

> var a = 5;
> a()
TypeError: Property ‘a’ of object #<Object> is not a function

When a function throws an error, execution stops:

function () {
  throw new Error(‘hi’);
  console.log(‘hi’); // this will never execute
}

 

If you use try/catch, you can handle the error and execution continues:

function () {
  var a = 5;
  try {
    a();
  } catch (e) {
    e instanceof Error; // true
  }
  console.log(‘you got here!’);
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值