Welcome to the deep dive. Think of this as your cheat sheet, maybe your shortcut to getting really well informed about important stuff.
Yeah, we basically wade through all the information, find the core ideas, and bring back what you really need to know.
Saves you time exactly.
And today we are plunging into javascripts specifically for web developers. We've got a whole stack of resources here.
We do, covering well everything from the real basic building blocks right up to the you know, the fancy new browser APIs and features just emerging.
Right, So the mission for this deep dive pull out the essential concepts, maybe some surprising details about modern JS development.
Give you a solid handle on it without you know, drowning you in every single tiny detail.
Perfect. Okay, let's kick things off with something well fundamental. We always hear javascripts and ECMAScript toss around. What's the actual relationship there?
Okay, good starting point. Think of ECMAScript as the official standard. It's the specificating like the rule book for how a scripting language should behave the rulebook okay in JavaScript? Well, JavaScript is the most well known language that actually follows those rules. It implements the ECMAScript standard.
Ah, got it? So xmascript is the spec. JavaScript is the implementation.
Exactly, and just like languages evolve, xmascript gets updated, new editions, come out S six, S twenty twenty, whatever, adding new features, refining things. JavaScript then usually catches up and implements those new features.
Makes sense. So when we put JavaScript on a web page, we use the script tags. Our sources mentioned two main types these days, the old text JavaScript and the newer module.
What's the key difference, right, So script type text JavaScript, that's the classic way. Code inside there runs in well basically the global scope for that script.
Everything together pretty much.
But script type module is different. I came with EES six. It tells the browser, hey, treat this code as a proper ECMAScript.
Module and what does that let us do?
That unlocks features like import and export, so you can break your code into smaller, reusable pieces, manage dependence the cleanly. It's a huge step up for organization and avoiding conflicts.
Right, So it stops everything from just clashing in that one big global space, more organized, way, more organized.
With separate offices communicating properly instead of one giant noisy room.
Good analogy. Okay, moving into the code itself, comments, essential notes.
Right.
Our sources mentioned the C style comments.
Yep, JavaScript uses the familiar SEA style you've got for single line comments. Anything after that on the line is ignored.
And the multi line ones that's.
To start and to end. You can put multiple lines of comments between those. It was a natural fit really, given JavaScript's influences and how common C style syntax was.
Makes sense. Keep it familiar. Now, code structure curly braces. We use them everywhere, like with if statements. Are they just for looks or more fundamental?
Oh, they're fundamental. They define code blocks. You can technically omit them for a single statement after an IF or a four like if condition do one thing.
Yeah, I've seen that, but it's really.
Really considered best practiced. Always use the curly braces. It makes the code much easier to read and prevents subtle bugs later if you add more statements to that block.
Good advice, Always use the braces. Okay, Variables the heart of storing data. We've got the old var and the newer let and constant. Let's break down the key differences, scope hoisting all that stuff.
Right, So var it's function scoped, meaning if you declare a var inside a function, it's known throughout that entire function, even inside nested blocks like ifts or loops.
Okay, function scope and hoisting.
Ye, var declarations are hoisted. That means the declaration part like varx is conceptually moved to the top of its function scope.
Before the code runs just the declaration.
Just the declaration the assignment x equals ten stays where you wrote it. This can lead to weird situations where you can use a variable before its declaration appears in the code, and it'll have the value undefined.
And you can readeclare var variables too.
Yep, you can write var myvar five and then later varivar ten in the same scope and JavaScript is fine with it, which can also cause confusion.
Definitely sounds like it could. So how does let improve things?
Let was introduced in e S six to fix these issues. The big change is block scope. A LET variable is only known within the specific block that curly braces words.
Defined, So inside an if or a for loop, it only exists there exactly.
Much more contained, much easier to reason about. It prevents accidental variable clashes between different parts of your code.
That sounds way better. What about hoisting and redeclaration with let.
Let declarations are also hoisted, but critically their initialization is not. This creates something called the temporal dead zone or TDZ. If you try to access a let variable before it's actual declaration line in the code, you get a reference there.
Ah. Okay, so safer prevents using it before it's.
Ready, right, and you cannot redeclare a let variable within the same scope. Yeah, if you try let x five let x bleeds ten in the same block, you'll get an error much stricter.
Good and then const the name implies it can't be changed.
Very similar to it's also block scoped has the TDZ and cannot be redeclared in the same scope.
But the key difference.
You must initialize a cost variable when you declare it like cost pi equals three point one four, and once assigned, you cannot reassign that variable to a different value. The binding is constant.
So pi equals three later would cause an error exactly.
But and this is important, if the const variable holds an object or an array, you could still change the contents of that object or array. You just can't make the variable point to a completely new object or array.
Ah. Subtle but crucial distinctions. The variable binding is constant, not necessarily the value itself if it's an object precisely.
And our sources mentioned a potential performance benefit to using let and const over var, because the engine has a better idea of how the variable will be used.
Interesting worth keeping in mind. Now, naming these variables identifiers, are there strict rules?
Yes, identifiers have to start with a letter, an underscore, or a dollar sign after the first character. You can also use numbers, okay.
Any things you can't use definitely.
You can't use JavaScript keywords like if, for function, let, const, var, et cetera. You also can't use reserved words words set aside for future use, and the literal values true, false, and null are also off limits as variable names.
Makes sense, don't want to confuse the language itself. Okay, Let's talk data types the primitives first. These are the simple fundamental types, right, the.
Basic building blocks. First up is number. This covers both integers and floating point numbers. JavaScript doesn't really distinguish between them internally in the way some other languages do.
Some number okay, Any special ways to write.
Numbers, Yeah, you can write integers in decimal obviously, but also binary using a zero B prefix, octal with a zero O prefix or just eleading zero in nonstrict mode, which can be confusing, and hexadecimal with zero.
X hex is pretty common in web dev, very common.
And within number you also have the special values nan not a.
Number, which can confusingly is a number type right?
Ah? Yes, type of nan returns number. It usually results from invalid math operations like zero zero, and you have infinity and into infinity.
Okay, And what about really really huge numbers.
That's where bigin comes in. It's a newer primitive type designed to handle integers larger than the maximum safe integer value for number, which is around two to the power of fifty three minus one.
Wow.
How do you create those?
You append an end to the end of an integer literal like one, two, three, four five n or you use the big in function.
Any gotcha's with big inn.
Yeah. You can't mix biggest and number types in standard arithmetic operations directly. You have to convert them, and you can't use big in values with the built in math object methods.
Good to know. Okay. Beyond numbers, we have.
String represents text basically a sequence of sixteen bit Unicode characters. You can use single quotes, double quotes, or backticks to define them.
Any difference between single and double quotes.
Functionally no, it's mostly style preference, though enable template literals, which are super useful for embetting expressions directly into strings.
Right with the syntax very handy.
Next, boolean simple one can only be true or false, used all the time for conditional logic.
Okay, and then null and undefined They seem similar but aren't quite.
The same correct. Null is a primitive type that represents the intentional absence of any object value you explicitly set something to null. Undefined means a variable has been declared but hasn't been assigned of value yet. It's the default state.
So null is I meant for this to be empty? And undefined is nobody put anything here yet?
That's a good way to think about it. And finally, among the primatives, there's symbol symbols.
These are unique identifiers right exactly.
Symbol creates a unique, immutable primitive value. Even if you create two symbols with the same description, like symbol foo and simple foo, they are not equal. They're unique.
What are they used for?
Often? Uses keys for object properties when you want to avoid potential clashes with other properties or library code. There's also symbol dot four key, which creates or retrieve symbols from a global registry. So symbol dot for food.
Interesting. Do they show up in normal object iteration? Not?
Usually they aren't enumerated by four dot. In loops, you need specific methods like object dot get town property symbols, or reflect dot own keys to access them.
Okay, and there are built in symbols.
Too, Yes, well known symbols like symbol dot iterator, symbol dot replace, symbol dot search. These allow you to hook into fundamental language behaviors.
That's a lot of primitives. Okay, let's talk operators doing things with these values basic math like and seem straightforward. But what about those bitwise operators? When do we use those?
Right? So, multiplication and division have rules for nan and infinity like infinity zeros in NAN, but the bitwise operators and D or xo R not marriot left shift signed right shift, unsigned right shift. They operate directly on the binary representation of numbers.
Lower level stuff, yeah.
Very low level. You might use them for things like manipulating flags stored in a single number. Performance critical calculations, maybe graphics or network protocol work where you're packing data efficiently.
So left shift multiplies by powers of two.
Correct and preserves the sign signed right shift divides by powers of two, also preserving the sign. Unsigned right shifts also divides, but always fills with zeros on the left, so the result is always non negative. Not everyday tools for most web devs, but good to know they.
Exist definitely now the sources mentioned the with statement sounds old, it.
Is and definitely deprecated and forbidden in strict mode. Its idea was to shorten access to object properties like with document dot location instead of repeating document dot location.
Why is it bad?
It makes code really hard to understand because it's unclear where variables are coming from. Are they local, global, or from the with object And it kills performance because the engine can't easily optimize lookups.
Avoid it good advice avoid with Okay, last fundamental strict mode you strict. Why should we use this?
Strict mode is basically a way to opt into a cleaner, safer, less error prone version of JavaScript. You put the string you strict at the very top of a script or a function, and what does it do. It changes certain things. It turned some previously silent errors into throne errors. For example, assigning a value to an undeclared variable throws an error instead of implicitly creating a global variable.
Ah. That's good. Helps catch typos exactly.
It also prevents or throws errors for certain unsafe actions like deleting variables or functions. It bans the wis statement. It makes evil safer. It prevents using reserved words like evil or arguments as variable names.
So it basically tightens up the rules and catches common mistakes pretty much.
It helps you write more robust, maintainable code. It's highly recommended for all modern JavaScript development.
Makes total sense like built in code review. Okay, let's switch gears to objects in a raise complex data first. That distinction primitive versus reference value. Why is this so critical?
It fundamentally changes how you work with data. Primitive values, numbers, strings, booleans, et cetera. Are passed by value. When you assign a primitive variable to another, you're making a completely separate.
Copy, independent copies, right.
But reference values objects in a raise are passed by reference. When you assign an object variable to another, both variables end up pointing to the exact same object in memory.
So changing the object through one variable affects the other absolutely.
If you have OBJ one down a OBJ two dot day one and then you do OBJ two dot name aples a b UPJ one dot name will also be b. They're referencing the same underlying data structure. Understanding this is crucial for avoiding unexpected side effects.
Definitely okay, So how do we figure out what type of data we have? Type of seems like the obvious choice, but it has quirks.
It does type or for works great for primitives number, string, boolly and undefined symbol big int. It also correctly identifies functions returning function.
But for objects, and as for.
Most reference types, including regular objects in arrays, type offf just returns object, and confusingly, type of null also returns object. That's a long standing historical bug.
So type of isn't always specific enough for objects. What else can we use?
The instance of operator is often better for checking object types. You can do my array instance of array or my date instance of date to see if an object was created by a specific constructor or inherits from its prototype.
Okay, instance of for more specific object checks now scope. How does JavaScript know which variable we mean when we use a name? The scope chain exactly.
Scope determines where variables are accessible. JavaScript uses lexical scope, meaning scope is defined by where the code is physically written. When you use a variable, the engine first looks in the current innermost scope, and if it's not there, looks in the next scope outwards, then the next, and so on up the chain until it hits the global scope. This sequence of scopes is the.
Scope chain, like nested boxes pretty much.
If it which is the global scope and still doesn't find the variable, you get a reference error in strict mode. Anyway, looking up globals can be slightly slower than locals because the chain might be longer, but engines optimize this well.
Okay. And memory management, JavaScript cleans up after itself with garbage collection. How does that work?
Yes? JavaScript has automatic garbage collection PC. The engine tracks which objects are still reachable, meaning they can somehow be accessed, starting from the root objects like the global.
Window object, so it traces all the references kind of.
The most common algorithm is mark and sweep. The GC starts at the roots, marks all reachable objects, and then sweeps through memory reclaiming the memory used by any object that wasn't marked.
So if nothing points to an object anymore, it gets swept up.
Essentially, Yes, it's automatic, but not fool proof. You can still create memory leaks if you unintentionally keep references to objects you no longer need. And the timing of GC is nondeterministic. You don't control exactly when it runs.
I know it's mostly handled, but leaks are still possible. All right, let's look at specific reference types. The basic object. It's more than just key value pairs, isn't it.
Oh yeah. Object is the foundation for almost everything complex in JavaScript. It's a dynamic collection of properties where keys are usually strings or symbols, and values can be anything. We usually create them with object literals. It's the basis for prototype based inheritance, which is core to JS.
The cornerstone, okay, an array. It's like a list, but more flexible than in some languages.
Definitely. JavaScript arrays are ordered lists, but they're dynamic. They can grow and shrink, and importantly, they can hold elements of any data type mixed together. A single ray could have numbers, strings, objects, even other.
Arrays very flexible.
How do we make arrays. Literals are common.
Literals are the most common and usually the best way. You can also use new array, but it has some weird behavior if you pass just one number argument. A ray out from is super useful for converting array like things like dom modalists or the argument's object or iter like sets or maps into real arrays.
Array dot from some sandy and array dot from.
Array does creates a new array with whatever arguments you pass it. A ray dot one two three gives one two three, and a ray of seven gives seven. It avoids the new array seven confusion, which creates an mpty array of length seven.
Got it now changing array contents, dot fil sort, splice, What do these do?
Phil Let's you set all or part of an array to a static value. Useful for initialization. Sort sorts the array in place than gotcha. By default, it sorts lexicographically like stringths.
So one ten two would sort to one ten two exactly.
For numeric sorting, you must provide a comparison function like ab equal ab for ascending order.
Right always provide the compare function for numbers, and splice.
Splice is the Swiss army knife. Let's remove elements in some elements or replace elements all of a specific index, modifying the original array directly. It's very powerful. Splice in x lead count outum one item.
Two okay, modifies in place. What about finding things? Index of last and x xen inclusion.
The first index of an item searching forwards last index yeah finds the last index searching backwards. Both return to nus one if not found, and both use strict equality and include just returns true or if false if the item exists in the array. Simpler if you don't need the index. It also uses strict equality index of and last index. Oves can take an optional second argument for the starting search position.
Use includes for existence, check indexoflast, index of if you need the position. And reduce sounds like it boils an array down.
It does. Reduce iterates through an array applying a function you provide to accumulate a single result. The function gets the accumulator, the current value, the index, and the array itself. You can some numbers, build an object, flatten an array really versatile. You usually provide an initial value for the accumulator.
Powerful stuff, okay. Type dearrays in eight array float thirty two array. These sound specialized? Why use them over regular arrays.
Performance, mainly when dealing with raw binary data. Regular rays are super flexible, but that flexibility has overhead. Type raise give you a direct fixed length view onto a chunk of binary memory an array buffer, where each element is known to be a specific numeric type like eight bit unsigned, editger, thirty two bit float, et cetera.
So for things like graphics or processing audio data.
Exactly WebGL web audio API manipulating file data read into an array buffer. They share many methods with regular arrays, map filter, etc. But they operate within the constraints of their type and fixed length. They also have methods like set for efficiently copying data in and subaray to create a new typed to array view over a portion of the same buffer.
Efficient binary data handling and data view. How's that different?
Data View also works on an array buffer, but it's even lower level. Instead of viewing the whole buffer as one type, data view lets you read and write different numeric types at any byte offset within the buffer.
So you could read an eight bit in then a sixteen bit float from the same.
Buffer precisely, and crucially, data view lets you control the endianness byte order big indian or little endian for multi byte types. This is essential when you're working with specific file formats or network protocols that dictate a particular byte order.
So typed arrays for uniform numeric arrays. Data view for fine grained multi type endingess controlled access to binary data.
That's a great summary.
Okay, let's talk collections, map and set. How are they different from plain objects and arrays.
Map is like an object for key value pairs, but with key differences. Keys in a map can be any data type, not just strings or symbols. You can use an object or even a function as a key. Also, map remembers the original insertion order.
Of keys any data type as a key and ordered useful and set.
Set is a collection of unique values you add items, and duplicates are automatically ignored. Like MAP, it also remembers insertion order. Great for quickly removing duplicates from an array or just storing a list where uniqueness matters.
Set for uniqueness map for flexible keys. What about weak set? What's weak about it?
Weekset is it's like set, but it only holds objects, and it holds them weekly. This means if an object is only referenced by the weakset and nowhere else in your code. The garbage collector is free to remove it.
Ah, so it doesn't prevent garbage collection. Why is that useful?
It's great for associating metadata with objects without preventing those objects from being cleaned up if they're removed from say the DOM. If you remove a DOM element and it was in the week set, the weekset reference won't keep it lingering in memory because items can disappear. You can't iterate over a week set.
Smart for managing metadata on potentially transient objects. Okay, iterating over these collections in arrays and strings. The iteration protocols. What's the deal with symbol dot iterator?
Right? For an object to be considered iterable, meaning you can use it with for out of loops or spread syntax, it needs to have a method whose key is the well known symbol symbol dot iterator.
And what does that method do?
That method, when called, must return an iterator object. The iterator object, in turn, must have an next method.
And next gives you the value.
Calling next returns an object with two properties value the next value in the sequence and done a boollion that's false until the iteration is complete, then it becomes true.
So iterable means has symbol dot iterator, which gives an iterator which has naxt got it.
That's the contract and for.
Data Bouve just handles all that automatically.
Yep fata b loops are designed specifically to work with this protocol. It calls symbol dot iterator, gets the iterator, and keeps calling next until done is true, give you the value at each step. Works on a raise strings, map, sets, no lists anything.
Iterable much nicer than old four loops with index counters. Sometimes now generators dot function How do they fit into iteration?
Generators are a special kind of function defined with function. When you call a generator function, it doesn't run the code immediately. Instead, it returns a generator object, which is an iterator.
So calling it gives you the iterator directly.
Yes. Inside the generator function, you use the yield keyword. Word yield pauses the function's execution and sends a value out that becomes the value in the value done object.
From next pauses the function Yeah.
The next time you call next on the generator object, the function resumes exactly where it left off right after the yield and continues until it hits the next yield or the end.
Of the function whoa functions that pause and resume.
It's powerful makes writing complex iterators much easier. You can also use yield to delegate iteration to another iterable or generator.
Fascinating and async iterators a sync function and for a weight dot f. This is for asynchronous sequences exactly.
ACNC iteration protocols handle sequences where the values arrive asynchronously, like data streaming over a network, and ACNC literable has symbol dot ACNC iterator, which returns an ACNC iterator.
And its next method.
Its next method returns a promise that resolves to the value downe object ah.
So next is async itself.
Right, and the four weight of loop is designed to work with these. It weighs asynchronously for the promise from next to resolve before each iteration. Perfect for handling streams of data like chunks from a fetch response or server send events.
Very cool.
Okay, let's dive deeper into objects. Property attributes, configurable, innumerable, writable. What are these internal things?
Every object property has these internal attributes to control its behavior. Configurable means can the property be deleted or can its attributes be changed later? Innumerable means does it show up in four lot loombs, ritable means can its value be changed? And value holds the actual value.
So they define the meta behavior of the property exactly.
They're also get and set attributes for accessor properties getters and setters instead of value.
And ritable, and we control these using object dot define property.
Yes, object dot define property lets you define a new property or modify an existing one and explicitly set these attribute values like innumerable dot false or ritable dot false. You can also define getter and setter functions using this object out defined properties lets you do it for multiple properties at once.
Gives you fine grain control. Now, object literals have some nice shorthands these days, right they do.
If you have variable X and you want an object property x with that variable's value, you can just write x instead of xx.
Nice. And for methods you can.
Write my methods my method dot function cleaner syntax.
And computed property keys.
Yeah, you can use square brackets inside an object literal to use the result of an expression as a property key like prefix plus id. Very dynamic.
These shorthands definitely make object creation less verbose. What about combining objects object dot A sign. How does it work?
Object out a sign target dot sources copies all innumerable own properties from the source objects into the target object. It modifies the target directly and returns.
It copies properties. Is it a deep copy?
No. Crucially, it's a shallow copy. If a property value is an object or array, only the references copy, not the nested structure itself. Both the target and source will point to the same nested object.
Okay, shall I copy important limitation? How does it handle getter setters?
It invokes getters on the source and copies the resulting value to the target. It doesn't copy the getter function itself. Setters aren't copied.
Got it useful for emerging simple objects or applying mix ins? What about getting values out of objects? Destructuring?
Object destructuring is fantastic. It lets you unpack properties from an object directly into variables like const name age user.
Much cleaner than constname user dot name constant age user dot age way cleaner.
You can also rename variables comments, provide default values, constme measures, and use the rest syntax to collect remaining properties into a new object. Constant aid rest data.
Super useful for working with API responses or config and the spread operator also works inside object literals.
Yes, similar to object dot assign it lets you spread the properties of an existing object into a new object literal constant new user u uzer age thirty one is admin false. Also a shallow copy. Great for creating modified copies of objects nondestructively.
Okay, spread for creating new objects based on old ones. Now the tricky this keyword. Its value depends on how a function.
Is called right, hugely depends on the call site. In a regular function called directly, not as an object method, this is the global object window and browsers in non strict mode and undefined as strict mode.
Okay, what about when it's a method like an object dot do something.
Then this inside do something refers to object the object the method was called on.
Makes sense, and we can explicitly set this yep.
Using function dot call this rg R one, function dot apply this ars array, or function dot bind this arg which returns a new function permanently bound to that this value.
And ero functions they're different.
Completely different regarding this erofunctions don't have their own this. They lexically capture this value from their surrounding scope at the time they are defined. This solves many old problems, especially with callbacks inside methods that lexical.
This in aerow functions is a key feature. Okay, let's talk inheritance prototypes. This is JavaScript's core inheritance model, right, not classes, initially.
Correct, JavaScript uses prototype based inheritance. Every function is a prototype property, which is an object. When you use a function as a constructor with new the object created inherence from the constructor's prototype, object inherits.
How does that work?
Every object has an internal link, often accessible via proto, though object dot get prototype of is the standard way to read it to its prototype. When you try to access a property on an object, if the object doesn't have it directly, JavaScript looks at its prototype. If the prototype doesn't have it, it looks at its prototype, and so on up the chain.
The prototype chain, so properties are looked up along this chain exactly.
That's how inheritance works. Methods defined on a constructor's prototype are shared by all instances created from that constructor. You can use object dot is prototype of another object to check the chain relationship.
Okay, Prototypes are the real mechanism. So what about ES six class syntax? Is that just sugar on top.
Pretty much class provides a cleaner, more familiar syntax for setting up constructor functions and their prototypes. The constructor method inside a class defines the constructor function. Other methods defined in the class body automatically get added to the class's prototype.
So it makes prototype inheritance look more like classical inheritance.
Kind of yes, it simplifies the syntax. Class also introduces features like static members belonging to the class itself, not instances, and more recently, private members using the hashtag prefix for true encapsulation. But underneath it's still leveraging the prototype chain.
Good to know classes mostly syntax over the existing prototype system. Okay, let's focus specifically on functions. Now different ways to define them declarations, expressions, arrows right.
Function declarations look like function my function. These are fully hoisted. You can call them before they appear in the.
Code hoisted okay, and expressions.
Function expressions assign a function to a variable like co hocal function or constant my aerowfunk. With these, only the variable declaration constant my funk is hoisted, not the function assignment itself. You can't call them before the line where they're assigned.
So declarations are fully hoisted expressions including arrows are not correct.
And aero functions have that concise syntax in the lexical this binding we talked about. There's also the function constructor new function ab return of plus b, but it's generally discouraged. Like evil, it executes code from strings, which is slow and potentially insecure.
Stick to declarations, expressions and arrows. Then, what about handling arguments rest parameters.
Rest parameters dot orgs let you gather an indefinite number of trailing arguments passed to a function into a single real array named arcs, much better than the old arguments.
Object and spread syntax in function calls.
That does the opposite. It takes an iterable like an array and expands it into individual arguments. When calling a function my function dot my array.
So rest collects arguments into an array. Spread expands an array into arguments. Got it and default parameter values.
Yeah, you can set defaults directly in the signature function creed. If the argument isn't provided or is undefined, the default is used. Makes functions more robust.
We covered hoisting already. How about functions as values first class functions?
It just means functions in JavaScript are treated like any other value. You can assign them to variables, store them in arrays or objects, pass them as arguments to other functions callbacks, and return them from functions higher order functions. This is fundamental to functional programming patterns in JS.
Very flexible. What about the caller property and the arguments object still relevant?
The argument's object exists in non arrow functions. It's an array like object holding all past arguments. But rest parameters are generally preferred now because they give you a real array. Arguments dot collie refers to the current function and arguments dot caller or function dot caller refers to the calling function are deprecated, non standard and forbidden in strict mode. Avoid them good to know.
Stick with rest parameters. Finally, execution context, scope chain, and closure.
These sound deep, they are core concepts and execution context is like the environment where code runs includes the variables scope this value. When a function is called, a new context is created. The scope chain, as we said, is how JS looks up variables by checking the current scope, then outer scopes.
Enclosure.
Closure is when a function remembers its lexical scope the variables from the environment where it was created, even when the function is executed outside that original scope, so an.
Inner function can still access the outer function's variables. After the outer function has finished running.
Exactly, the inner function closes over the outer scope's variables. This enables powerful patterns like data privacy, creating private like variables and functions that maintain state between calls.
Closures are powerful. Okay, asynchronous JavaScript promises a better way than callbacks.
Oh, definitely. Promises represent the eventual result of an ACINC operation. A promise object is a placeholder for a future value. It starts an appending state, and then it eventually settles into either a fulfilled state if the operation succeeded with the result value, or a rejected state if it failed with an error or reason.
How do we create them?
Usually using new promise resolve reject inside that function the executor, you perform your ACNC operation. When it's done, you call resolve value on success or reject error on failure.
And how do we use the result or handle the error?
Then and dot catch Precisely.
You chain that on fulfilled unrejected onto a promise. Unfulfilled runs if it resolves getting the value, on rejected runs if it rejects getting the error catch unrejected is just shorthand for that null unrejected, focusing.
Only on errors, and then returns another promise. That's how chaining works.
Yes, each then or dot catch returns a new promise, allowing you to chain asynchronous steps together in a much cleaner way than nested callbacks callback hell. The handlers in then are also non reentrant. They won't be called immediately if the promise is already settled, they get cued.
Very elegant. What about managing multiple promises? Promise dot all promise dot race.
Yeah, useful static methods. Promise dot all promises waits for all promises in the input iterable to fulfill. If any reject it rejects immediately, it resolves with an array of the results.
Okay, waits for all successes.
Promise dot all settled promises waits for all promises to settle, either fulfill or reject it always fulfills, returning an array of objects describing the outcome of each promise.
Safer if you need to know about all outcomes, even failures.
Right. Promise dot race promises settles as soon as the first promise in the terable settles either fulfills or rejects, It takes on the outcome of that first one, a race to the finish and promise. Any promises resolves as soon as the first promise fulfills. It only rejects if all promises reject and it rejects with a special aggregate error.
Useful if you just need one success out of many possibilities. What about serial promise composition executing promises one after another.
That's often just standard dend chaining. You ensure one acinc operation completes before starting the next, often passing the result along a synca weight makes this look even more sequential.
Speaking of timing the micro test queue, how does that affect promises?
Promise dot then and dot catch callbacks don't run immediately when a promise settles, its handlers are scheduled to run in the micro task queue. This queue has higher priority than the main macro task queue, which handles things like set time out or user events.
So promise callbacks run very soon after the current synchronous code finishes, but before the next timer.
Or event exactly. It ensures a predictable execution order for promise reactions happening after the current task but before the browser does other things like rendering got it?
And why is it crucial to avoid unhandled rejection?
If a promise rejects and nothing catches that rejection you dot catch or unrejected handler in a dot catch, then it's an unhandled rejection. Modern environments will log errors to the console, and in some cases, like no JS, it might even terminate the process. You always want to handle potential errors to keep your application stable.
I always have a dot catch somewhere down the chain. What about promise extensions like cancelation or progress? Are those standard?
No, they aren't part of the official trauma specification. Cancelation the ability to stop an ongoing async operation tied to a promise, and progress notifications getting updates before it finishes are things you usually implement with libraries or custom patterns, often using mechanisms like the abort controller, which we'll touch on with fetch.
Okay, so not built in now? Asinc and a weight this is syntactic sugar on top of promises right makes ACYNC code look synchronous exactly.
You mark a function with the acinc keyword inside that function, you can use the awake word before a promise.
And what does a weight do?
It? Pauses the execution of the acing function at that point until the promise you're awaiting settles.
Pauses the function, not the whole browser, just.
The acing function. It asynchronously waits if the promise fulfills a weight, returns is the result value. If the promise rejects a weight, throws that rejection reason as an error.
So you can use try dot catch around awake.
Yes, that's the beauty. You can use standard try dot catch dot finally blocks for error handling. Just like synchronous code, an ACYNC function itself implicitly returns a promise that resolves with the function's return value or rejects if an uncaught error occurs inside it.
That sounds much easier to read and write than loss of dot chains. Where can we use.
A weight only directly inside an acing function? You can't just sprinkle a weight anywhere In regular synchronous code. You might use an immediately invoked acing function expression iiaff e like acink a weight to use a weight at the top level of a module if needed.
Gotcha. So for serial execution, instead of then, we just await, await, await.
Pretty much concer result one will await step one const result two. Await step two Result one looks very linear and clear.
Fantastic. What about running things in parallel with they sink away, but handling errors safely rejection safe parallelization.
Right if you just await promise dot all P one, P two, p three, the whole thing rejects if any of them reject. If you want to get results even if some fail, you could await promise dot all settled, which always results and tells you the status of each. Or you could map your promises and handle errors individually, perhaps using a weight p dot catch EP do or within the mapping or wrapping awights in individual try dot catch blocks if doing them sequentially.
So options exist to manage parallel tasks gracefully even with failures. Great. Let's shift to the browser environment itself, the browser object model BOM. What does this cover?
The BOMB represents the browser window and its features, distinct from the HTML document content, which is the DOM. The core object is which is the global object.
In browsers, and we can find out where the user.
Has scrolled YEP, window dot scroll x or paychecks offset and window dust scrolly or pageops. I could give you the horizontal and vertical scroll positions in pixels.
What about opening new windows? Window dot open pop up blockers are a thing.
Though they are Window dot open ural name features tries to open a new window or tab, but browsers usually block this unless it happens right after a direct user action like a click. You must check the return value of window dot open. If it's null, the pop up was likely blocked.
Good check. Timers set time out and set interval. How do they work with the single thread.
Set time out callback delay runs the callback once after at least delay milliseconds. Set interval runs the callback repeatedly every interval milliseconds. Because JavaScript is single threaded and uses an event loop, the delay is a minimum. The callback actually runs only when the main thread is free after the delay is passed. Set time out returns an ID you can pass to clear timeout to cancel it. Set interval returns an id for clear.
Interval minimum delay not exact. Dot IT navigation, location and history oobjects.
Location gives info about the current url location dot href, location, dot path name, location, dot searchlocation, dot hash, et cetera, and lets you navigate by assigning to location dot h ref or using methods like location dot sign. You all navigates and ads to history location dot replace, heural navigates but replaces current history entry and location dot reload and history history lets you move through the user session history dot backstory, dot forward history dot go in where N
can be positive or negative. History dot link tells you how many items are in.
The history stack, useful for custom back forward buttons. What about the navigator object? What browserinfo does it?
Whole navigator gives you browsersniffinginfo, though user agent is notoriously unreliable. Better info comes from properties like Navigator dot Language, Navigator dot platform. Crucially, it has Navigator dot online booley in for connection status and events online offline. The Navigator Dot Connection object Network Information API provides more tas like connection type, effective type, speed, downlink rtt OTT and a change event.
Network INFOS sounds handy, and the screen object.
Screen tells you about the users display screen dot width, screen dot height, screen dot availwith excluding os interfaces, screen dot color depth, screen dotpixel depth, screen dot orientation.
Good for responsive design decisions. Can we control audio and video via.
The bo yes HTML media elements Audio video have a rich JavaScript API. You can play, pause, control volume, get duration, get and set current time. They fire lots of events play pause and a time update, canplay error, etc. You can use canplay type mime type to check codec support.
Full media control. The URL object better than string manipulation much better.
New url string parses a URL string into an object with properties for easy access to protocol, host name, path, names, search, hash, et cetera. It also has search perms and objects specifically for manipulating query string parameters easily.
Nice and performance monitoring dot performance dot.
Now Yeah, the performance API is key for measuring speed. Performance dot now gives high resolution timestamps. You can create name markers with performance dot mark start task, measure durations between marks with performance dot measure task duration, start task and task and retrieve these entries with performance dot get entries. The Navigation Timing API Performance Navigation Timing gives detailed timings for pageload.
Stages, essential for optimization. Okay, let's switch to the Document Object Model DOM. This is about the page content itself, the HTML structure exactly.
The DOM represents the HTML document as a tree of nodes, elements, text, comments, attributes. The document object is.
The root, and nodes have properties and relationships.
Yep. Node type tells you what it is, element, texts et cetera. Note name gives the tag name for elements. Node value gives the content for text nodes. Relationships like parent node child nodes first child, last child, next sibling, previous sibling. Let you navigate this tree structure.
How do we grab specific elements? To start with? Element by id.
That's a classic for unique ideas. Get elements by tag name gets a live HTML collection of elements by tag. Get elements by name gets a live nodalist by the name attribute. There's also document dot, document element, the h nolande and document dot body.
Right different ways to get elements. How do we change things add or remove nodes.
You can document dot create element tag name and document dot create text node, then use parentode dot a pen child new node to add it at the end, or parentnode dot insert before new node, reference node to insert before another node. Use parentnode dot remove child node to remove and parentode dot replace child new node old node to replace document dot create. Document fragment is useful for building a chunk of dom off screen before appending it all at once for better performance.
Document fragments for batch updates. Good tip what about using CSS selectors dot query selector yes.
Query selector selector returns the first matching element, and query selectora selector returns a static nodalist of all matching elements. These are incredibly powerful on it available on document fragments and individual elements, much more flexible than the older get elements by methods and.
Get elements by class name was added later.
Right get elements by class named it gets a live HTML collection based on class names, also useful.
Okay, we have the element, how do we change its content? Inner HTML, text content, etc.
Inner HTML gets or sets the HTML content inside an element. Setting it parses the string as HTML. Outer HTML includes the element itself. Text content gets or sets only the text content, ignoring HTML tags and encoding entities when setting. Intertext is similar to text content, but is aware of CSS rendering. It omits hidden text and also codes entities differently. Be careful with inner HTML as it can be slow and requires reattaching event listeners to recreated elements.
Good point about listeners. How do we change styles? Dot element, dot.
Style, element dot style accesses the elements inline style attribute. You set properties like element dot style, dot background color red to get the actual computed style including styles from CSS rules. Use window dot get computed style element. You can also access style sheets via document dot style sheets and manipulate CSS rules, CSS rule CSS style directly, though that's less common.
Inline versus computed style makes sense. What about element size and position offset client scroll.
Dimensions to give different measurements offset offset offset with offset left offset top includes borders and padding and position relative to the offset parent client client height client with is the inner size, padding included, border, scroll bars excluded, scroll height scroll width is the total size of the scrollable content, while scroll left scroll top is the current scroll position within the element. Client dimensions are read.
Only different numbers for different use cases. What if we need more advanced dom traversal no iterator and tree walker.
These are for more complex iteration needs. They let you traverse a subtree of the dome, optionally filtering nodes based on criteria you define, especially tree walker, which has a filter function. They give you finer control than simple loops or recursive functions. Sometimes true walker keeps track of the current node.
Specialized tools and DOM ranges selecting parts of the document.
Yeah. Document dot creator range creates a range object representing a contiguous section of the document, you can set its start and end points. Set start, set end. Then you can manipulate that selected content. Delete contents, extract contents into a document fragment, clone contents, and certain nodes around contents. Useful for things like text editors or highlighting.
Powerful selection manipulation. Lastly, for DOM intersection observer and resize observer modern ways to react to visibility and size changes.
Exactly intersection observer new intersection Observer callback efficiently tells you when an element intersects with the viewport or another development. Great for lazy loading images, infinite scroll triggering animations on view resize observer new resize observer callback efficiently tells you when an element size changes, much better than pulling off stwidth constantly. Both are asynchronous in performance focus.
Do you sound like essential modern tools? Okay? Events making pages interactive? DON level zero Level two.
DOM level zero is the old way. Element dot on click will function simple, but only one handler per event type and only runs in the bubbling phase. This inside is the element removed by setting to NOL and.
Level two the modern way.
DOM level two introduced element dot ad event listener type listener, use capture This is the standard. You can add multiple listeners. The third argument use capture boolli in or options object lets you choose whether to listen during the capturing phase down the tree or the bubbling phase up the tree. The default you remove listeners with remove event listener, needing the exact same arguments.
AD event listener is the way to go. When an event happens, we get an event object. What's in it?
Lots of useful stuff? Event dot type like click, event dot target, the element the event originated on, event dot current target the element the listener is attached to. Event dot prevent default, stop to full browseractions, event dot stop propagation to stop bubbling cap Also details like coordinates, client x, clinyy, modifier, keys, feature, l key, old key, event phase, et cetera. Properties vary a bit by event type.
Lots of context. What are some common event types we handle?
Oh tons load for window, images of scripts, unload, window focused, blur or form fields, window, mouse, events, click, TVL click, mousedown, mouse oup, mouse over, mouse out, mouse enter, mouse leave wheel, keyboard events, key down, keep us key at form events, submit, change input, clipboard events, touch events, many more.
A whole universe of events. Can we trigger events ourselves in code simulate them?
Yes, it's a bit verbose. Use document dot create event like mouse events, then initialize it with details using a method like event dot inn at mouse event or newer constructors like new mouse event or new custom event. Finally, dispatch it on an element using element dot dispatch.
Event create initialized dispatch guid. For smooth animations, request animation frame.
How did that work?
Instead of timers like set timeout, use request animation frame callback. The brow sol so calls your callback function just before it's about to repaint the screen. The sinks your animation logic perfectly with the browser's rendering cycle, making animations much smoother and more efficient. It passes a high resolution timestamp to the callback. You call it recursively within the callback to continue the animation loop. Use cancel animation frame to stop it.
Perfect for performance animations.
Okay.
HTML five APIs canvas for drawing.
Yes, the canvas element gives you a drawing surface. You get the two D context with canvas dot get context two D. This context object has tons of methods for drawing shapes, rectangles, lines, arcs, curves with begin path moved to a line to arc et cetera. Filling, fil style, fill, stroking, stroke style, stroke struck, drawing text on fill text, applying transformations, translate, rotate, scale, drawing images, dramage, adding shadows, gradients, patterns, clipping, compositing, global
composite operation and even pixel manipulation. Get image data, put image data wow.
Full two D graphics engine and WebGL for three D also on canvas.
YEP, canvas, dot get context, WEBNIL or webjail two. It's based on OPENNGLS, providing low level access to the GPU for hardware accelerated two D and three D graphics. You define geometry in buffers, write vertex and fragment shaders in GLSL, link them into programs, past data via attributes and uniforms, and then issue draw calls, drawrays, draw elements. Much more complex than two D canvas, but incredibly powerful.
High performance three D on the web. Forms got upgrades in HTML five to two, new types, validation, big.
Time, new input types like email, earle date number with built in UI and validation attributes like required pattern min max, the constraint validation API element dot validity, element dot check, validity, element dot set custom validity, the invalid event programmatic submission with form dot submit. Fans like input change, clipboard events, copycut, paste, ridge text editing via the content editor attribute and document dot exec command, though the latter is getting replaced by
newer APIs. So like boxes also have a good API from manipulating options.
Forms are much smarter now, Okay, shifting to general JavaScript APIs atomics and shared airy buffer for worker community.
Yes. This enables shared memory between multiple web workers and the main thread shared The rebuffer is a buffer whose underlying memory can be accessed by multiple threads simultaneously. Atomics provide special functions atomics, dot ad atomics, dot load atomics, dot store atomics, dot weight atomics, dot notify, et cetera that perform operations on that shared memory in an atomic way,
preventing race conditions and ensuring operations aren't interrupted. Very advanced, high performance stuff for parallel computation.
Shared memory powerful, but needs care. Clipboard API a better way to copy paste.
Navigator dot Clipboard provides an async promise based API right text read text write for more complex data like images using clipboard item objects read. It's generally more secure as it often requires user permission, especially for reading. Also integrates with the copycut.
Paste events, asynchronous and permission based sounds. Safer cross context messaging post message.
Window dot post message message target origin allows safe communication between different windows I frame are workers, even if they're from different origins. The sender specifies the target origin for security, The receiver listens for the message, event checks event dot origin to verify the sender, and accesses the data via event dot data crucial for secure cross domain communication and things like embedded widgets.
It's your window to Window Talk encoding API. Text encoder, text decoder.
Simple but essential. Textingcoder converts a JavaScript string into a U and data array of UTFA bytes by default. Text cooder decoder, dot decode uit data array converts an array of bytes back into a JavaScript string. Handling different encodings useful when dealing with binary data from files or network requests that represents.
Text, handling texting codings properly. Blob and file APIs for raw data and filed.
Blob represents immutable raw data like a junk of binary data. File inherits from blob and adds file specific metadata like name, size, type, last modified usually comes from an input type file or drag and drop file reader reads the contents of blobs files asynchronously to text read as air buffer read as
dator RRL. With events like onload on air. You can create object URLs url dot create creature l blob for referencing blobs files directly in things like MMG tags, but remember to URL revoke objet url when done.
Comprehensive file handling. Full screen API making things take over the screen.
Element dot request full screen ask the browser to make an element full screen requires user gesture usually document dot a inst full screen to leave document dot full screen. Element tells you what's full screen full screen change event fires when state changes. Good for videos, games, presentations.
Immersive experiences. Geolocation API finding the user's.
Location navigator dot geolocation methods get current positions success ab air CB options and watch position success CB air CB options needs user permission. Success callback gets a position object with chords latitude, longitude accuracy. Error callback gets position aer codes for permission denied, unavailable, timeout, use eaht TPS. Be mindful of privacy.
Permission and privacy first. Other device APIs orientation network info.
Yeah, we mentioned navigator dot connection for network details. Device orientation events. Device orientation, give alpha beta gamma values for physical orientation if hardware supported. Others like battery API are mostly deprecated. Provides context about the device environment.
Good context fetch API the modern way for network.
Requests absolutely fetch EARL options is the standard. Returns a promise that resolves to a response object. Options object controls method header's, body, credentials, cash, mode, et CETERA response object has methods to read the body response dot jason, response dot text, response dot, blob, response dot orra buffer. You check response dot OK or response dot status for success.
Handle's cores via options and server headers. Integrates with request header's objects can be aborted using a board controller and a bort signal. Can work with dreams. Integrates with the cache. API caches for service workers. Far superior to XMLHTTP request.
Fetch sounds like the complete package. Web sockets for real time communication.
New web socket are established as a persistent two way connection. Ws dot, WS or WSS use eventhandlers dot on open on message gets data in event dot data on air on clothes send data with socket dot, send doses socket dot close. Great for chat, live updates, multiplayer games. Doesn't use ad event listener style. You assigned handlers.
Directly persistent connections, web storage, local storage, session storage.
Simple key value storage. In the browser. Local storage persists across browser sessions. Same origin. Session storage allows only for the current tab. Windows session both have set item key value, remove item key clear length limits around five to ten mil us storage event fires and other tabs. When storage changes stores values is strings.
Simple key value stores.
Then for more complex data, index dB.
Yes INDEXTB is a full transactional NOSEQL database in the browser, stores complex JavaScript objects, files, blobs, asynchronous API. You work with databases object stores like tables, indexes for query transactions, cursors for iteration. Open with index dB open name version, schema changes happen in the unupgrade needed event powerful for offline apps and large data sets.
A real database in the browser. Okay. Modules organizing code ES modules versus the old module pattern.
Module pattern used iiv's enclosures to simulate modules. Es, modules, import exports, script type module are the native standard, much cleaner syntax, static analysis benefits, better dependency management. Named exports export x inport x, default exports, export default y, import y, dynamic import phrase incloading import maps for controlling resolution. The modern standard.
Native modules are the way forward. Web workers background threads yes.
Run jas off the main UI thread to avoid blocking dedicated workers. New worker for a single script, shared workers, new shared worker accessible by multiple scripts same origin. Service workers act as network proxies for offline support, push notifications, et cetera. Communicate via post message and on message. Data is copied, structured, cloning, or transfer transferable like a ray buffer. Each worker type has different scope in life cycle.
Essential for performance parallelism in the browser. Important error handling and debugging stayingsane.
Use try, dot, catch dot finally, throw errors with throw new error or specific types type er, et cetera. Handle global errors with window dot one, air, use browserdeb tools extensively, console debugger breakpoints, stepping, network panel, static analysis linters. Typescript helps catch errors early assertions can help during development. Robust error handling is key.
Good practices are essential. Finally, json stringify.
And parse Gson does stringify value. Replacer space converts a JS value to a JSON string. Json Dot parse text Reviver parses a Jason string back into a JS value. Replacer and reviver functions allow customization during serialization de serialization. Space argument pritifies the string output ubiquitous for data exchange, especially with apisvia.
Fetch perfect, and we covered fetch for the actual sending earlier.
Yep fetches how you typically get that Jason data from a server?
Wo Okay. That was a seriously deep dive into JavaScript and the web platform. It's a massive ecosystem.
It really is so many layers, from the core language features to these incredibly powerful browser APIs, and they all interconnect.
Yeah, hopefully this gives you, our listener, a really solid map of the territory, a framework for understanding how all these pieces fit together in modern web development.
It's definitely a foundation you can build on whether you're focusing on say React or view or maybe no JS on the back end, or getting deep into specific APIs like WebGL or web RTC.
And it just keeps changing, doesn't it. JavaScript and the web platform are constantly evolving.
They really are. Which leads to a final thought, maybe, given everything we've touched on today, this huge landscape, what's the one area of JavaScript or the web platform that really sparks your curiosity right now?
That's a great question for everyone listening to think about, where do you want to explore next? Keep learning, keep building. Thanks for joining us on the deep Dive
