Categories
Object-Oriented JavaScript

Object-Oriented JavaScript — Async Programming

JavaScript is partly an object-oriented language.

To learn JavaScript, we got to learn the object-oriented parts of JavaScript.

In this article, we’ll look at JavaScript async programming.

Async Programming

Async programming is an import part of JavaScript apps.

It’s different from the alternative mode, which is synchronous programming.

Synchronous programming is where we run code line by line.

And async programming is where we run some code, then wait for the result.

While we wait for the result, we let other pieces of code in the queue run.

Then once the result is obtained, then we run the code that’s waiting for the result.

This is different in that we aren’t running anything line by line.

We queued up the code and initialize them.

Then once the result is computed, we go back to run the code that’s initialized.

When the code is waiting, the latency isn’t predictable.

So we can’t just run code and then wait for the result without letting other pieces of code run.

JavaScript Call Stack

The call stack is a record of the functions that are called from latest to earliest.

For instance, if we have:

function c(val) {
  console.log(new Error().stack);
}

function b(val) {
  c(val);
}

function a(val) {
  b(val);
}
a(1);

Then we get:

Error
    at c ((index):37)
    at b ((index):41)
    at a ((index):45)
    at (index):47

from the console log.

We see that a is called first, then b , then c .

When c returns, the top of the stack is popped out.

And then b is popped out when it returns.

And finally a is popped.

Event Loop

A browser tab runs in a single thread.

It runs in the event loop.

The loop continuously picks messages from the message queue and runs callbacks associated with them.

The event loop keeps picking tasks from the message queues when other processes add tasks to the message queue.

Processes like timers and event handlers run in parallel and add tasks to the queue.

Timers

The setTimeout function creates a timer and wait until it fires.

When the timer is run, a task is added to the message queue.

It takes a callback and the duration in milliseconds.

Once the duration is reached, then the callback is run.

When the callback is run, then other interactions in the browser is blocked.

Callbacks

Node popularized its own style of callback.

The callback takes an err and data parameter.

err has the error object.

data has the result data.

For instance, we have:

fs.readFile('/foo.txt', (err, data) => {
  if (err) throw err;
  console.log(data);
});

which has a callback with err and data .

The fs.readFile reads a file asynchronously and gets the content.

Conclusion

JavaScript needs lots of async code because it only runs on one thread.

It needs to queue tasks and then run asynchronously.

This way, it won’t hold up the main thread.

Categories
Object-Oriented JavaScript

Object-Oriented JavaScript — Variables Best Practices

JavaScript is partly an object-oriented language.

To learn JavaScript, we got to learn the object-oriented parts of JavaScript.

In this article, we’ll look at the scope of variables.

Scope of Variables

JavaScript has block-scoped variables since ES6.

As long as we declare variables with let or const , they’ll be block-scoped.

We can write:

function foo() {
  let local = 2;
}

to create a block-scoped variable local .

This is only available within the block.

We can also cvrearte global variables.

For instance, we can write:

var x = 1;

at the top level to create a global variable.

It’s hoisted, which means that the declaration of it can be accessed from anywhere within the script.

But the value is only available after it’s assigned.

var used at the top level will be global.

We should avoid creating global variables to avoid naming collisions.

Block-scoped variables are easier to track since they’re only available within the block.

Variable Hoisting

Variable hoisting is done only with var variables.

For instance, we can write:

var a = 123;

Then if we use it as follows:

var a = 123;

function foo() {
  console.log(a);
  var a = 1;
  console.log(a);
}
foo();

then we get that the first log of a is undefined .

And the 2nd console log is 1.

This is because the console log takes the a from within the function.

var is function scoped, it the value will be taken from a function.

Therefore, we get undefined and 1 respectively.

Block Scope

Because function scoping is confusing, ES6 introduced block-scoped variables.

We can use let and const to declare variables.

They aren’t hoisted and const variables have to have an initial value assigned to it when it’s declared.

For instance, we can write:

var a = 2; {
  let a = 3;
  console.log(a);
}
console.log(a);

The a in the console log would be 3.

And the console log outside the block would log 2 from the var declaration.

Because it’s easier to reason with block-scoped variables, we should use them everywhere.

The rule for creating variables is that we consider const first we can’t assign them to a new value.

If we need to assign a new value to a variable, then we use let .

And we never use var .

Functions are Data

Functions can be assigned to variables.

For instance, we can write:

const foo = function() {
  return 1;
};

Then we assigned a function to the foo variable.

This is called a function expression.

And if we write:

const foo = function bar() {
  return 1;
};

then we assigned a function declaration to a variable.

They’re the same, except that we can access the original name within the function.

So we can get the name bar from within the bar function’s body.

But we call it with foo outside it.

Using the typeof operator, we return the type 'function' as the value.

If we have:

typeof foo

We get 'function' .

Conclusion

We should use let or const to declare variables.

Also, functions can be assigned to variables.

Categories
Object-Oriented JavaScript

Object-Oriented JavaScript — String and Math

JavaScript is partly an object-oriented language.

To learn JavaScript, we got to learn the object-oriented parts of JavaScript.

In this article, we’ll look at the String and Math objects.

String Object Methods

Strings have various methods we can call to do stuff with.

The toUpperCase method lets us return the upper case version of the string.

For instance, if we have:

const s = 'foo';

Then:

s.toUpperCase();

returns 'FOO' .

The toLowerCase method converts a string to all lower case.

For example:

s.toLowerCase()

returns 'foo' .

The charAt method returns the character found at the position we specify.

For instance, if we have:

s.charAt(0);

then we get 'f' .

We can just write s[0] for short.

If we pass in a non-existent position to charAt , we get an empty string.

The indexOf method lets us search for a substring within a string.

For instance, if we have:

s.indexOf('o');

we get 1.

Also, we can optionally specify the position to start the search with indexOf .

For instance, we can write:

s.indexOf('o', 2);

and we get 2.

The lastIndexOf method starts the search from the end of the string.

For instance, if we write:

s.lastIndexOf('o');

we get 2.

We can also search for a series of characters.

For example, if we have:

const str = 'foobar';
str.indexOf('bar');

we get 3.

They can be combined together.

So we can write:

s.toLowerCase().indexOf('foo'.toLowerCase());

The slice() and substring() methods return a piece of the string when we specify the start and end position.

If we have:

const str = 'foobar';
str.slice(1, 3);
str.substring(1, 3);

and we get 'oo' .

The split method lets us split a string by a separator.

For instance, we can write:

const s = 'foo bar';
const arr = s.split(" ");

console.log(arr);

Then arr is [“foo”, “bar”] since we split by a space.

The join method joins an array of strings into one with a separator between them.

So if we have:

["foo", "bar"].join(' ')

We get:

"foo bar"

The concatr method appends a string into an existing string.

So if we have:

'foo'.concat("bar")

We get:

"foobar"

Math

The Math object isn’t a function.

It’s an object that has various constants and methods.

Constants that it includes are:

  • Math.PI — pi
  • Math.SQRT2 — the square root of 2
  • Math.E — Euler’s constant
  • Math.LN2 — natural log of 2
  • Math.LN10 — nature log of 10

We can generate a random number of between 0 and 1 with Math.random() .

We can use the expression:

((max - min) * Math.random()) + min

to generate a random number between min and max .

Math has various methods to round numbers.

floor() rounds down.

ceil() rounds up.

And round() rounds to the nearest integer.

We can use them by passing in a number:

Math.floor(9.1)
Math.ceil(9.1)
Math.`round`(9.1)

Math.pow raises a base to an exponent.

For instance, kf we have:

Math.pow(2, 3);

then we get 8. 2 is the base and 3 is the exponent.

The Math.sqrt method returns the square root of a number.

For instance, we can write:

Math.sqrt(9);

and we get 3.

Conclusion

Strings have various methods to let us manipulate them.

The Math object lets us do various operations and provides us with some constants.

Categories
Object-Oriented JavaScript

Object-Oriented JavaScript — RegExp

JavaScript is partly an object-oriented language.

To learn JavaScript, we got to learn the object-oriented parts of JavaScript.

In this article, we’ll look at the RegExp object.

RegExp

The RegExp constructor lets us search and manipulate text.

JavaScript uses the Perl 5 syntax for defining regex.

A regex consists of a pattern to use and match the text.

It can optionally contain zero or more modifiers to provide more instructions on how the pattern should be used.

For instance, we can use the RegExp constructor by writing:

const re = new RegExp("c.*t");

We have a regex that matches a word with some letters in between c and t .

. means any character.

* means preceding whatever comes after.

We can add some modifiers called flags to change the regex.

Some flags include:

  • g for global.
  • i for ignoring case
  • m for multiline

So if we have:

const re = new RegExp("c.*t", 'gmi');

We can check that it does global match with the global property.

So re.global should return true .

The property can’t be set, so assigning a value to it won’t change the value.

RegExp Methods

RegExp instances have some methods.

They include the test and exec method.

test checks whether a string matches the regex pattern.

And exec returns the string the matches the regex.

We can call test by running;

/c.*t/.test("CoffeeScript");

then we get false .

But we call:

/c.*t/i.test("CoffeeScript");

then we get true because of the case-insensitive match.

To call exec , we can write:

/c.*t/i.exec("CoffeesScript")[0];

Then we get:

"CoffeesScript"

String Methods that Accept Regex as Arguments

Some string methods accept regex as arguments.

They include:

  • match — returns an array of matches
  • search — returns the position of the first search
  • replace — substitute matched text with another string
  • split — accepts a regex when splitting string into an array of elements

We can pass in a regex to search and match .

For instance, we can write:

'JavaScript'.match(/a/);

then we get ['a'] .

If we have”

'JavaScript'.match(/a/g);

Then we get:

["a", "a"]

If we write:

'JavaScript'.match(/J.*a/g);

then we get:

["Java"]

If we call search :

'JavaScript'.search(/J.*a/g);

then we get the position of the matched string, which is 0.

The replace method lets us replace the matched text with some other string.

For instance, we can remove all lowercase letters by writing:

'JavaScript'.replace(/[a-z]/g, '')

Then we get:

"JS"

We can also use the $& placeholder to let us add something to matches.

For instance, we can write:

'JavaScript'.replace(/[A-Z]/g, '-$&')

Then we get:

"-Java-Script"

replace can take a callback that lets us return the matches manipulated our way.

For instance, we can write:

'JavaScript'.replace(/[A-Z]/g, (match) => {
  return `-${match.toLowerCase()}`;
})

Then we get:

"-java-script"

We replaced the upper case characters with lower case and add a dash before it.

The first parameter of the callback is the match.

The last is the string being searched.

The one before last is the position of the match .

And the rest of the parameters have any strings matched by any group in our regex pattern.

The split method lets us split a string.

It takes a regex with the [pattern to split by.

For instance, we write:

const csv = 'one, two,three ,four'.split(/s*,s*/);

Then we get:

["one", "two", "three", "four"]

We split the string by the whitespace to get that.

Conclusion

The RegExp constructor lets us find patterns in a string and work with them.

Categories
Object-Oriented JavaScript

Object-Oriented JavaScript — Prototypes, Call, and Apply

JavaScript is partly an object-oriented language.

To learn JavaScript, we got to learn the object-oriented parts of JavaScript.

In this article, we’ll look at prototypes, call , and apply .

Function Prototypes

Functions have a special prototype property that has items that are shared between all instances of the constructor function.

For instance, we can write:

function F() {}

F.prototype = {
  name: 'james',
  say() {
    return `I am ${this.nam}`;
  }
};

Then if we create 2 instances of F :

const foo = new F();
const bar = new F();
console.log(foo, bar);

We see that both foo and bar have the same properties.

The say method also does the same thing.

Methods of Function Objects

Function objects have their own methods.

For instance, functions have the toString method to return the string with the code of the function.

So if we have:

function add(a, b, c) {
  return a + b + c;
}

console.log(add.toString());

We get:

"function add(a, b, c) {
  return a + b + c;
}"

logged.

Call and Apply

Functions have the call and apply method to let us run functions, set the value of this and pass arguments to it.

For instance, if we have:

const obj = {
  name: 'james',
  say(who) {
    return `${this.name} is ${who}`;
  }
};

Then we can call say with call by writing:

const a = obj.say.call({
  name: 'mary'
}, 'female');

Then a is 'mary is female’ .

We set this to:

{
  name: 'mary'
}

so this.name is 'mary' .

The 2nd argument is the argument for say , so who is 'female' .

We can also call apply by doing the same thing, except that the arguments of the function are in the array.

For instance, we can write:

const obj = {
  name: 'james',
  say(who) {
    return `${this.name} is ${who}`;
  }
};

const a = obj.say.apply({
  name: 'mary'
}, ['female']);

and we get the same thing.

Lexical this in Arrow Functions

this is a dynamic object that changes according to its context.

Arrow functions don’t bind to its own value of this .

So if we have:

const obj = {
  prefix: "Hello",
  greet(names) {
    names.forEach(function(name) {
      console.log(`${this.prefix} ${name}`);
    })
  }
}

We’ll get an error with the greet method since this is the callback function, so it doesn’t have the prefix property.

But if we use an arrow function:

const obj = {
  prefix: "Hello",
  greet(names) {
    names.forEach((name) => {
      console.log(`${this.prefix} ${name}`);
    })
  }
}

Then the function works properly since it doesn’t bind to its own value of this .

Inferring Object Types

The toString method of Object.prototype gives us the class name that’s used to create an object.

For instance, we can write:

Object.prototype.toString.call({});

And get:

"[object Object]"

And if we write:

Object.prototype.toString.call([]);

We get:

"[object Array]"

We can use call with the toString method by writing:

Array.prototype.toString.call([1, 2, 3]);

We get:

"1,2,3"

This is the same as:

[1, 2, 3].toString()

Conclusion

The call and apply methods let us call functions with different values of this and arguments.

Also, the prototype has properties that are shared between all constructor instances.