I've organized this blog page in this long run on series of mini articles because this is my ever expanding tool-belt. This series of short articles discussing the tools in which I work should be all accessable in one place. If articles are too detailed they are not succeeding here in providing easy to digest knowledge about high level concepts about what is going on with the tools in my Toolbelt.
An Execution Context is the environment that JavaScript code runs in. Execution Contexts are
comprised of the global object, the 'this'(link to this concept) variable, a reference to the
outer environment, and the code to be executed.
When the JavaScript compiler starts to work through a file, it creates a Global Execution
Context. The Global Execution Context is the base Execution Context. In the browser, the Global
Execution Context will have the window object be both 'this' and the Global Object. The outer
environment is null. The code to be executed will be what code is in the file.
The creation of an exection context is often refered to as the first phase of an execution context. In this first phase, the JavaScript engine sets up memory space for functions and variables. In the second phase, the JavaScript engine will run the code inside of the execution context line by line.
Execution contexts other than the global execution context are created on any function invocation. If the engine encounters a function invocation, it will stop where it is in the current execution context and build another execution context that it puts on top of the first one. We refer to this concept as the Execution Stack. Once JavaScript is finished executing the code of an execution context, it pops it off of the stack and start working on the next execution context in the stack.This behavior is a consequence of JavaScript being single-threaded and synchronous. JavaScripts executes one line at a time and one execution context at a time.
The scope chain is the concept that defines how the JS Engine searches for variable values while in an execution context. An execution context has a reference to it's outer environment. This outer environment is determined by a function's lexical environment. A function's lexical environment is where it was physically defined. So, if function "a" was defined inside of function "b," function "a" lexical environment and subsequently outer reference will be function "b". If function "b" was defined in the global context, it's outer reference will be the global environment. Scope Chain uses this relationship to look for variables in memory space. A variable referenced in a function will look down it's scope chain for the first instantiation of that variable. Note, the same variable can be instantiated in different Execution Contexts which could lead to some undesired behavior if one doesn't understand the scope chain.
Operators are special functions in JavaScript that are invoked syntactically different than regular functions. Assignment(=), addition(+), and equality (==) are a few of the operators in JavaScript. Operators have special properties, precedence and associativity. Expressions with multiple operators in them rely on operator precedence to decide which ones to execute first and in what order. This concept is similar to order of operations from mathematics. When operators have the same precedence value, they rely on their operator associativity to determine which order to execute the operators. Operators are either left to right associative or right to left associative.
All functions are JavaScript objects. A JavaScript Object is a collection of key value pairs where the value can be JavaScript primitives, JavaScript objects, and JavaScript functions. Functions here are special types of objects that are invocable with the parenthesis syntax and can store invokable code. When a function is invoked an execution context is created. Since functions are objects, you are able to treat them like a regular JS object and give them properties.
In JavaScript, functions are considered "first class." This means that everything you can do with objects and primitives, you can do with functions. For example, you are able to pass functions as a parameter to other functions. This property allows for JavaScript to be used in the functional programming paradigm.
Functions can be defined a couple of different ways and modern JavaScript has different syntax for these. The main distinction are function expressions versus function statements. Function expressiosn are units of code that actually return a value. Function statements do not return a value. Function expressions can be assigned to a variable or not assigned but in this case must be surrounded by parenthesis. A common pattern in JS programming is the use of IIFE, Immediately Invoked Function Expression. Since the function expressions returns the defined function, it is possible to invoke this value immediately with the function invokation syntax. This is used in some libraries to avoid namespace collisions with other JavaScript packages or scripts. A namespace collision can occur in situations where two different projects are adding the same variable to the global object. By using IIFEs, JavaScript progams avoid adding to the global namespace and instead add to the context of the function.
Closures are created when a function is defined. This gives a function access to it's lexical environment even after the execution context has popped off of the stack. It's memory remains and any function invocation will have access to any variables and methods from the lexical environment. To use closures, you can have a function expose a function, i.e. return an inner defined function. Closures can be useful in cases of data privacy. It can also be useful when using function factory patterns and invoking function currying, setting permanent parameters that are borrowed by inner parameters. Let's take the following code and understand how closures allowed this to happen.
function add(y) {
return (x) => {
x+y
}
}
const add5 = add(5)
const add10 = add(10)
Inheritance is an comes from object oriented paradigms. It means one objects getting access to the properties and methods of another object. JavaScript implements this through prototypes. Proto is a special reference on JavaScript objects. When a method is called on an object, if the JavaScript engine cannot find it on the object it will look for it next in the Proto reference. It will continue down this path until it's found the method thus establishing the prototype chain.
Everything in JavaScript is an object or primitive. All arrays, objects, and functions inherit from the base prototype object eventually.
//Code without null-safe operator
if (object != null) {
object.fooMethod()
}
//Code with null-safe operator
object?.fooMethod()
You can still get Null Pointer Exceptions (NPE) at runtime in Kotlin a few ways. A couple common ways of getting a NPE are the use of the not-null assertion operator (!!) and working with generics and platform types. Sometimes, nullability is not always the best pattern to use. For example, if you must wait to initialize a parameter a pattern to use instead of marking that parameter as null would be to use the lateinit property on that parameter.