VDone Demo VDone Demo
Home
  • Articles

    • JavaScript
  • Study Notes

    • JavaScript Tutorial
    • Professional JavaScript
    • ES6 Tutorial
    • Vue
    • React
    • TypeScript: Build Axios from Scratch
    • Git
    • TypeScript
    • JS Design Patterns
  • HTML
  • CSS
  • Technical Docs
  • GitHub Tips
  • Node.js
  • Blog Setup
  • Learning
  • Interviews
  • Miscellaneous
  • Practical Tips
  • Friends
About
Bookmarks
  • Categories
  • Tags
  • Archives
GitHub (opens new window)

Nikolay Tuzov

Backend Developer
Home
  • Articles

    • JavaScript
  • Study Notes

    • JavaScript Tutorial
    • Professional JavaScript
    • ES6 Tutorial
    • Vue
    • React
    • TypeScript: Build Axios from Scratch
    • Git
    • TypeScript
    • JS Design Patterns
  • HTML
  • CSS
  • Technical Docs
  • GitHub Tips
  • Node.js
  • Blog Setup
  • Learning
  • Interviews
  • Miscellaneous
  • Practical Tips
  • Friends
About
Bookmarks
  • Categories
  • Tags
  • Archives
GitHub (opens new window)
  • Basics
    • 1. Key Concepts in JavaScript
      • What is Scope?
      • What is a Closure?
      • What is a Constructor?
      • What is an Instance Object?
      • What is this?
      • What is a Prototype?
      • What is the Prototype Chain?
      • What is constructor?
      • What is a Wrapper Object?
    • 2. Data Type Conversion
      • 2.1 Explicit (Manual) Conversion
      • Number()
      • String()
      • Boolean()
      • 2.2 Automatic Conversion
      • Automatic Conversion to Boolean
      • Automatic Conversion to String
      • All types concatenated with a string become strings
      • Automatic Conversion to Number
      • Except for addition with strings (which converts to string), most other operations automatically convert to numbers
    • 3. Error Handling Mechanism
      • 3.1 Error Instance Objects
      • 3.2 Native Error Types
      • SyntaxError (Syntax Error)
      • ReferenceError (Reference Error)
      • RangeError (Range Error)
      • TypeError (Type Error)
      • URIError (URI Error)
      • EvalError (Eval Error)
      • Summary (Manual Use by Developers)
      • 3.3 Custom Errors
      • 3.4 throw Statement (Interrupt Program and Throw Error)
      • 3.5 try...catch Structure (Catch Errors, Handle Them, No Interruption)
      • 3.6 finally Block (Always Executes After try...catch)
    • 4. The console Object
      • console.time() and console.timeEnd() (For Timing Operations)
    • Reference
  • Built-in Objects
  • Object-Oriented Programming
  • Asynchronous Operations
  • DOM
  • Events
  • Browser Model
  • 《JavaScript教程》笔记
xugaoyi
2020-01-12
Contents

Basics

Note: This chapter contains the author's personal study notes added on top of the original tutorial. Source: https://wangdoc.com/javascript/ (opens new window). All tutorial copyrights belong to the original author.

# Basics

# 1. Key Concepts in JavaScript

# What is Scope?

The range in which a variable exists.

Scope can be divided into global scope and function scope. ES6 introduced block scope.

# What is a Closure?

A closure is a function that can read variables from another function's internal scope.

  • Form of a closure: defining a function inside another function
  • Essentially, a closure is a bridge connecting the inside and outside of a function

Uses of closures:

  • Can read variables inside a function
  • Keeps those variables in memory, meaning a closure can keep the environment where it was created alive
  • Encapsulates private properties and methods of an object

# What is a Constructor?

A function used to construct (generate) instances, giving instances the properties and methods defined within the constructor.

# What is an Instance Object?

An instance object is created via new with a constructor, possessing the properties and methods defined within that constructor.

# What is this?

this refers to the object where a property or method currently resides -- it points to the current execution context (object).

# What is a Prototype?

Every function has a prototype property that points to an object. This object is called the prototype object.

# What is the Prototype Chain?

All objects have their own prototype objects. Since prototype objects are also objects, they too have their own prototypes. This forms a prototype chain.

The topmost prototype is Object.prototype.

When reading a property of an object, JavaScript first looks on the object itself. If found, it returns the value directly. If not found, it looks on the prototype. If still not found, it continues up the prototype chain. Ultimately, it reaches Object.prototype. If still not found, it returns undefined.

# What is constructor?

Every prototype object has a constructor property that by default points to the constructor function that the prototype object belongs to.

# What is a Wrapper Object?

A wrapper object refers to instantiating a primitive type (number, string, boolean).

# 2. Data Type Conversion

# 2.1 Explicit (Manual) Conversion

Explicit conversion mainly refers to using the Number(), String(), and Boolean() functions to manually convert values of various types into numbers, strings, and booleans respectively.

# Number()

// Numbers: remain the same after conversion
Number(324) // 324

// Strings: converted to the corresponding number if parseable
Number('324') // 324

// Strings: returns NaN if not parseable as a number
Number('324abc') // NaN

// Empty string converts to 0
Number('') // 0

// Booleans: true becomes 1, false becomes 0
Number(true) // 1
Number(false) // 0

// undefined: converts to NaN
Number(undefined) // NaN

// null: converts to 0
Number(null) // 0

Number({a: 1}) // NaN
Number([1, 2, 3]) // NaN
Number([5]) // 5
Number([]) // 0

// Using parseInt() to convert an array
parseInt([1, 2, 3]) // 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# String()

// Primitive type conversions
String(123) // "123"
String('abc') // "abc"
String(true) // "true"
String(undefined) // "undefined"
String(null) // "null"

// Object conversions
String({a: 1}) // "[object Object]"
String([1, 2, 3]) // "1,2,3"
String([]) // ""  empty string
String(function(){}) // "function(){}"
1
2
3
4
5
6
7
8
9
10
11
12

# Boolean()

// Only these five values are false; everything else is true
Boolean(undefined) // false
Boolean(null) // false
Boolean(0) // false
Boolean(NaN) // false
Boolean('') // false

// true
Boolean({}) // true
Boolean([]) // true
Boolean(new Boolean(false)) // true

Boolean(1) // true
Boolean(' ') // true // Note: the string contains a space
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 2.2 Automatic Conversion

Automatic conversion is based on explicit conversion.

JavaScript automatically converts data types in three situations, where the conversion happens automatically and is invisible to the user.

First case: operations between different data types.

123 + 'abc' // "123abc"
1

Second case: evaluating a non-boolean value as a boolean.

if ('abc') {
  console.log('hello')
}  // "hello"
1
2
3

Third case: using a unary operator (+ or -) on a non-numeric value.

+ {foo: 'bar'} // NaN
- [1, 2, 3] // NaN
1
2

The rule for automatic conversion is: call the conversion function for whatever type is expected at that position. For example, if a position expects a string, the String function is called. If a position could be either a string or a number, it defaults to a number.

Because automatic conversion is unpredictable and hard to debug, it is recommended to use Boolean, Number, and String for explicit conversion wherever boolean, numeric, or string values are expected.

# Automatic Conversion to Boolean

When JavaScript encounters a position expecting a boolean (such as the condition part of an if statement), it automatically converts non-boolean arguments to booleans. The system internally calls the Boolean function.

Therefore, except for the following five values, everything else automatically converts to true:

  • undefined
  • null
  • +0 or -0
  • NaN
  • '' (empty string)

In the following example, each value in the condition is equivalent to false. Using the negation operator makes them true.

if ( !undefined
  && !null
  && !0
  && !NaN
  && !''
) {
  console.log('true');
} // true
1
2
3
4
5
6
7
8

The following two patterns are also sometimes used to convert an expression to a boolean. They internally call the Boolean function as well.

// Ternary operator
expression ? true : false

// Double negation operator
!! expression
1
2
3
4
5

# Automatic Conversion to String

When JavaScript encounters a position expecting a string, it automatically converts non-string values to strings. The specific rule is: first convert composite types to primitive types, then convert primitive types to strings.

Automatic string conversion mainly occurs during string concatenation. When one value is a string and the other is not, the latter is converted to a string.

# All types concatenated with a string become strings
'5' + 1 // '51'
 1  + '5' // '15'
'5' + true // "5true"
'5' + false // "5false"
'5' + {} // "5[object Object]"
 5 + {} // "5[object Object]"
'5' + [] // "5"
 5 + [] // "5"
'5' + function (){} // "5function (){}"
'5' + undefined // "5undefined"
'5' + null // "5null"
1
2
3
4
5
6
7
8
9
10
11
#

This automatic conversion can easily cause bugs if you're not careful.

var obj = {
  width: '100'
};

obj.width + 20 // "10020"
parerInt(obj.width) + 20 // 120
1
2
3
4
5
6

In the above code, the developer might expect 120, but due to automatic conversion, the actual result is the string 10020. The correct approach is to first convert the string to a number.

# Automatic Conversion to Number

When JavaScript encounters a position expecting a number, it automatically converts the argument value to a number. The system internally calls the Number function.

# Except for addition with strings (which converts to string), most other operations automatically convert to numbers
'5' - '2' // 3
'5' * '2' // 10
true - 1  // 0
false - 1 // -1
'1' - 1   // 0
'5' * []    // 0
false / '5' // 0
'abc' - 1   // NaN
null + 1 // 1
undefined + 1 // NaN

true+true // 2
1
2
3
4
5
6
7
8
9
10
11
12

In the above code, the operands on both sides of the operator are converted to numbers.

Note: null converts to 0 when converted to a number, while undefined converts to NaN.

Numbers with booleans and null also convert to numbers

5+true // 6
5+false // 5
5+null //5
1
2
3

Unary operators also convert their operands to numbers.

+'abc' // NaN
-'abc' // NaN
+true // 1
-false // 0
1
2
3
4

# 3. Error Handling Mechanism

# 3.1 Error Instance Objects

When a JavaScript parsing or runtime error occurs, the engine throws an error object. JavaScript natively provides the Error constructor, and all thrown errors are instances of this constructor.

var err = new Error('an error occurred');
err.message // "an error occurred"
1
2

In the above code, we call the Error constructor to create an instance object err. The Error constructor accepts a parameter representing the error message, which can be read from the instance's message property. After an Error instance is thrown, the entire program halts at the point where the error occurred and does not continue executing.

The JavaScript language standard only specifies that Error instances must have a message property for the error message; no other properties are mentioned. Most JavaScript engines also provide name and stack properties for Error instances, representing the error name and error stack respectively, but these are non-standard and not available in every implementation.

  • message: Error message
  • name: Error name (non-standard)
  • stack: Error stack trace (non-standard)

The name and message properties provide a rough understanding of what error occurred.

var err = new Error('an error occurred');
if (err.name) {
  console.log(err.name + ': ' + err.message); // Error: an error occurred
}
1
2
3
4

The stack property is used to view the stack trace when the error occurred.

function throwit() {
  throw new Error('');
}

function catchit() {
  try {
    throwit();
  } catch(e) {
    console.log(e.stack); // print stack trace
  }
}

catchit()
// Error
//    at throwit (~/examples/throwcatch.js:9:11) // Innermost: throwit function
//    at catchit (~/examples/throwcatch.js:3:9) // One layer out: catchit function
//    at repl:1:5 // Runtime environment


// Stack trace explanation
// Error
//    at throwit in the throwit method (~/examples/throwcatch.js:9:11) filename:line:character
//    at catchit in the catchit method (~/examples/throwcatch.js:3:9) filename:line:character
//    at repl:1:5 // Runtime environment
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

In the above code, the innermost layer of the error stack is the throwit function, then the catchit function, and finally the runtime environment.

# 3.2 Native Error Types

The Error instance is the most general error type. On top of it, JavaScript defines six additional error objects -- that is, there are six derived objects of Error.

# SyntaxError (Syntax Error)

The SyntaxError object is thrown when a syntax error occurs during code parsing.

// Invalid variable name
var 1a;
// Uncaught SyntaxError: Invalid or unexpected token

// Missing parenthesis
console.log 'hello');
// Uncaught SyntaxError: Unexpected string
1
2
3
4
5
6
7

The errors above can all be detected during the syntax parsing phase, so a SyntaxError is thrown. The first error message is "invalid token," and the second is "unexpected string."

# ReferenceError (Reference Error)

The ReferenceError object is thrown when referencing a variable that does not exist.

// Using a non-existent variable
unknownVariable
// Uncaught ReferenceError: unknownVariable is not defined
1
2
3

Another trigger scenario is assigning a value to something that cannot be assigned, such as the result of a function call or this.

// Left side of assignment is not a variable
console.log() = 1
// Uncaught ReferenceError: Invalid left-hand side in assignment

// this cannot be manually assigned
this = 1
// ReferenceError: Invalid left-hand side in assignment
1
2
3
4
5
6
7

In the above code, assigning to the result of console.log and to this both trigger a ReferenceError.

# RangeError (Range Error)

The RangeError object is thrown when a value exceeds the valid range. Main scenarios include: negative array lengths, Number object method parameters out of range, and function stack overflow.

// Array length cannot be negative
new Array(-1)
// Uncaught RangeError: Invalid array length
1
2
3

# TypeError (Type Error)

The TypeError object is thrown when a variable or parameter is not the expected type. For example, using the new command on primitive values like strings, booleans, or numbers throws this error, since new expects a constructor function.

new 123
// Uncaught TypeError: number is not a function

var obj = {};
obj.unknownMethod()
// Uncaught TypeError: obj.unknownMethod is not a function
1
2
3
4
5
6

In the second case, calling a non-existent method on an object also throws a TypeError, because obj.unknownMethod is undefined, not a function.

# URIError (URI Error)

The URIError object is thrown when URI-related function arguments are incorrect, mainly involving encodeURI(), decodeURI(), encodeURIComponent(), decodeURIComponent(), escape(), and unescape().

decodeURI('%2')
// URIError: URI malformed
1
2

# EvalError (Eval Error)

The EvalError is thrown when the eval function is not executed properly. This error type is no longer used and is only kept for backward compatibility with older code.

# Summary (Manual Use by Developers)

All six derived errors, along with the original Error object, are constructors. Developers can use them to manually create error object instances. These constructors all accept a parameter representing the error message.

var err1 = new Error('An error occurred!');
var err2 = new RangeError('Error: variable out of valid range!');
var err3 = new TypeError('Error: invalid variable type!');

err1.message // "An error occurred!"
err2.message // "Error: variable out of valid range!"
err3.message // "Error: invalid variable type!"
1
2
3
4
5
6
7

# 3.3 Custom Errors

In addition to the seven native error objects provided by JavaScript, you can define your own error objects.

function UserError(message) {
  this.message = message || 'Default message';
  this.name = 'UserError';
}

UserError.prototype = new Error(); // Prototype inherits from Error
UserError.prototype.constructor = UserError;

// Usage
new UserError('This is a custom error!');
1
2
3
4
5
6
7
8
9
10

The above code defines a custom error object UserError that inherits from the Error object. You can then generate this custom type of error.

# 3.4 throw Statement (Interrupt Program and Throw Error)

The throw statement is used to manually interrupt program execution and throw an error.

var x = 0;
if (x <= 0) {
  throw new Error('x must be a positive number');
}
// Uncaught Error: x must be a positive number
1
2
3
4
5

In the above code, if variable x is less than or equal to 0, an error is manually thrown to inform the user that the value of x is incorrect, and the entire program halts at that point. As you can see, the error thrown by throw is its argument -- here, an Error instance.

function UserError(message) {
  this.message = message || 'Default message';
  this.name = 'UserError';
}

throw new UserError('An error occurred!');
// Uncaught UserError {message: "An error occurred!", name: "UserError"}
1
2
3
4
5
6
7

In the above code, throw throws a UserError instance.

In fact, throw can throw any type of value -- its argument can be anything.

// Throw a string
throw 'Error!';
// Uncaught Error!

// Throw a number
throw 42;
// Uncaught 42

// Throw a boolean
throw true;
// Uncaught true

// Throw an object
throw {
  toString: function () {
    return 'Error!';
  }
};
// Uncaught {toString: f}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

For the JavaScript engine, when it encounters a throw statement, the program halts. The engine receives the information thrown by throw, which could be an error instance or any other type of value.

# 3.5 try...catch Structure (Catch Errors, Handle Them, No Interruption)

Once an error occurs, program execution halts. JavaScript provides the try...catch structure that allows errors to be handled and optionally continue execution.

try {
  throw new Error('An error occurred!');
} catch (e) {
  console.log(e.name + ": " + e.message);
  console.log(e.stack);
}
// Error: An error occurred!
//   at <anonymous>:3:9
//   ...
1
2
3
4
5
6
7
8
9

In the above code, the try block throws an error (using the throw statement), and the JavaScript engine immediately transfers execution to the catch block -- the error is "caught" by the catch block. catch accepts a parameter representing the value thrown by the try block.

If you are unsure whether some code might throw an error, you can place it inside a try...catch block for further error handling.

try {
  f();
} catch(e) {
  // Handle error
}
1
2
3
4
5

In the above code, if function f throws an error, the catch block is entered for error handling.

After the catch block catches an error, the program does not halt and continues executing normally.

try {
  throw "An error occurred";
} catch (e) {
  console.log(111);
}
console.log(222);
// 111
// 222
1
2
3
4
5
6
7
8

In the above code, the error thrown by the try block is caught by catch, and the program continues executing.

Inside a catch block, you can throw another error, or even use nested try...catch structures.

var n = 100;

try {
  throw n;
} catch (e) {
  if (e <= 50) {
    // ...
  } else {
    throw e;
  }
}
// Uncaught 100
1
2
3
4
5
6
7
8
9
10
11
12

In the above code, another error is thrown inside the catch block.

To catch different types of errors, you can add conditional statements inside the catch block.

try {
  foo.bar();
} catch (e) {
  if (e instanceof EvalError) {
    console.log(e.name + ": " + e.message);
  } else if (e instanceof RangeError) {
    console.log(e.name + ": " + e.message);
  }
  // ...
}
1
2
3
4
5
6
7
8
9
10

In the above code, catch catches the error and then checks the error type (EvalError or RangeError) for different handling.

# 3.6 finally Block (Always Executes After try...catch)

The try...catch structure allows adding a finally block at the end, representing statements that must run regardless of whether an error occurred.

function cleansUp() {
  try {
    throw new Error('An error occurred...');
    console.log('This line will not execute');
  } finally { // finally executes whether or not an error occurred
    console.log('Cleanup complete');
  }
  console.log('This line will not execute');
}

cleansUp()
// Cleanup complete
// Uncaught Error: An error occurred...
//    at cleansUp (<anonymous>:3:11)
//    at <anonymous>:10:1

// Since there is no catch block, the error message is printed and code is interrupted (except for finally).
// If there were a catch block, the catch code would execute without printing the error message, and code would not be interrupted.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

In the above code, since there is no catch block, once an error occurs, execution is interrupted. Before interruption, the finally block executes first, then the error message is displayed.

function idle(x) {
  try {
    console.log(x);
    return 'result';
  } finally {
    console.log('FINALLY');
  }
}

idle('hello')
// hello
// FINALLY
1
2
3
4
5
6
7
8
9
10
11
12

In the above code, the try block has no error and includes a return statement, but the finally block still executes. The function's return value is still result.

The following example shows that the return statement executes before the finally block, but waits for finally to complete before actually returning.

var count = 0;
function countUp() {
  try {
    return count;
  } finally {
    count++;
  }
}

countUp()
// 0
count
// 1
1
2
3
4
5
6
7
8
9
10
11
12
13

The above code shows that the value of count in the return statement is obtained before the finally block runs.

Below is a typical use case for the finally block.

openFile(); // Open file

try {
  writeFile(Data); // Write to file
} catch(e) {
  handleError(e); // If writing fails, handle the error
} finally {
  closeFile(); // Close file regardless of whether an error occurred
}
1
2
3
4
5
6
7
8
9

The above code first opens a file, then writes to it in the try block. If no error occurs, finally closes the file. If an error occurs, catch handles it first, then finally closes the file.

The following example fully illustrates the execution order of try...catch...finally.

function f() {
  try {
    console.log(0);
    throw 'bug';
  } catch(e) {
    console.log(1);
    return true; // This would normally be delayed until after the finally block
    console.log(2); // Will not run
  } finally {
    console.log(3);
    return false; // This overrides the previous return
    console.log(4); // Will not run
  }

  console.log(5); // Will not run
}

var result = f();
// 0
// 1
// 3

result
// false
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

In the above code, the finally block executes before the catch block finishes.

The trigger for entering the finally block from a catch block is not only the return statement but also the throw statement.

function f() {
  try {
    throw 'An error occurred!';
  } catch(e) {
    console.log('Internal error caught');
    throw e; // This would normally wait until finally completes
  } finally {
    return false; // Returns directly
  }
}

try {
  f(); // Receives return value false, not an error
} catch(e) {
  // This block will not execute
  console.log('caught outer "bogus"');
}

// Internal error caught
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

In the above code, upon entering the catch block and encountering a throw statement, execution transfers to the finally block. Since finally has return false, it returns directly and never goes back to complete the remaining catch block.

try blocks can be nested inside other try blocks.

try {
  try {
    consle.log('Hello world!'); // Error: console is misspelled
  }
  finally {
    console.log('Finally');
  }
  console.log('Will I run?');
} catch(error) {
  console.error(error.message);
}
// Finally
// consle is not defined
1
2
3
4
5
6
7
8
9
10
11
12
13

In the above code, there is a try inside another try. The inner try throws an error (because console is misspelled), so the inner finally block executes, then the error is thrown and caught by the outer catch.

# 4. The console Object

# console.time() and console.timeEnd() (For Timing Operations)

These two methods are used for timing and can calculate the exact time an operation takes.

console.time('Array initialize');

var array= new Array(1000000);
for (var i = array.length - 1; i >= 0; i--) {
  array[i] = new Object();
};

console.timeEnd('Array initialize');
// Array initialize: 1914.481ms
1
2
3
4
5
6
7
8
9

The time method starts the timer, and the timeEnd method stops it. Their parameter is the timer name. After calling timeEnd, the console displays "timer name: elapsed time."

# Reference

Study reference: https://wangdoc.com/javascript/ (opens new window)

Edit (opens new window)
#JavaScript
Last Updated: 2026/03/21, 12:14:36
Built-in Objects

Built-in Objects→

Recent Updates
01
How I Discovered Disposable Email — A True Story
06-12
02
Animations in Grid Layout
09-15
03
Renaming a Git Branch
08-11
More Articles >
Theme by VDone | Copyright © 2026-2026 Nikolay Tuzov | MIT License | Telegram
  • Auto
  • Light Mode
  • Dark Mode
  • Reading Mode