What do you want to learn?
Leverged
jhuang@tampa.cgsinc.com
Skip to main content
Pluralsight uses cookies.Learn more about your privacy
JavaScript: Advanced Fundamentals to jQuery & Pure DOM Scripting
by Alexis Abril and Justin Meyer
Gain an advanced understanding of difficult JavaScript concepts like closure, new, “this”, prototypical inheritance, type comparators, coercion, and delete.
Resume CourseBookmarkAdd to Channel
Table of contents
Description
Transcript
Exercise files
Discussion
Recommended
JavaScript Basics
Introduction
(Introduction- music) Alexis and I, we do JavaScript consulting for Bitovi and in the last like, seven years I've been doing this, we've worked for about 30 different companies and I've seen so much that people will start to become a JavaScript developer, but they'll never spend time really learning the fundamentals, they'll be a jQuery developer but never learn the DOM, so this two day training really tries to change all of that. I really love questions, so people kind of online, people in the room, please, at any moment if you have a question, concern, just ask it. I really want to answer it. So the agenda for today is we're going to really be covering, for most of the day, covering the basics of JavaScript. We're going to talk about how, like where JavaScript is, kind of like in the environment of the browser, we're going to be mostly focused on JavaScript in the client. We're going to talk about, you know, JavaScript is a language, with commands like if, switch, that thing. But we're mostly going to be talking about types and operators in the beginning, really understanding the data structures that JavaScript provides, and kind of how it builds those structures in memory. We're going to talk about the difference between the double equal and the triple equal operator. You're really going to understand the difference exactly and precisely. We'll have lunch, which will be great. Talk about then closures, how like, every language has a stack and closures are very similar to stack and we're going to understand that difference. And then we're going to talk about what this means, which most people don't, they think they understand, but really don't, and it's much more simple than you think. And then finally talk about prototypical inheritance, and we'll start our DOM and jQuery stuff at the very end of today, and tomorrow will all be about that resulting in us building that tabs widget I showed from the first slide. So again, we both work for Bitovi, if you want to follow us on Twitter, that's where we are, we like followers. @justinbmeyer and @alexisabrill. And I was just saying we've built a lot of different applications, and we do JavaScript consulting, training, and we do a whole bunch of open source work. If, when we're not talking about JavaScript and DOM, if people want to ask questions about this, happy to answer about questions about those as well. So, at this point, everybody should hopefully be setup, you should open in your browser, tags.html. So exercises/JS/tags.html and exercises/JS/test.html. So I have these open... Like this, tags will just be blank and the test page... Should have a bunch of breaking tests. And then in your IDE, you should have... Open tags.html, this will be where we do our first very small exercise, just kind of like a almost like a hello world. And then we'll be doing everything else, almost everything else today in this my_js where we'll be building kind of our own implementation of the dot operator, the instanceof operator, the new operator, making sure we really understand how JavaScript works. So with that, let's, yeah, so just to show I've got these, that's what they look like. tags.html and my_js.js.
Basic JS
The basics of JavaScript, and this is really just a high-level overview of JavaScript, how it operates in the browser, that kind of thing. Our goal, and then we're going to go into all of these things, our goal really today is to show you how the sausage gets made. My first question to the audience is is this JavaScript? Would you consider this JavaScript code? Yeah, some people nodding their heads yes. This is kind of a, it is and it isn't because the one thing that a lot of people are confused with when they begin JavaScript development, is not understanding the difference between JavaScript and the DOM. What we'll see is really a lot of this is the DOM, but the DOM's implemented in JavaScript. It's the only implementation that matters, but we'll just kind of break down what the technologies are and how they're used in this presentation. So what is JavaScript? JavaScript is a language, right, it's an entire complete language that you use to essentially move data around. And there's HTML and that's like when you go to a website, it's just sending back an HTML document, almost that you can think of it as a string. And what kind of hooks these two worlds together is the DOM. The DOM doesn't actually have a logo. People when they hate JavaScript, they really tend to hate the DOM, that's why created a really ugly logo for it because it doesn't have a logo. The DOM is an interface that is supposed to be language neutral, so like if you had a Ruby program or you had something written in C, you could potentially have a DOM API for it that allows you to manipulate HTML, listen to event handlers and things like that. But fundamentally, that document getElementById is supposed to be an interface, it's just one that JavaScript implements, so we'll see how these things relate a little bit more. So to the best of someone in the classroom hopefully's ability, what do you think happens if I go to a page, helloworld.com/index.html, it's going to return back this HTML. What's going to happen? As specific as you can be. Anybody adventurous enough to do this? You'll get a pop-up that says hello world. Good, but can you break it down even further? No. So like what I mean is by breaking it down further, not necessarily what's the outward appearance to the user, but what's happening inside the browser? The page renders first and I am assuming that you get the pop-up after the H tag is displayed. The pop-up after the H1 is displayed? Yeah. That's good, you're thinking the right way about how things get shown in order, but the whole situation's a little bit more complex than that, so I'm going to try to break it down, and while I'm doing this, apologies if these fonts are a little bit too small. I tried to make them as big as I could yesterday, but I will talk through it. So when the user hits Enter in the URL to go to that page, the browser's going to send an HTTP request to a server, right, so it's going to make a GET request for content to a server, and the server's going to respond with an HTTP response. In it, it's going to include the body of the response. And that's going to be the HTML that the server is returning with, that's going to look like in some ways a string with an HTML, head, essentially what we showed on the previous page. The browser is going to pass it off to its, when I say the DOM, I mean the Document Object Model, it's going to pass it off to something like WebKit that will start processing the HTML. It'll parse it, and then it will start building DOM elements up one-by-one, right, so it'll see an HTML element, it'll build a document element. Then it'll see a head element, and put a pin to head element to it. And then it'll see a script tag, and then it's going to kick off to the JavaScript interpreter. This is something like V8, this is what processes JavaScript and it's going to pass that hello world to JavaScript. JavaScript is going to tokenize it, so it's going to break it down into words essentially, and then it parses that into something like a structure like this, an abstract syntax tree. This is kind of an intermediate representation of the code. And then essentially it's going to do various transformations of that to essentially something close to like bytecode, really something that the machine can understand, and then it's actually going to run the code, it's going to look up alert, and then it's going to call alert with hello world. This is kind of high level what a JavaScript engine is doing. When the alert is called with hello world, it's a pop-up is going to be shown. It used to be this was like a system call that would actually show alert hello world on the page, and it's just going to freeze JavaScript until the user, and all processing, the browser's totally going to freeze until the user hits OK. And then it's going to go away as you can see in the top left corner, I have it going away when the user hits OK, and then the DOM is going to take over again, and it's going to... See the closing script tag, the closing head tag, see that a body tag has been opened, add a body, then add the H1. You've got a question? Yeah, a couple of questions, will DOM content ready or DOMContentReady or DomContentLoaded run exclusively before the script is executed? It will not. So the answer to that is well, DOMContentLoaded won't execute until the body, the end of the body, until all HTML in the document has been processed. Is there another one? That's it, okay. Oh, well, yeah, there's a few other, I mean besides WebKit, what are the other DOM creation engines? I don't know the names of them anymore, the modern ones. I'm sure you can look up, I don't know what there's-- Someone else answered, Gecko, Firefox, Trident, IE. Yeah, Trident was the IE one. But they have a new one I thought now. It's not Trident anymore, maybe not. Any other questions, or should I continue on? Yeah. When it hits that script tag, it stops, leaves the page, runs through all the script. It doesn't necessarily leave the page, it just stops processing other elements in the page. So one thing is commonly said about JavaScript is it's kind of single threaded, there's only one thing happening at a time, so JavaScript won't keep processing the body while there's JavaScript being compiled essentially and executed. Is that why the script tags are typically at the bottom of the page? Is that why what? Why they're at the bottom of the page typically. The script tags. That's exactly why, I was just about to say that's why you should typically bottom load your scripts and a lot of times people top load your CSS, because you want all of your elements built something visible to the user before you have to spend time loading JavaScript and that kind of thing. Cool. So yeah, the H1 would be produced and then the H1 would show up in the page, it'd show hello world, what you expect. So a little bit about, so that's just how JavaScript kind of high level operates in the browser, the nature between it and the DOM engines. Justin, quick could you explain blocking a little bit more, there's a few questions I had about that. Sure, blocking as in blocking... The JavaScript just blocks any other execution happening on the page? Yeah, I think that's, yeah. So, I'll try to rephrase it, I'm not sure what about it I can explain-- Well you say alert is blocking. Oh, okay, so again, so until, so alert, yeah. Alert, okay, whoops, I stepped on my cord here. So if we had an alert and then anything else after it, the browser won't run JavaScript code until the user has clicked OK. Essentially the code that's running is hung up until the user hits OK, and then it starts running JavaScript code again. Hopefully that answers the question. So just kind of interestingly, there's not really another way you can do something like this, as far as I'm aware, but if I do alert(foo) and then I have just something like you know, let's say even throw an error or something. You know until, if this code is all running here, I won't throw the error until this code has finished running or until the user, not only this code is finished running, code kind of finishes running when the alert is shown, but until the user actually hits OK, the next line will not be ran.
JavaScript Features
Most people now are relatively familiar but, or know these facts about JavaScript, but just to clear up because there's a lot of misconceptions about it, at least a couple years ago, JavaScript is not Java even though it looks the same. JavaScript is a real programming language. People would say it's like a toy language. No it's a real, there's big, big applications and big software has been written in JavaScript. JavaScript is kind of a synonym for ECMAScript. ECMAScript is a standard and JavaScript is like a trademark name, but if you say ECMAScript, JavaScript, IE's version of JavaScript or Microsoft's version is called JScript, these things are all synonyms. If you see one, they all mean about the same thing. Typically if you hear someone talking about ECMAScript, it means like a standard that's coming out for all the different browser vendors to implement. And then JavaScript again is not the DOM, although they are kind of made for each other at this point. Okay, so some things about JavaScript the language, that separate it from other languages. And these are the things that I actually really love about the language. The first is JavaScript is dynamic. So, when you have most other language, like compiled language, something like C, what happens is the, you'll write your C code, and you have to compile it, and what a compiler will do is read that code and kind of convert it into Bytecode and then when you execute that, it's just that Bytecode is loaded into memory and then just the computer just goes instruction instruction down in memory and is just reading through memory and operating on some other memory somewhere else inside the computer, there's just like a block of, there's a block of memory for code, and there's a block of memory for everything else that the application might use. JavaScript and dynamic languages like it are amazing because in some ways you're coding your code. With JavaScript or like what jQuery does, jQuery might have a property map like this to create its val in HTML function, and then might iterate through those properties generating its val in HTML function, and so here I'm going through every property and prop map and I'm setting $.prototype to essentially be equal to a function that will call on whatever this is value or inner HTML. This isn't exactly what jQuery does, but it's similar. You'll see this code a lot in a lot of different libraries because you're actually building the structures using the language, which you don't really see in compiled languages, and this is, I really love this nature. So in JavaScript if you were to look at like when the program is running, there is no distinction between the memory that's used for code, and the memory that's used for like data. So that's kind of what dynamic languages give you. JavaScript is also weakly typed, hopefully most people are kind of familiar with this aspect of JavaScript, which is sometimes a bitter pill but also sometimes very nice is that you can create a variable and assign it to any type of thing without an error. It's because you can think of data in JavaScript as like a little, instead of just raw data, instead of just a number in memory, JavaScript data looks like it's like a little packet, it has additional information, it has this data is a number in memory, and then it has this data, here's the number associated with it. So type travels with a value, and not with a variable. We'll see what this means in a little bit. We're going to break all these things down actually quite a bit. JavaScript has first class functions, this is another one of my favorite features about the language. Anything you can do with an object in JavaScript, you can do with a function. So I can create a function... I can return a function from within a function and I can pass functions as arguments. And then I can of course at the very end, call a function, which is what most languages give you. This is dynamically creating a language. It's a little bit different than it being statically created. And then finally, JavaScript is prototype based and we're going to do a whole hour on this, and really get to understand what this is doing. I'm not going to go into it in detail right now. So in summary, JavaScript is a, basically JavaScript is... In summary the DOM is a JavaScript representation of the HTML and a browser. It's there for you to kind of manipulate in HTML page, change what's going on inside of a browser. It's an interface provided to JavaScript. And then JavaScript itself is a language with all of these kind of interesting quirks that we'll spend today really deep diving in...
Data Types, Operators, and Primitives
Data Types and Operators
For those that are just joining us, we had a little transition. My name is Alexis Abril. We're going to talk a little bit about fundamental constructs in the language in JavaScript. Everybody's favorite part, Data Types, what kind of keywords we're going to use, what they mean. We're going to go through a little bit of the groundwork as we start to build up our knowledge with language. So, first off, we have our basic Data Types. You can think of these as the chemistry of JavaScript. These are divided into two categories. We have our Primitive and Object or Composite Data Types. Every language is going to have this kind of set up. JavaScript is a little unique in a few areas. One everybody's pretty much familiar with is a String, what that refers to. In JavaScript, we have Undefined and Null. This is kind of nice, but they are somewhat confused and mixed up from time to time, especially if you're using something double = Null or Undefined. A lot of that will trip people up. Undefined is actually going to refer to a Pointer that points, that hasn't been set. It's, by the literal definition, has not been defined yet. We have not set this variable. Var foo; This will be Undefined, or if you're trying to use any kind of variable in memory that just hasn't been set yet. Null is actually referring to the Null Pointer. I like to think of it as, if you come across Null in a piece of code, it's by intent. Something has manually set this to be Null, versus Undefined which hasn't been declared, maybe it's a mistake. Null is typically that zero x zero in any kind of stack. Booleans and Strings, we're pretty much familiar with those. Numbers, in JavaScript we have numbers as opposed to like a statically-typed integer or a floating point or a big Int. Numbers are, in this case it's going to be an integer, but typically referred to as Floats. Then we have our Composite Types. Objects, which is our Hash, it's our key value pairs. We're going to get deeper into what Objects can really be. We have Arrays, which is just slightly more advanced Object construct. We're going to show a little bit what that looks like in memory. Dates, Date times, everybody has a Date construct of some point. Regular Expressions, which I'm sure are everybody's favorite for using, or solving problems, or adding problems, depending on how you look at it, and functions. Functions are kind of unique, as we were talking about earlier. Functions are first class in JavaScript. We have the literal definition of what that means. We're really going to get to experiment with how powerful, and how expansive functions can be. Do we have questions, yes, go for it. What about NaN and also the ES6 symbols? Not a Number. We're not going to talk about any ES6 symbols. I'm assuming you're talking about things like Rocket Syntax, and those types of Operatives. Symbols actually. Yeah. Oh. We're sticking to the well supported image. Yeah. So symbols isn't in most browsers yet. We'll hit that like a year from now. That's true, that's true. Most of what we're going to cover is kind of just the cross browser, the most modern acceptance of a standard, if that's a way to phrase that. Something that's applicable across all environments. Not is a Number is a number. It just returns false. It returns true if you put it through is Not a Number. For the mic, the question was what about the Not a Number Type. It is a number was the response for the people at home. If you do interject, can you speak loudly? Yeah, I'll try to. Thanks. Cool, any other questions? Good so far? Right on. So these are our basic types, these are basic constructs. So if you're thinking of this as the chemistry, maybe we have a little bit more of the physics of what makes things possible, what brings these constructs together. Those are our Operators. We're not going to go through every reserved word in the language, but we're going to touch a few of the big ones here. Var is how we declare variables. Remember, JavaScript is a weakly-typed language. So we don't care necessarily about the type on the left side. Instead of saying Int foo, we care about the value it's being assigned to. So here we're just declaring a Pointer, just Undefined. New, this is how we're going to create new Objects based on some kind of constructing function. In this case, maybe Foo is a constructor. If we really want to invoke this, it would be new Foo, open, close. So Foo and then the calling of the Foo function. Assignment, we're talking about the Equals Operator. We're taking a Pointer and actually assigning an Address to that variable in memory. So we're going to tell, in this case, we have some Object, some Hash representation in our memory stack, and we're going to point the Foo its own Address. This is weird what I'm saying, Address, because we actually have a visual here on a couple slides. We're going to take Foo's Pointer and point it to this Object somewhere else in memory. Same thing, if you have foo.bar. Foo.bar is its own place in memory, and we're going to point it to some new, to some other reference, which is value. Delete, delete's a special keyword. An easy way to describe this from a high level is it does exactly what it sounds. What it really does, the deleting of a Pointer, or a reference, in this case, is really just an observance of behavior. There's no real deleting necessarily going on behind the scenes, and we'll show what that means here in a second too. We have our Member Assignments, if you're using the Dot, or if you've seen the Bracket Syntax. How many people have never seen this Bracket Syntax before, where you have a Bracket and then a String within that? Is everyone familiar with that? These are actually doing the same exact thing, but this is a really, really nice feature. We're all probably familiar with seeing this in Array Notation. You can do this in Object Notation as well, to look for any property that is on a given Object. Then we have our Call. Call is this first line here, this open-close paren, whenever you're invoking a function. .call is just invoking a function that's a member of another Object. We're going to get into why that distinction is important as well. Then we have our Comparison Operators. Double Equals, Triple Equals, Greater Than, Not Equals To, all kinds of different Comparison Operators. Double and Triple are a very, very important distinction. Many of us have probably at least heard along the grapevine, we shouldn't use Double Equals. We should always use Triple Equals. One is faster than the other, but we're not really sure why that is. We're going to show you why exactly that is, and what kind of performance impact something as simple as using one Comparison Operator over the other will have on your applications. I'd like to interject two things. You should be interjecting on me too. You don't have to use the parentheses with the new Operator. They're optional. Oh. Then the Delete, just to kind of rephrase a little bit, it deletes a property and we'll see it in a second. It doesn't actually delete the data. So if there's a foo.bar = something Object, it doesn't actually delete the Object, it deletes a reference to the Object. We'll see what that means. Yes.
References
Let's observe a really simple set up here, and kind of think about this out loud. Here we have me, which is this new Object. It's going to have a name, and it's going to be another Object with a first, and a value of String justin. So me.name.first will be justin. Then we're going to have a second declaration which is name, and this looks like it's just going to be a shortcut to name = me.name. So name, we're going to reassign it down here to a new Object called {first: "alexis"}. However, at the end of this whole execution, me.name.first is still going to be justin. Does anyone think they know why this is the way it is? Different scope? Different scope, ok. Yeah. Ok. How many people look at this and say this is crazy, that slide's wrong, hold on, let me type it into a console? No, nobody, alright. We're going to deep dive and break into this on why things are assigned the way they are. Why this actually results the way it does, with nice graphics in memory. So, to break this down, let's talk about how things are assigned in memory. We're going to talk a little bit about reference and value types. If you've ever heard something by reference, something by value, we're going to get a little bit into that now. This, my disclaimer, this is a very-- We're going to get into a really simple implementation of a memory stack in a browser. Inspired by V8's, but this is not V8's implementation. Browsers today can do really, really smart things with memory allocation, but we're going to pretend this is like 1995 and we're inventing something. So, here we have the statement above, var str equals this Primitive String, "hi." Here we have our blank memory stack. We're going to use this as a graphical representation of what we have in memory. This will be our Call Object, or our global scope. So this is where we're going to start. This is the initial representation of what we have in memory. We've opened the browser. It hasn't really done anything yet. We haven't executed any code. The way the parser is going to come through this is it's going to see this Primitive String "hi," and the first thing it's going to do is it's going to add it out there in the scope. We just have this String in memory, and it's going to give this an Address. So here in this case, we have 2001. It's going to say what type it is, it's type String. The length perhaps, and then the actual value. This is where it's going to be in memory, but nothing is really linking this up. It's just something in space. Then, the parsers are going to come across the var str. So it's going to create our str Pointer in memory. That's all it's going to do. It's just a Pointer pointing to nowhere. Right now it's technically Undefined if you were somehow able to stop it here. It's going to declare a Pointer, give it its own Address, but that's all it's going to be is a Pointer to nowhere. Then the real magic happens with the Assignment Operator. The Assignment is going to take that Pointer, and now we're going to have an Address. At 1003, it's going to say hey, str points to Address 1003, or I'm sorry, 2001. which is going to give us its type, any arbitrary properties, and its value. This is a really simple implementation of how Primitives are used in memory. Does that make sense to everybody? It's a little bit different way to look at things, but it really helps to understanding reference versus by value. Let's take a little bit more complex example. So here we have, we're going to start with our clean slate at the bottom. We have var obj and we're going to create a new Object. We have obj.txt, we're going to assign some key to this Object and set its value to some Primitive String. So we're going to start at the same point. The parcer's going to come to this curly brace first, and create a new Object in memory. For our purposes, for most of these slides, we're going to denote these with circles. This will be a new Object in memory. It will just be a circle. Then we're going to create its Address allocation. We're going to say hey, we have an Object. It doesn't have any properties. This is where it's going to live in memory. It's going to come across to the other side of the coin. It's going to say hey, I have a Pointer obj. Let's create that in our scope. It's going to be at Address 1002, and we're going to assign it this 2001 Address. Obj as an empty Object that lives at Address 2001. Then we're going to come down to the next line. Parser is going to come across, see our Primitive String, do the same thing it did before, create a Primitive String in memory. Give it its own Address. We have String with its length, its value, down to 2101. It's going to come down to obj. On the second line, come across to our .assignment. This is going to create our new txt Pointer, which is going to point to our Primitive String, "hi." It's going to increase our properties to one. We're going to get a new Address assignment. 2003 is our txt Pointer and its Address is going to point at 2101. This is where txt lives in memory. So you can think of a HashMap in memory as just a bunch of Pointers telling you where its real values are. At a very high level. So far so good? Sure. Clarification. So the diagram demonstrates variable containing a Primitive value, uses its own storage space, so values based on such a variable have a completely different storage location? Say that one more time. I think what people are asking for is clarification on the Call Object in the variables and what's going on there. The Call Object in variables. When you're creating a new String, I guess maybe I still don't understand that question. Go back to the-- Let's go back to the first slide. To the first slide, yeah. Right after the String is allocated, but before the str variable is allocated. Ok, so whenever you're running JavaScript, any time a variable is created, that variable is really like a Pointer. It points to some data somewhere. All those Pointers need to be captured in something. So when something else is looking up str, it looks up, hey what's the value of, where does str point to. Ok, now I've got the value of the String. So, every script tag, when you just have a script tag and it's got some code in it, it runs in a context of some sort. What you guys might call context. Another name for it is a Call Object. A function has a Call Object, but there's a global Call Object and that's the variables that the window has in it. Alright, so when str, when a variable is created, it always goes in a structure, right. We draw it over here, in kind of 2-Dimensional space, but it's also kind of captured in memory that we show in here, right. So we'll see that when we execute a function, another one of these things get created too. We'll understand it better later, but that's when it's there. Just think of it for now, where variables and their Pointers go. That's what a Call Object is. I'm going to paste a link to an actual discussion I had with someone in the V8 team, to give you what is actually going on, but this is, I worked it through with him. This is a good enough representation that you won't get the answer wrong for what JavaScript's doing, but the reality of this is a lot more complex, but this is a good rule of thumb. So I'll post that. Cool, right on.
The delete Keyword
So earlier we were talking about what is Delete doing. Delete's removing a key from our Object. Is it really deleting data from memory? What's going on with Delete? So let's take a look at one of our examples from earlier. We have me, name, first is going to be justin. Then we have a reference, name = me.name. Our little shortcut. Then we're going to call Delete, me.name. Then name.first is still going to be justin. Really quickly, does that look weird to anyone first? Got a few nods, yeah that looks weird. This isn't right, this guy's lying again. Let's type this into a console. Let's work out in memory why this is the way it is. So, we're going to take a little graphical example here on the side of what's going on in memory. Here is our window. This structure is going to be created from the first Object, from me, name, first. We're not going to talk about the second one just yet. So me is a Pointer to a new Object in memory. That Object has a Pointer called name, which is going to point to another Object in memory, which has a Pointer called first, which will lead us to our Primitive Justin String in memory. So this is the path we're taking. We have our scope, we have a me Pointer and two Objects, ending at a String at the end of the line. So far so good? This is the road we're going to travel down. Now, name is another Pointer. Right off the bat, var name is another Pointer in memory. So that's going to start here and it happens to point to our first Object. This is a little bit easier way to kind of consume this information. So when we call Delete me.name, that's the Pointer that we're removing. I don't know if you guys can see that animation. It's really subtle. I'm going to dare walk away from the podium here without tripping on any wires. This reference, this link is all we're removing. When we call the Delete keyword in this line of code right here, deleting me.name, this is the Pointer we're going to remove. So when you have name.first, this path is still intact. So realize if Delete was actually deleting data from memory, I would probably expect this entire Object to be removed, to be cleaned up, but that's not actually what's going on. You're actually just working with Pointers. Either reallocating, reassigning them, or removing them from memory. Does that make sense? Did that clear things up a little bit? There's probably going to be some weirdness when you're working with the Delete key, where you're not seeing maybe what's going on behind the scenes. This is actually one of the things that's going on. So basically, just expect that Delete is going to delete a reference, not delete a value. Yes, most of what you're working with in JavaScript is with Pointers, so that part alone trips a lot of people up, right off the bat, because the same thing is going to happen with, when we're talking about me and name, the same thing is happening with assignments. We're going to show that here in like two slides, why that first slide was really, really weird too. It's just being able to understand, or remember that things are just pointing to places in memory. A lot of times when I'm dealing with modules in a large application, or application I haven't worked with or even something I'm just building for the first time, I'll draw stuff like this out just for my own sake, like oh, that's what's going on. It makes it really, really easy to understand seemingly more complex concepts. What would happen if you deleted me? What would happen if we deleted me in this context? So, me is our Pointer to this Object. So if we called Delete me, what do you guys think would happen? Yeah. The me Pointer would go away and then that Object would get garbage collected because there's no references to it. The me Pointer would go away and that Object would get garbage collected, ok. Ok, any other thoughts, concerns? No, this part-- Go ahead. There should still be a reference to it through name. There would still be a reference, oh ok, because you're saying even if this is deleted in memory, this would still exist. Yeah. That part's true. That is a true statement, with the if condition before that. No, that's not true. Me is referencing the name Object, but name does not reference the me Object. So the me Object-- Well, it depends. That second variable, name does. That references the name Object, but it doesn't actually reference the me Object. Oh ok, yeah, yeah. Right, immediately after it's done, yeah. I misunderstood. I was saying this one will be removed. Yes. The trick is, neither will be removed, Yes in current browser implementations. Correct. Delete is only going to actually remove attributes on an existing Object, not the Object itself. Me is pointing to an Object itself. So this something where, if you really wanted to have the garbage collector remove it, you could say me = Undefined. Then the garbage collector will be like oh, this isn't being used anymore. If there's no hooks to it, if nothing is needing that, has a reference to that me variable, then the garbage collector will just come along, but deleting yourself isn't something you can do. I feel like there was one browser way back in the day that let you do stuff like that. But here's the one other thing. Sure. Just to be clear, when you delete me, it doesn't do anything. Delete actually returns false. So you can't actually delete a variable. It won't remove the variable from the Call Object, and it will not set the point to Null or Undefined, or anything like that. The interesting thing about Delete, it does return true or false, but it only returns true if your Syntax is right, if there's a Dot Operator, really. If you did delete me.name here, it would return true, and if you immediately followed that with delete me.name, it would still return true. So the return doesn't tell you if it did delete anything. It's like, could there have been something deleted there? It returns true. If you just did delete me, it returns false. Like I couldn't, this is wrong. You gave me something wrong. That's how Delete works. It's confusing. I don't know what else to say about it. (laughs) It's a very special animal. A good rule to live by with this is if you're focused on dereferencing attributes of Objects, of existing Objects. That's really only what you need to use it for. So if you wanted to say, delete me.name, if you wanted to remove some key from an existing Hash, and not the Hash itself, that's really what you would use this stuff for. Does that make sense? So just to recap, if we do delete me, name.first no longer works. Name.first will still exist. Me will still exist. Ok, ok. That's the really weird part (laughs). So after deleting me, if you do me.name, you'll get Object? If, for deleting me, yes, yes. You would still get the Object. You would still get this first Object up here, yeah. (sneezes) Bless you. Is that weird? Who thinks that's weird? I think that's crazy. So, this is one of the weird parts, but it's always good to understand, because especially if you're building a rich JavaScript Application, you're probably going to have a need for this keyword, or feel a need for this keyword. Be aware of what kind of behaviors you're going to get into, especially if you're wrapping some kind of condition around, well if it was deleted, do this other thing. That's not going to respond the way you think it's going to respond.
typeof
Typeof. So because JavaScript is weakly typed, we do sometimes need to figure out what we're working with. If we're checking arguments, we want to validate inputs, things like that. We do have a couple of reserved words to help us out. Typeof is one of these, but it can get a little weird as well. So, here's a basic table of a few things that we would expect and a couple things we wouldn't expect. Typeof Undefined. This is our unreferenced Pointer that we have set up. Undefined will be "undefined." That's fairly straightforward and expected. Typeof Null will return "object." That is really weird and unexpected. Typeof Boolean, Number, those are expected. Not a Number, this answers that question earlier as well. If you say Typeof Not a Number, that's going to return a number, which Not a Number returning a number, by the English definition is a contradiction. Strings will be "strings." Functions will be "functions," even though functions inherit from Objects. Functions are the special case in JavaScript. Arrays will be "objects." What's funny is Typeof Array being object is, out of this whole table, out of any applications I've worked on, Typeof Array = "object" as a condition, like I want to make sure an Array is an Array, that's probably the biggest offender in applications I've seen, like oh, this if statement is wrong. It's not going to do what you expect, but out of this whole, out of any of the weird items in this graph, that one makes the most sense to me, for some reason. Let me show you, let's talk about what an Array looks like. We'll ad hoc here in memory. I'm going to pop open an IDE for you. So, we think of Arrays really as this. Very simple kind of set up. Let me make this giant. This is our basic Array. I'm going to use letters instead of numbers, because this is going to get weird, a, b, c. This is our basic Array set up, and when we expect this to be-- When we say Typeof Array and this returns "object," that's a little weird when we say it aloud, but let's think about what an Array actually looks like in memory. So the Array construct is just a nice abstraction for us to handle this kind of concept. What it really looks like in memory is something more like this. Then we have some stuff like length. Then we have really, way up the proto chain, we have stuff like, really way up the proto chain. Slice. Actually this will be, if you want to get technical. There we go. You can think of an Array as looking something like this. An Array is just a Hash. It just happens to have-- The keys are just going to be integers, or numbers. Zero, one, two, three, these are the indexes of the Array. Those indexes are going to point to what values we actually have in the Array. Then we get a bunch of helper methods and properties like length. We walk up our proto chain and we're going to talk about what that means here a in a minute. It's got a bunch of helper methods like slice, and splice, and all those, push, and pop. You keep walking up the proto chain until it gets to the base Object and you're going to have stuff like toString, like the base, toString method. This is what an Array really starts to look like. So when say Typeof Array equals an "object," I'm like, oh, that makes sense, it inherits from Object. A way I think of it is Typeof is always going to return the most base type, except for functions. Typeof Function will return "function." That's the special case. So if you have Typeof, and you have a custom constructed Object that you've made, Typeof That Object will be "object," regardless of how many levels, where ever you inherited that from, etcetera. For the most part, it's returning that hidden type. Yes, yes (laughs) sorry. Well, we're going to talk about that when we have a debugger here open in a second too. Does that make sense? So if you really want to check if an Array is an Array, there's a couple other keywords, and we're going to get to those here in a second too. I don't want to jump too far ahead. Any other Object-- Yes, go ahead. Isn't everything in JavaScript considered an Object? So, that is a really commonly way to think of things now. It's a really popular way to think. Everything is an Object. If you have String, you have methods on the String. I prefer to think of everything in JavaScript as, from my perspective, I would say everything in JavaScript is a Pointer, because everything you're working with is actually just a Pointer referencing something else in memory. You do have things like, you're going to have a method on a String. That's not the same as creating a new String, if you use the capital S String construct, that's going to return a little something different. So I prefer to think of everything, at a very, very base level, everything is a Pointer, because that's really what you're working with. You're working with a bunch of var somethings that are pointing to something else in memory. The Pointer itself is not an Object. Does that make sense? Yeah. That's the way I like to think about things. Good question though, good question.
Summary
So to summarize all of this. Variables are put in a Call Object. This is our Call Object visual representation here in blue. We're going to say var me. This is going to be assigned to our new Object with the equals. That's what it's going to set our Pointer to our Address in memory. Here's our new Object. Down here, me = curly brace. Then if we have any attributes on this Object, like age, we're going to have this be a new Pointer, and it's going to point to some other Primitive. In this case, this could be anything. Right now, in this case, it's a Primitive number, but this could be anything else. This is going to be our flow of what points to what. We're going to get into a few situations here. Some really, really common situations like this, what we would describe as maybe unexpected behavior, but once you have an understanding of what is pointing to what, you would completely, oh this makes sense, I completely expect this to work the way it does. So let's talk about this. Why does this still point to justin at the end of this? So here we go. We have our initial construct, me.name. This is our name Object. I'm sorry, me is our Object. This is our name Object here, name Pointer. Then we have a first Pointer pointing to our Primitive String Justin here. This is the first construct. We have our second Pointer. Name is going to point to this new Object, and this is the weird part. Name = object, {first:"alexis"}. What this really does in memory, if you think about what this does, remember the parser is going to come to-- If we're looking at name = curly brace name alexis, the parser is going to come to that curly brace first. It's going to create a new Object, that happens to have an identical construct to our earlier Object, and then we're just going to reassign that Pointer. This is a little bit different than what you expect in like a C or Java. When I say C, I'm really referring to C Sharp, not standard C, because we would expect this to probably modify this Object. Again, if you consider everything a Pointer, all we're doing with equals is reassigning it to our new spot in memory, our new Object we've allocated. So when you say me.name.first at the end of this, you will still get justin. Does that make sense? Cool, yes, go for it. In Firefox, I've been running this and every time I set me.name to name, it sets name as a String with the Object, for Typeof placed in a String. You're setting me.name to name. So you're doing this concept here, Yup. and you're setting, after name = me.name, Yeah. You're doing the reverse me.name = name. When I do name = me.name, then I call name, I get object, object in String. Not sure if that's what he's referring to. Oh, you're using Firefox as well? I'm Chrome, mine's in Chrome though. Gotcha. So if I create the me Object and then do name = me.name, and then I see what the value of name is, I get object, object. Yeah, value of name works out because the value of the name is this right here. Ok, so how do I access to-- Can I do name.first? Yes, you can totally do name.first here. So that's correct. If you say Typeof me, Typeof me is going to return a what? Object. If you say Typeof me.name, name is going to return an Object. If you say Typeof me.name.first, we're going to get our String. If you say Typeof name, what is name going to return? Object. In both instances? Before the allocation too? Yeah. Cool, any questions? Any other questions, yes. So the reason why this is happening. You were using Firefox too, or did you try-- Chrome. Chrome, ok. So, sorry about using a bad example here. If you change this to something other than name, it should work. If you just did Foo and then Foo = something it should work. The problem is window.name-- Gotcha. is a property. Windows have a named property that is almost certainly being type coerced to a String, because they want it to be a String. So when you set name equal to this Object here, or name equal to this Object here, you're just type coercing it to a String, and that's why you get the object, object thing. We should change this slide. You guys are the first people to notice. I've shown this slide a million times and no one's ever pointed that out so thanks for-- Good catch. Good catch, but hopefully that makes sense. Essentially, this is a special property. This is a special variable essentially, the name variable. So you should avoid setting it in kind of the global context. If you did this in Node.js, it would be just fine, right? Yeah, probably. Right, right. Unless Node has a special name property, which I don't think it does. I don't think so. Yeah, I don't think so either. So, good catch. In terms of the language, this is how things operate, in terms of running it in a browser. Running it in an environment, we're at the mercy of the environment. Good questions though. Good Catch.
Comparison
== vs. ===
You've probably seen, I know Brian Roux has that awesome blog post or video out there with all the crazy things that's wrong with JavaScript, and most of this is in there, I like that blog post, it's really humorous. But there's a lot of weird things that happen when you use double equals. We've all observed it. At this point I assume everybody's observed something. Oh, that's not what I expect, but it's there and it's easy, so sometimes we use it. Here's what's going on, 21 the number, double equals the string 21 what do you guys think? True, false, what do you think this is going to return? True. True? I would kind of expect this to be true. Like okay, 21, string 21, ah they're different types but I get it. The you know, stuff behind the scenes is doing smart things, it knows what we're talking about, okay. Undefined double equals null. Now remember, these are primitive types. Undefined is a primitive type, it's a undefined pointer, a unreferenced pointer. Null is an actual mem reader, a zero x zero, it's the null pointer in memory. If you say undefined double equals null, what do you guys think, true or false? True. True. You think true? False. Couple, one false, any other falses? I would think false, I would expect this to be false. Just looking at it, you know, newcomer to the language, undefined double equals null, they're two primitive types. I would expect it to be false, it is true. This is strange. Don't worry we're going to come back to why this is the way it is. Triple equals, with two primitives. Now again, a newcomer to the language, I would say, oh I would expect this to be the same as before, what do you guys think, true or false? False. Okay, I got a couple false. This is the weird part, because looking at this, if the roles were reversed here, I would look up like, uh, it's got to be true, right? The previous one is true, this one is going to be false just to make things completely confusing. Don't give up on the language yet, we're going to make it through this chart and we're going to show you why. Whoops, didn't mean to show you the answer. Number equals number, we assume that would be true, I would hope that's true, here's an interesting one. Empty object equals empty object, triple equals what do you guys think, true or false? True. True. False. False. False, true, the room is divided. I would expect this, well, this one is different, I don't know, this one is unique. If you've come from another dynamic language, I would expect this to be false, and it is. We're going to talk about why. Those that said true, probably assuming like, oh, the properties are identical. That's the basically the logic that went through our heads. I'm going to show you what this is actually doing. Not a number is triple equals to not a number. What do you guys think, true or false? False. I'm going to say it's true. True, true. The room is divided once again. It is false. How many people have completely just ah, I give up? I'm never going to put another if statement to my code again Now this is crazy, this last one. True double equals an object with a value of function that returns a string one, what do you guys think? I can tell you right now false, I expect that to be false. That's crazy, that's... True. One true? True, false, what do you guys think? False, true, split, split down the middle again, I like this room, uh, this one's going to be true. Which is insane, right? I would never expect, if you had if true and then some crazy object, let's say you're passing in your function, accepting some kind of object as a parameter, and you know, like oh, I need to make sure the data is what I expect, or throw some error. And then right at the start of my function I say, if true equals whatever the user passed in, and then some malicious user says, I'm going to pass in an object with a value of function that returns this. And I'm going to pass your condition, that's crazy! Let's talk about how this is set up in memory and then I'm going to walk you guys through what this actual comparison is doing.
Comparison Operators Explained
We briefly touched on by reference and by value, what that means, have you guys heard that term before? Has anyone not heard that term, by reference or by value before? Pass by reference, pass by value? Okay, we're good on that front. So, we're going to talk about triple equals versus double equals, let's observe. We have this code on the left side, we have two strings, the two pointers to two primitive strings, but they're the same string, they're the same, you know, actual string, then we're going to do a comparison. Str1 triple equals str2, what this is going to do in memory, you can see here on our right side, we have our two str1 and two pointers, they're pointing to our two primitive strings in memory, the first one in 2001, the second 2101, what this is going to do is it's going to find those two primitives in memory and compare the actual values that those have, this is what we call, you know, comparison by value, I guess. When we're passing things by value, it's going to look at the actual value that's held at those locations. So, this will compare those two, does hi equal hi? That's true, so triple equals, this will return true. Question? Interjection, come on in. Little qualification here, the two strings. Very likely would only be one string in memory, okay? This is a rule of, like you know our We like to say that every time a string is created, a string object is created in memory, right? But in reality, JavaScript interpreters it will only treat it will only probably create one string. Again just our rule of thumb versus like what happens in reality. Primitive types like's strings are... You could almost think of it there's only one hi ever created in reality, but I think it's better to actually think like they're both created and that there could be a comparison like this. Because they're actually, there could be, two hi's created in some. Like there's nothing preventing the language from doing that, it's just what happens and most browsers would only create one hi in this case. Be sure. The weird thing I want to tell you about primitives is they're both like pass by reference and pass by value in some ways. Because you can't actually modify a string. You can't just say to a string like hey change this second bit of a hi, or change the second byte of the hi to a capital I. You can't actually do that and keep the same string in memory, you'll just get back a brand new string. So, the reality of primitive types like this is much more complex, there's a lot to learn there. But again, I just want to The rule of thumbs that we're giving will get you the right answer, just there's a lot of optimizations underneath the hood. Yes, yes. You could learn about, but there's really Only if you're like a geek do you need to learn about it. Be sure, I know we mentioned that just with the discussion of the V8 developer. That's where this really was all born from, is we had a core V8 developer that was like no, we would never do this, it's so inefficient. We just create one hi, we'll be sure to post that just cause or, you put the post up? It's a really good discussion. Or you have someone with intimate knowledge, one of the core team member over at V8 talking about how they set this stuff up in the real world. Not in our we're learning how to create a browser world. So cool. Okay, now this is with primitives, with objects, it's going to do things just a little bit different. So we have obj1 is the 7T object, obj2 is a 7T object. We have our pointers to their respective addresses in memory And from, you know, at face value, I would do the same thing. I would say hey, these objects have the same actual structure, they have the same values, they're both empty in this case. They should result to equal, but because they're composite types, what this is going to do, is it's going to check by reference. It's going to check the actual address of where these objects are in memory. Now since these are two different objects, two new objects, created in memory, they have two different addresses. We're not going to go through and check all of its attributes, we're just going to say are you at the same spot? You're not, you must be two different things. This is going to return a false. Can you give that same example using a double equals? Like how the memory works? Yes, I can. But I can also, come on. Second time's a charm. I can show you what would happen in a double equal scenario. So that was triple equals. Triple equals and a primitive case. We're going to compare the values at the two addresses and a composite case, we're going to compare the addresses of what's on left and right side. What happens in a double equals case? This. This is the logical path that a double equals comparison is going to take. You're going to take the left double equals the right and it's going to run through each of these in order. To produce recursively, to produce some type of end result. So let's talk about this. Rather than take the two objects, let's do something really weird, let's take that crazy case where we had a Boolean compared to an object with a two string. We used a value up in the example, we're going to use a two string in this example, returning our one, why this return is true. So let's walk through this. The first thing we're going to come to, is we're going to say hey, are these two types the same? In this case they're not, one's a Boolean, one's an object. So it's going to say no, so the next step is going to say hey, are both null or undefined? It's going to say no, that's not the case we're at yet. Do we have a string being compared to a number? Again, false. Do we have a Boolean being compared to anything? This is a condition we can pass. We're like okay, now we're on the right track. Let's pass this into our little state machine and we're going to convert our Boolean true, this is going to spit out a one. That's the only thing that we can really do in this state machine is we're going to take true, we're going to convert it to a one, and then we're going to recursively call the same double equals comparison except now we're going to say one compared to the object two string function one. Then we start this whole machine over again. Are the types the same? Nope. Are they both null or undefined? Still not there yet. Do we have a string equal to a number? Not quite. Do we have a Boolean equal to anything? No, we're going to get to go one level deeper this time. Do we have an object equal to a string or a number? Yes, this is the case we're at. So what we're going to do is we're going to call two string or value of. We happen to have the two string method on our object. And we're going to compare the number or string, our case is the number, to whatever is returned from these methods. So now we're going to get one double equals string one because we happened to pass an object with a two string function, when invoked, will return a string one. This is our clever little trick. We're going to start the whole process over with one double equals, string one. Are the types the same? Still no. Both null or undefined? Do we have a string equal to a number? Yes, so now we're going to go back to our state machine and what we're going to do, you can see down here at the bottom we have a string. We're going to convert the string to either a number or not a number. In this case, the string one can be converted to a one. So we're going to get one double equals one. We're not done yet, we have to start the whole machine over again. One double equals one, are the types the same? Yes, call triple equals, internally. That's what this machine's going to do. And eventually it now, one triple equals one. It's going to do the comparison and say yep, you're the same thing. Finally after, I'm not sure how many slides that was, to get through this machine that many times. This is why it's a performance hit and why you're going to get unexpected behavior. Expect it if you have this kind of memorized and eternalized, which I don't, but... Still going to be, you don't want to base any kind of validation or any kind of condition logic at all on this. This is exactly why you don't use double equals. The performance footprint of a triple equals, this is the graph. Are the types the same? Yes or no. If they're not the same, then it's false. It just stops right there. If the types are the same, is it a primitive? Compare the values, if not, compare the addresses. And then you're done. This is as complex as it's going to get for triple equals. Double equals is that crazy state machine. To answer your question. So would you never use the double equals? I never use the double equals, ever. Do you use double equals? When I want to compare null to undefined. That's a good place-- Why is that different? So that I don't have to write-- Even then, I actually write it. I do the type of, you know-- Cool, you could write. (audio distorts) I want to write like foo triple equals null, or foo triple equals undefined. It's just nicer to write foo double equals null or undefined then you get both. And you'll see that in a lot of, Like a lot of libraries tend to accept it. There's like an exception in JSLint or something, too, for doing that I think. Oh, a flag you mean for IA? Yeah, yeah.
Closures
Types as Arguments
Quick question for the audience. if anybody is brave enough to answer. What is the value going to be when all of this code is run of a, b and c? And try not to cheat and just write it out. And just so you know, the prefix plus-plus operator, that returns the incremented value. So if x was going to be let's say 10, it would return, it would increment that to 11 and return, the result of the parentheses would essentially be 11. Any ideas on what a, b and c are going to be? They're not going to change? That's true of one of them. (laugh) Any other? Oh, sorry, it's. Is that true... Well, c is not really being changed. But yeah, c will change I guess, from undefined to have a value. So, one, two three? If you have one, three and then five. So let's see how that works. So b dot val will be three. So, again, when everything is run, it's always run, when all code is run, there's always this kind of global call object. This global container for all variables. And we're going to treat this code just like how, kind of JavaScript processes it. Think like a computer. So, computer's going to come see the, the JavaScript processor is going to come see this first, kind of statement here, and it's going to do what's on the right-hand side. The expression on the right- hand side of the equals sign. And it's going to create a function in memory first. We'll be using this a little bit later, but I want to give a sneak peek to it. Whenever a function is created in memory, it has a prototype property that points to an object in memory. We'll be using that later. But just saying, whenever you see a function created in memory, we create a little function, on our kind of two dimensional representation of memory, whenever it was created in code, we create one in memory with a prototype property and a circle for its object that the prototype property points to. And then we're going to do what's on the left-hand side of the equal operator. We're going to create a sum variable in our call object. And then we're going to set that sum to point to the function in memory. That's what JavaScript does. And JavaScript doesn't know what's going on inside the function. You can think of is it has no idea what's going inside the function. It has no idea about, like x or y being incremented, any of that, it's just kind of blind to at this point. The next thing it's going to do is run these two things. It's going to create an a variable, point it to one, and it's going to create an object in memory, with the val property, and it's going to point b to that. The next thing is it's going to call the sum function. And I apologies if the font is a little small up there. Couldn't really make it much bigger. And whenever a fun, the important thing though is, whenever a function is called. Whenever you see that call operator. Some function followed by parentheses, there's a bunch of things that happen. The first thing it does is it creates a new call object that's going to contain the arguments and variables, and also the reference to this. That invocate, when that function is invoked, it's going to contain its variables, arguments and things like that. So that's another call object, for the invocation of sum, with the variables a and b. So, creates this little place in memory, to contain variables and things like that, and it starts putting things in there. So, it's called with a and b, but it's going to translate that to values that it contains of x and y. So because a is a primitive, it's passed by value. So x is going to have the same, it's going to have. X is going to point to essentially a copy of a. You can think of it as creating a new one in memory. It really doesn't, but think of it that way. And then y is going to be passed by reference. So y is going to point exactly to what b points to. So this is what gets set up. Then the function is actually, it's code is going to be run. So, it's going to say, hey look, give me the value of x in memory. I'm going to increment that. And give me the value of y, give me y dot val, look up that and increment that. So it's going to increment x to two, and y dot val to three, and then return the sum of those two things as c is five. Any questions there? Make sense? So. The first thing to remember is whenever a function is invoked, whenever it's called. Or sorry, two things to remember. Whenever a function is defined, a kind of function is created in memory. And the second thing, or is created in memory with a prototype property. And the second thing, whenever a function is called a new call object is created and the arguments passed to the function are kind of translated to what the the names of the arguments the function like defines out, so like x and y. A and b gets translated to x and y. So, another summary. Primitives passed by value get a copy, objects passed by reference. So, another question. What's going to happen, what's going to be alerted when this code runs? And then bonus points for explaining why. Any brave souls? I can tell you my guess. I would assume, looking at this code, I would probably think it's going to be zero one two. You're an idiot. No. (laugh) No it won't be that. It will be, any other guesses? If it's not going to be zero one two, what else could it be and maybe why? Brave souls, we should start taking names, and then like give rewards like cookies or something tomorrow. Cinnabons. Yeah, cinnamon, well, yeah. Well, maybe bring something nice for those who are. Did you want, did you have a stab in the dark here. Well. I ran across something like this two or three years ago, where it ended up being something like two two two, but. That's, you're right on the. You're so close. But I forget. I forget why that was. (laugh) It's good. It's going to be three three three. Okay. Anybody know why? Yeah. Because i is the reference, and it's the last reference in order once the loop finishes. And so as each line then executes afterwards, it's using that same reference. Yeah. So once the. I is going to be left at three, because the for loop like will. The conditional will fail for the for loop. So i will be zero, then one, then two, then three. This will fail, then it'll exit the for loop. But it's because everybody, a lot of people think, oh well but, shouldn't i be zero, one then two? It's because JavaScript doesn't have block level scope. So this i is kind of global, it's in the global call object, so it's just going to output the value of i as it stands, every single time. So we'll come back to this and show how to fix it. And explain the problem a little bit better. But, yep? A couple questions that came up a little bit back here. He was asking if objects are all called by reference? And then also kind of related to that, call object is a synonym for scope? Call objects are called by, call. So, call objects, I don't know what. Call objects aren't... You can't really pass a call object to a function. So you can't really like, that pass by reference pass by value thing. I don't know how, maybe the phrasing of the question I'm missing. We'll, what was the. Oh, he's not talking about call. He's that was the gentleman talking about objects are called by reference? Yeah. Oh. I think he was referring to the exercise at the time. So objects aren't called by reference, they are passed by reference. And then is call object a synonym for scope? Call object is like a piece of a scope, you could think of it as. If the whole scope consists of, you know if, inside this function I can reference a, b and c, but also inside this function I can reference x and y. If that's what, a lot of times people refer to as the scope, it's like all of the call objects combined is the scope. Alright. That, it's kind of related. So he kind of asked a follow-up question there. Why x isn't a call by reference in this example? So, x is not called, it's passed, right? There's a difference between called and, like so when this, when the sum function is called, it passes a and b. So a is passed by a value because it's a primitive type, it's just a one. B is an object, so it's, so y. It's passed by reference. Sorry, did I say x is passed by... X is passed by value, y is passed by reference. (laugh) B is passed by reference to sum so y, when it kind of like translates the arguments, y is going to point to b. But x is going to get a new copy of a. Does that make sense hopefully. So why isn't x called by reference? Oh, maybe he was also referring to when I said x isn't. When I said it's not actually a new copy is made. The reason is it can be and it could not be. You don't know. Because again, real primitives in JavaScript, you can never mutate a number or a string or anything like that, in place. You always get a new copy whenever you increment x, that actually value here, really we're showing it as being... I kind of try to show that it's not like so much the number has changed in place, instead a new number has been like. Instead x is really pointing to a new number. That's what's really happening when you increment x. Because you can't actually change primitives. So that's why, it's not necessarily, it could, the engine could optimize and say okay, well I see that this function is constantly changing the number. So, I'm just going to copy the number that was passed, and pass a fresh copy that it can increment in place. Or it could decide that oh, they just want the number, and they do almost nothing with it, I'm just going to pass the same number as if it was passed by reference. So I don't know if that's the question that was being asked, but there's a whole lot of complexity that can happen because primitives are not mutable. That engines can decided whether to do reference or value. But think of it as passed by value.
Counter Example 1
Let's do this counter example. And this is one of my favorite examples here. Here's a counter function that returns a function itself that when called increments a variable and just returns that newly incremented value. Let's see what's going on in memory when JavaScript's doing this. So, first thing again, JavaScript sees a function created in memory. Sorry, a function defined. And creates a function in memory. Now last time, we drew out that a function also has a prototype property. I'm not drawing that here just to save space. But there's one more thing that happens to a function whenever it's created. A function always has like this, hidden, magical reference to the call object in which it was created. So a function always knows, like hey, here's, I was created in the global call object, I should know about that call object. Alright, so there a little magic pointer here, that you can never reference, but the function internally knows. So then we're going to point the counter variable to that function. And then we're going to go to the next line. Okay, so this line is going to call the counter function. And again, whenever a function is invoked, a new call object is created that contains any arguments and any variables created while that function is running. Now, one other thing call objects have is they know about their parent function. They know about the function that called to create a call object, to create that call object. So, it's kind of interesting. Functions, whenever a function is created inside of a call object, that function knows about its parent call object. Whenever a function is called and creates a call object, well that call object knows about its function. And this is important for how closures fundamentally work. So, Now this function's going to be ran. So now we've created the call object, now we're going to run the function. And we're going to create the count variable. Well, variables always get put in their call object, the current call object that's running. So, a count variable is going to be created inside this call object that going to point to the value zero. Now we're going to get to this line. And again, we're creating a new function in memory. So I'm going to create a function in memory. And again, functions always know about their parent call object. And we're just creating the function in memory. We're not looking inside. We don't know what it's doing. But we are returning this function and sending its value as c1. So c1 is pointing to a function in memory who has a parent call object with a count variable. When we run c1. Again, whenever a function is run, a new call object is created. And the body of that code is going to be run. So this is where the c1 function's code is. It's going to be running this count, plus-plus count. But it needs to find a count variable. So it's going to first look for the count variable inside c1's call object. Not find it. And then walk up these, kind of magic reference that I said these things that you can't actually access, but JavaScript internally can access to find the parent call object. Look for count there, find it, and increment it to one. Now if it didn't find a count in this call object, it would just keep walking up to try to find a count variable. And eventually just say hey, count is not defined, if it couldn't find it in the window. Alright, so this is closures really. This is how closures work. Essentially functions know about their parent call object, and call objects know about the function that was ran and it creates this kind of linking that JavaScript can go through to find variables. So, let me walk through doing this again. Just to show, make sure I'm getting it. So it'll return one, because nothing now is referencing that call object. It will be garbage collected. Then c1 is then going to be called again. A brand new call object is created. So this is important. Every time a function is run, a new call object is created. Every time. So again, same process is going to happen. This code is going to be ran. C1's code is going to be ran. It's going to look for count. It's going to increment count to two. There a question? Yeah, within the closure, is this dot count the same as count? No. We will talk about what this means in maybe next Next set of slides. The next set of slides. And the yeah, we'll get to this. I don't want to (laugh). The answer is no, forward, we'll get to why. Yeah, we'll get to why. But I will say that call objects themselves store the reference to this. In reality if I was drawing this full call object out, it would have a this pointer that points to the window. It would have this inside here, and pointer right back to the window. But we'll explain that later. Anyways, so we just called c1 again. And it's going to, we just incremented our count variable to two. And now we're going to call the counter function again. And this is really important, because a lot of times I think people don't. They kind of see code like this and they might understand, oh there's two different count variables, but not really the mechanism that supports and allows that. So we're going to understand what happens when you call counter again. When you ever call a function again, a new call object is created. For that second invocation of counter. And it's going to know about its parent function. And we're going to run the counter code now. So we're going to create a count variable. In this other call object that's going to be zero. And we're going to return another function in memory. So a brand new function is going to be created. And we're going to return that as c2. There's a question on how is that return function invoked, is it internally invoked when called? The return function. How does-- The inner function, how is it invoked? It's invoked as c1 right here. And c, by calling c1. So we save, that inner function is returned. And we save it as c1 and then we're calling it here. And now, we're going to create a new inner function. We're going to actually create two functions in memory. This is really important, where I think sometimes beginners, might not understand. They think that there's just one function created in memory. There's actually, this function is created every time counter is created, as you can see here. We have two functions in memory. And then again, we're going to save the function that was returned by the second calling of counter as c2. And then we're going to call c2. Which will, again, call c2's code, which will look for a count variable. And this case, should try to find count here. Not find it, walk up these references, and increment this count to one, and then return one here. Yeah. How does it work to have two return key words in? Because once you hit that first return key word, doesn't it break out of the function and then go to the code that called it? Or is that because the second return is within that second function? Exactly. So the big thing is to think of. When you, functions are first class. So you can do everything with a function that you can do with an object. In some ways this return is almost like I returned an object from this outer function, but in reality, I'm returning a function. So c1 is a function that you can then call. So that's why this return in here, nothing is happening with until c1 is called.
Counter Example 2
If you can get this, this is like closures. You actually, I think, understand more about JavaScript development, or JavaScript, how it works as a language than 90% of developers I would say. Most people don't really get the mechanism for how this works. So, again, this code. JavaScript just comes to it. You know, parses it. Then builds it all into expressions. And is going to run, essentially the first expression. Although I'm going to run kind of two at once. It's going to say, I'm going to first build a function in memory. And like we said, functions always know about their parent call object. And then I'm going to do the counter equals part. So again, it doesn't know what's going on inside that function. It just knows there's a function. Then it's going to run that function, counter. And every time a function is ran, there's this magical box that variables can go into. And while this code is running, any variables that this code creates are put into that box. So here count is going to go in and it's going to be zero. Now this function returns another function. So just like before, when we saw the counter function, we're going to create another function in memory. And we're going to return that function's memory address essentially, to be set as the c1 variable. So c1 will point to that function in memory. Then we're going to call c1. And whenever you call a function, a call object is created. And it's going to run then the code. So whenever a function is called, call objects created then it runs the code for the function. So in this case, c1 is that inner function. The we're going to run plus-plus count. It's going to try to look for a count variable in that variable, but we didn't create a count. Or sorry, it's going to look for a count variable in that call object. But we didn't really create, we didn't do a var count in. We didn't do a var count inside here, so it's not, there's not one in here. So it's going to keep looking up to try to find a count variable. Find that count variable and increment it. And then return because c1 is a function itself, it's going to return the incremented value of count as one. And we're just going to do, call c1 again. Same function in memory, we're going to call again, but every time you call a function, a new call object is created, and that same process of trying to find count in memory is going to be looked up. It's going to be looked up as two. Do you want to use return then, every time you put another function inside that function? Now you could, it's possible that you could do like, window dot, you know foo equals a function and then you could, I could call foo down here. But it would overwrite that foo property every time with a new function. So, the cool thing about this, is down here, if I were to call, I could still keep calling c1 and it would still be it would still be counting c1's variable and not c2's, kind of closed variable. In some ways you might, like if you use JQuery code where you have a lot of nested, a lot of nested functions. Like you're adding event handlers and doing AJAX calls and things like that, where you have a lot of nested functions. That's the exact same thing that's going on here. Is if you have a function defined inside of another function, it can reference the variables in the parent function. That's how closures work. This count can access the count in its outer function. And it can also reference the, all the variables c1 and c2 if it really wanted to. Even though itself is being created as c1 and c2. That's just because closures work. It just keeps walking up these chains until it finds a variable. Might be just a, there's a question about what does the parentheses after it mean? Oh, when we're just putting a call object? Like drawing it out like that? That just, it's our way of representing that this is a call object that was created when you called the counter function. No but I think, like if you have var c1, the different between just c1 and then if you were c1 with parentheses after it. Open close. So if I did-- So if you just did c1 semicolon, versus c1 open close semicolon. Right. So c1 is just a reference to the function in memory, just a pointer to that function. C1 with the open close parentheses is doing two things. It's finding that function in memory, following the pointer to its function in memory. And then invoking or calling that function in memory, if that makes sense. And in the process creating our call object here. What this is, a nice way to do this, is a really nice example too of how we can simulate private variables in JavaScript. By, with this kind of constant, this knowledge, count is not accessible. I saw there was in the chat, there was some, why isn't count accessible on the window, on the global scope? This is how we can prevent, or keep a nice closed, that's where we use the word, set of variables that we want to use in our methods. If that answers the question. So one fun kind of technical aside. For the computer science-y, nerdy folks in here like me. Let me step back. So when a call object is really. So most, every language has the idea of a stack. You might have heard of a call stack, right. So, in C, when a function is called, any variables created inside that function are kind of added to the stack, and when the function exits that part of the stack is popped off and discarded. Alright, so you enter a function. Variables get stored on this thing called the stack. And then when the function exits, they're popped off. That's why if you've ever had a stack overflow, and not the question site, the actual stack overflow error, that's because you keep calling so many functions that the stack gets so big and that there's just, you run out of memory. A call object is really a part of the call stack. So each individual part of a call stack, that represents a single function, that's called an activation frame. And a call object is really an activation frame. So, one invocation of functions, all of its arguments and variables, stored in something. But it can be made permanent. A call object is some. Call object, or sorry. A call object is a activation frame that can exist past when the function has exited. Right, so that's why like, I'll start over here. So when I call this counter function, in some way what JavaScript's really doing internally is it's creating a new activation frame for the invocation of this function that stores all variables on it. And because it's returning a function, that has c1 pointing to it, and this pointer func, this function then points to the activation frame, really. Or the call object. It knows I'm not going to garbage collect that then. Because I'm not, when that function exits, I'm not going to pop that activation frame. I'm not going to discard it, I'm going to save it. Because something might still want to talk to a variable inside this activation frame and that's this count here. That's the very technical, deep reason, like kind of computer science-y reason. Closures are really just, someone was like, hey, we've got this stack. Let's make a, let's with activation frames, what would happen if someone still wanted to access the items in the activation frame later, and how would we make that permanent? And the mechanism which JavaScript uses to make activation frames permanent is a function that's created inside of another function. If you have a function, then functions know about their parent call object. It will make that call object permanent, as long as, and keep it there as long as somehow something is essentially referencing that function. This question is the activation frame still on the stack? It will be on the stack while this function is running. And at the end, when the function exits, it will be popped off and kept somewhere else. I think. That actually thread that I posted, that, where I was working through this with the V8 Core member, he. I forgot what he said, at what point it's moved off. It's definitely moved off the stack. I don't remember exactly what's done with it. Cool. Alright. Sorry to get all, super, hyper technical. But I enjoy it. (laugh) Hopefully some of you guys do too. If not just, just write a comment telling me not to talk about that stuff. I won't be offended. So to finish this, okay. C1 is created, right, is returned from here. We call c1, it's going to run itself, but try to find this count variable. Increment it to one. Then we're going to call c1 again. Every time a function is called a new call object is created, right? Just like activation frame is put on the stack. And it's going to try to look for count, but because it can't find count, it's going to walk up these these little magic references to find that version of count, and increment it to two. Now here comes the crazy part. We're going to call counter again. So whenever a function is created, or called. A new call object is created. And that function's code is going to be run. And any variables created while that function is running, are going to go in that call object. So this is going to get a different, separate, count variable. And then within this function, another function is going to be returned, or created and returned. As c2. So then when we call c2, a new call object is going to be created. And it's going to look up a value of count again. But this time it's going to look up a different value of count, and increment it to one. Cool. Any questions before I move on? Could you pass parameters into that second function? In this? Yeah. It would, these parameters would show up here. So if you wanted, and then they would also be put in this col. So, if I pass like increment by, or something like that, alright. So if I didn't just want to increment by one, I could pass an optional increment by. So I might have increment by as an argument here, and I might do count plus equals. Well, I have to figure out how to write that so it would like return the. No, count equals count plus increment by. I could write it that way. Now, when this call object is created. So when c2 is created, it would actually get the increment by saved in here. So when increment by was looked up, it would find increment here, but it would find count still up here.
Closure Gotchas
Okay, so, back to this. Hopefully this can be a little bit more understandable now. Why this was happening. We'll walk through this code the same way we just walked through that counter example. So. JavaScript is going to come to this. Going to see a var a equals an object. It's going to create an object in memory. Then it's going to go through. It's going to start this for loop. And the for loop is going to create a variable i and point it to zero. So we're going to kind of start with something like this in memory. And now we're going to iterate through the body of the for loop. So within the body of the for loop, it's going to create a function in memory, right here. And again, functions don't know about anything that's going on here. It's not like because this function has an i here it somehow is going to say oh, give me the value of i right now. That happens later when this function is actually run. So it's going to create a function in memory, and it's going to set i, a's, object a's ith property to point to that function. So it's going to say a and its zeroth property points to that function in memory. And now i is going to be incremented to one. And it's going to do the same kind of thing. And then i is going to be incremented to two. And again, just a function is going to be created in memory. And a sub two is going to point to that. Now remember these are all different functions in memory too. It's just, even though you've just defined, you've written function once, you've actually, it's creating three different functions. And finally i is going to be incremented to three. It's going to fail the for loop's test. And exit the for loop. And then a subzero is going to be called. Now whenever a function is called in memory, a call object is created, again, sorry about it being small. This just says a zero followed by parentheses. And it's going to, run the function body. The function body is going to try to alert i. So it's going to look up i. And it's going to start looking up i in this call object here. But, it, that doesn't have an i. So it's going to walk up again, through the parent call objects, looking for a variable i, find it, and then it's going to alert three. Any questions? So that makes sense now? Yeah, kind of? A lot of blank stares, okay. If there are questions, I'm happy to talk about this ad nauseum. Because to me, understanding this, and especially understanding this and prototypes and stuff like that is so fundamental to writing good software for JavaScript projects. Alright, make sure you're doing things the right way. So, if there, is confusion, or other things you want to ask in reference, related to this, please ask. Okay, so the fix for this. So if kind of understanding closures is the problem we're dealing with right now, well, the fix for this is adding more closures. Adding more call objects. So, what you can do is wrap this with an immediately invoked function. So I've wrapped my code I had before with another function, because what this is going to do for us as we'll see is it's going to create a individual call object that these inner functions will be referencing, and an individual value of j essentially here. A unique value of j stored in that unique call object. So that this will alert zero one two correctly, like we want. So let me do this. So we have our window. We have our a. We have our i. And now we're going to run, the in, the body of the for loop. Now in the body of the for loop, you can see here we're creating a fun. The first thing we're going to do is create a function in memory. So we create a function in memory. And the next thing we're going to do is call that function in memory. And again whenever you call a function in memory, a call object is created. And that call object is going to contain any arguments passed to that function. So here we're passing i, but that's going to be translated to j. And because i is a primitive, j is going to get its own copy of i. So that we're going to create a structure that looks like this. And then, we are going to run the inside of this outer function here. We're going to run this function. Or I guess we are running the function already, because we have our call object. And we're going to do what its code says, which is to create another function in memory. And then set that as a subzero. Alright, j is going to be zero. And sub is a subzero. Cool. So then we're going to just repeat that process. I'm not going to draw it out. For a, for when i is one and for when i is two. We're going to create these things. Okay. And now let's see what happens when we call a subzero. When we call a subzero, a call object is going to be created. Again this is small. So this just says a subzero, and then colon with parentheses, just like before. When we call this function in memory, a new call object is going to be created and then it's going to run that code. Whoa. Why is the thing... Oh, I think something happened. Normally, my presentation shows it's trying to look up the value of j. This, once we run this function, it's going to run this code in here. It's going to look up the value of j. And it's not going to find it, because we didn't pass it j. So it's going to walk up to find the value of j here that was passed, and then alert zero. Any other questions about closures? Because we'll be using. We'll be doing something very similar to this as our first exercise immediately following this slide. Yeah? Is the j just picking up the loop then? Or where are you getting the j in there? See this, so we're pass, here we're passing i to this function. Okay. That function takes as an argument j. So, it's like before. Whenever you call, it's just like the sum example. In this sum example, we're calling sum here with a and b. But they become x and y inside the sum. Alright. So the. This is a. Slide show, back, right slide. We're doing the same thing. But we're doing it in this kind of weird syntax. It's like we're creating a function. But we're not saving it as like a sum variable or anything. We're creating it just to call it right away. Alright, so we just created a function, and then we're calling it with i. But i is going to be translated to j inside here. Alright. So that, again what's going to happen is we create that outer function. We're going to run that outer function by passing it i. The current value of i, which would be zero. But, that's going to create a call object with j, i translated to j, so j is going to point to zero. That same thing is going to happen. Cool. Any other questions? Awesome. So, yeah? One, I guess. I'm not sure, can you use void instead of wrapping a function with parentheses? There is another syntax where you can do like a bang or something too. I don't. You might be able to. I actually. I know there's different syntaxes that I've seen people use. I always use this to like, invoke the function. I don't know if you can use a void or not. Okay. You can use, I think it's any Unicode operator, I think. So, like plus. Because bang usually denotes something URL related. But a lot of people will put like plus in front of function, Because that'll do the same exact thing. And then you don't have the wrapping parens. But I forget what the rule is. I want to say something like if you have any Unicode operator will do. I don't know. And an alternate way you could do is just var i equals j, right? Without passing it in? Var? Inside the (mumble) Inside the what? Inside the a p there, the anonymous function. Oh, in here? You could put instead of passing it, just do var, yeah, you could do that. J equals i. J equals I. Yeah. you could do that too. So to just illustrate what Mark was just saying. What he meant is you could just do var j equals i. Ah. And then you don't need this. And you're just calling the function. But, again, your call object is going to look the exact same. It's going to contain a variable of j that was set to i. This is, this can be, doing it this way is fine. They both get the same result. I was about to say something, but I realized both have the. Both suffer from objects instead of primitives that you're kind of passing. But that's fine, this works. Okay, so just to talk about our recap here. So this handout. Just wanted to touch. Kind of go to where we are, and then before we do the exercise. Here's. I guess we do that. We'll recap in a second too. But just to show where this is in the exercise. This is what happens. Everything when you create a function. All the different properties that get set when a function is defined. And then whenever you call a function. This is kind of what a call object gets, what's created inside of a call object. And you can see here is the kind of magic references and everything and everything like that.
Exercise 1: Making a Tag Library
Just a quick exercise. Although it might be a little confusing if you've not written a lot of JavaScript. Is to make a, we're going to make a tag library. Something that I just want to make. Something that, a make object, that has an H1 function that when I call it will give me an H1 element. But the secret to this is I want you guys to try to do it in the least lines of code possible. I want you to use the dynamic nature of JavaScript, where it can kind of. If you remember that JQuery example, where I kind of looped through kind of properties and values, and dynamically generated a like a version of JQuery. I want you to try to do something like that. So, essentially taking maybe like an array of tag names, generate an H1 function, that creates the H1. A anchor element that creates the anchor element. And you'll have to use kind of similar techniques that we just used to fix the for loop problem. So are there questions about this? One thing, just going back. Can you mention some of the practical uses of closures in JavaScript? So, you use closures constantly in JavaScript. Any time you have a function inside of another function. Or any time a function is accessing like a variable, that it itself did not create or is not directly passed to it, you are using closures. For private variables was also another one that Alexis talked about. It's hard for me, like you just. The counter example is in some ways a nice use of it. Because I created a function that you can just call and it increments itself. Almost like using a generator pattern. Hey, call this outer counter function, and I'll give you an inner function that counts. That's, that kind of stuff you do all the time. When you're building APIs in JavaScript. So, with this example, we're going to just, if you open up this tags dot html, you can see the functionality. You can just right, here's kind of a little starter code. And that test code right below it. So you could just take it from there. And we're here for questions, for like I guess, fifteen minutes. And then we'll give the solution. But if you're struggling or you even have questions right now, ask them. And we will try to help guide you through this example.
Exercise 1: Solution
Alright, thanks everybody, for going through this exercise. I will say, a lot of our exercises are difficult. Right? They ask you to do things that are what a lot of times library authors are doing. So, they will be challenging, but it's good to be challenged. So if you have questions, please ask. And if you're feeling like, oh this is really hard. It's supposed to be. We want to challenge you guys. We want you to learn and be better programmers after this. So I'm going to go through this and I think we're breaking for lunch I believe. So again, what we want to do is, as kind of. What I want to do is make a a library called make that allows me to not have to all. That allows me to create different tags. Right? Different elements. I want to do it, like how JQuery would probably write it. So there's as little code as possible. The naive way of doing this would be write a make dot a and then just keep writing out the same code over and over again. So this is how I would create my make a, and then I would just essentially copy and paste this code a bunch of times. Every time I wanted to add a new element, I'd have to copy and paste this and create a new element. But the beauty of JavaScript is that again, you can program your program. That's because it's a dynamic language. So instead of doing this, what I'm going to do, is I'm going to copy those copy these tags. And I'm going to save them in a variable called tags. Then I'm going to make each one a string. This is taking a little bit because I don't have my mouse. Okay, so I'm going to create each one of those tags. And instead of doing this, I'm going to create a for loop that goes through every tag and gets. I'm going to save the tag name. And then I'm going to what I might think to do next is just write make tag. I'm going to add the tag property. Whatever, it might be a, it might be div. And I'm going to set that equal to a function. And then I'm going to make that function whenever it's called return document create element. I'm going to make it return an element for that given tag. Now, there's a problem here. Because tag, when it's all said and done, and after this for loop, you know, at this point here or in this test here. When it's all said and done, tag is going to be left at undefined. No, it won't. Because tags, it'll be left at H4. H4. Yeah, because it's exiting here, it's never hitting tags. It'll be left at H4. So here I'm, I'll only be creating H4 elements and that's not right. There's a bunch of different ways to solve this problem. The way that we learned from doing it with for loops would be to wrap this in a function. That calls itself. And I'm going to pass the tag name to that outer function, and I'm going to put it as tag here. And this, now this code is essentially creating a bunch of tags. And if I want to add another tag someday, I could just add to this list very easily, and the function will automatically be generated. So yeah, I've got my list of tags. I'm going through each one. And I'm creating a closure just so that the name of tag stays permanent when this inner function tries to look up the value. It's not going to get some global tag name. So this is how it works. How many of you guys get this, a little bit? Some people. Some people, okay, awesome. Very good. Any questions for those who don't? Like things that are confusing about this that I could explain? I know I'm holding you up from lunch right now, but, I'd still like to answer any questions you guys have. Yeah, I'm confused about the syntax with the make brackets tag. I'm not sure what that's. Make, this thing? Yes, exactly. Okay, so Alright, good question. So, Alexis touched on this just very briefly when he was talking about the operators. Objects like make. You know I can assign a make property like foo. You might have seen that. And I could set that to two. That's the dot operator, alright. There's also an index operator, which does the same thing, if it looks like this. Right. So if you. It'll evaluate what's ever inside of here, what's ever inside the brackets. And whatever that is, it'll turn into a string, and set that property to whatever is on the right-hand side. So it's not interchangeable with the dot notation though? You can't write like make foo like this. But they do the exact same thing. It's just this is in some ways like a. You could almost think of it as like a this a hard coded way. It's like your sending make dot foo. This way, I could have a variable. Like called propToSet. And I could set that to foo. And then I could have propToSet in here. Alright, so this is going to set the foo property. And if something else later changed propToSet to, or before. Right before it was setting to bar, it would set the bar property to two. And I could do even weird crazy things like, propToSet, you know, toString that function that returns baz. And now it would set baz. So essentially this is a way to kind of variable set a property name. You don't know which property you're going to set. It's going to be dynamically set. You're always going to be setting foo. Think of it that way. So that's what we're using here. Because we're going through every tag name, and we're assigning those properties that way. Cool. Alright. One. Steven in here showed another way, which is like nicer to look at. Which would be to use the, on tags, you can use forEach. And that will get called back with each tag name. And because this tag name is already going to be, you know this is kind of like making this function that we did here. It's pretty much doing the same thing. We can just do this. And this is a nicer way of writing it. But, in my opinion, well, I think this is how I would absolutely write it, but we want people to write it the other way, just because we want to make sure people understand closures and the problems with them. Things like that. So here's another good way of writing it. The way you probably should write it. And this works again, because this function is called for every single tag. So there is a call object created with tag in it. And that's what this tag is going to look up. Is this tag here. So we're already doing a lot of our work. Recap of functions. So what happens whenever a function is defined? So, whenever a function is defined, a function object is created in memory. It has a prototype property that points to an object. And the function knows about its parent call object. So, function is defined. It's created in memory. It's got a prototype. Knows about its parent. Those are the only three things you really need to know whenever you see a function defined like that. And when a function is called, or invoked, a few other things happen. Let me get those things in memory first. So whenever a function is called, a new call object is created. And it's arguments are translated. So in this case, well sorry. Let me step, let do it in the order these are in. A call object is created. It's this is set up to point to whatever this is in that invocation of function. So if this is looked up inside fn, the body of fn, it'll make sure it gets a window back. And then the arguments are translated. So in this case, arg1 is going to point to the same thing that the me pointer is pointing to, the me variable is pointing to. And arg2 is going to get its own copy of val. And then finally, any variables, the function is going to be run, and any variables that are created while the function is being run are put in there.
Context
What Is 'this'?
Let's talk about one of my favorite things to talk about, which is context. Specifically, the this keyword. I can speak, I like talking about this because I speak from a personal experience of pain and learning what context is and how it works in JavaScript. Originally I came from a C sharp background, through Ruby, so this, not this, or both, was one of the most confusing concepts. So we're going to talk about what that actually means. But first while we gauge the room, feel free if you're watching online to respond to this. We're going to go through some little audible exercises. Here's a very simple scenario. We have a dog object. Dog has a couple properties, it has bark count, which is just going to be 0, and bark, which is a function. Inside this function we're going to say, this.barkCount, and we're going to increment it. So when we invoke this function, what is this, the this keyword, what is it going to point to? Dog. Dog? How many people say dog? If you're online feel free to type in dog or not dog. Anyone think anything other than dog? No. No, alright. It is dog. In this case, this will point to our dog object. We're going to get into how this works here in a second. Let's change this up slightly. We have the same dog object, but instead of calling dog.bark directly we're going to create like an alias to it. We're going to say var bark = dog.bark. And then we're going to invoke that same function. In this scenario what do you think this points to? Bark. Points to bark? Alright, anybody else? Any other thoughts? It points to Kevin, right on. Anybody? Brave enough to take a stab? It's okay this is a safe place. Feel free. The video will be sent to your supervisors, so be careful with your answers. In this scenario, this is going to point to the window. That may not be what we expect, it's very similar code than what we had prior. Let's observe a constructor type of function. We have a person function, it can take a name as an argument. And we're going to set that argument to the name property of this. And this slide to overuse this word, what do you think this points to? Points to that, did somebody say that? That's clever, I don't think I've heard that before. What does it point to? The function object? The function object. Do you mean like the actual capital F function? Well I was just thinking of the memory space. Pointed over to the fn, which-- Oh, to the call object? Yeah. Okay this points to the call object, alright. Few people say P. Any other, person? The capital P person? Okay, right on. It is in this case, it will point to P. Little P, the instance of our person. This is weird, I know. Don't worry we're going to circle back to this. Okay, let's change that same, we're going to use that same code, we're just going to take out the new keyword. In this case we're going to invoke the same function, we're going to say var p = Person("Justin Meyer") as opposed to new person. In this scenario, what do you think the this keyword refers to? Or points to, rather? Window. Window? Any other brave souls? Person. Person? Right on. In this case, it will be the window. Okay, we're going to do one more, I think one more example. This one's a little bit out there. How many people have seen the methods call and apply? Let me rephrase, how many people have not seen the methods call and apply, have never heard of this? Okay, this is going to be fun. Call and apply is really, really cool, we're going to get into the really gritty details of what these do, really cool methods to just invoke other methods, it's a way to invoke other methods. We'll talk about the behaviors. Here we have our dog object, first, but we're also going to have a cat object. Defined, and cat will have a bark count of 0. Because cats don't bark. So cat will have a bark count of 0. Then, for those that have seen the call and apply methods, we're going to have dog.bark.call(cat, 1); in this scenario, what do you think that this keyword will be? If you haven't seen call and apply, don't necessarily get hung up on this too much cause this probably looks really weird. Cat. Cat? In this case it is cat. So, how many people are really comfortable with all the slides we just did? Like oh yeah that makes sense to me. Is anybody just like, oh this is easy. Nobody? Okay, actually, we're going to make it really easy. There's a really simple set of rules that all of those sides actually followed. But it's not what you would expect especially if you're classically trained in a statically-typed language. I say classically I mean class-based statically-typed language. If you're coming from that kind of background this is going to be really, really weird to you. But this has four simple rules. One, is the call operator. Actually I'm going to come back to that one last. The .call. If you have an object, on the left side of the dot, specifically the dot call is the dot operator, with invoked method, an invoked function. So puppy.bark. If you're using .call, this will be set to the object that's on the left side of the dot. In this case puppy. So if you have object.method, or object. you know the function that you're calling, that object will be your context. Inside that function. You have the new keyword. New keyword you say var puppy = new Dog() If you're invoking a function like a constructor, if you're using the new keyword in front of it, the context will be the new object that you're creating and returning in this function. So in this case, new dog will create a new instance of a dog, a puppy for example. So the context within your constructor, will be puppy. And finally, you have call and apply. Call and apply both do exactly the same thing, but in JavaScript if you're familiar with the term method overloading, in JavaScript we don't have method overloading, it's just whatever's last wins. So you had to call, if you have something with two different signatures that do the same thing, you have to call them two different names. Call and apply do the exact same thing, I'll talk about the signatures here in a second. But what they do is invoke a function, with a context that you specify. Saying I want to use this function, and this inside of it will be whatever the first argument is. Now the signatures for call will be context, argument one. So that number 1 will be the first argument that gets passed into the bark function. So call will be context, argument 1, argument 2, argument 3. Apply will be the exactly the same thing, except it'll be context, array of arguments. Two different signatures that do exactly the same thing. A really succinct way to think about this is in JavaScript, functions don't know where they live. And this is the hardest part to really grasp if you're coming from a statically-typed language. In JavaScript functions don't know where they live, they only know how they are called. If you're in C sharp or Java, and you have a method on a class, the function does know where it lives. This will always point to the instance of that class. But in JavaScript, up until now I'm not going to talk about the class and up and coming. Up until now, this, there is no concept of classes. This will only point to one of these three rules. If none of these three rules apply, it will point to the window. Or the global, whatever the global object is. In node it's not window, it's something else. But in a browser it'll point to window, if it does not meet one of those three rules. Does that make sense? Okay. I know that was a lot of uh, yes? The secret I always say it is, it doesn't matter how function is defined, it only matters how a function is called. What matters, what it's this is going to be it. Yeah. How a function is called is the most important part to grasp. Yes-- For what this-- For what we're talking about here. Yes? Somebody was asking, why do we need both call and apply? And then they also just want you to run through these again. Sure, okay. So call and apply, goes back to the method overloading. They do exactly the same thing, let me show you, let me just write it out. So if we wanted to do dog.bark as the method, as the function that we want to call, that we want to invoke I'm going to stop using the same word over and over. Let's say our dog equals an object, bark is some function, and maybe bark takes a count of how many times we want our dog to bark. We can, oh sorry. Thank you. We can call, we can invoke this with the context that we specify two ways: We can say cat, I want to bark once, or dog.bark.apply(cat, these two will do exactly the same thing. It's the signatures that matter. Because if you're writing something in like C sharp, you could say, call, I'm going to write C sharp, if it was in JavaScript syntax forgive me. You could say function(int count) { }, and then right after that you could say call: function(array counters) { }, something like this. This you can't do any of this in JavaScript. One will just overwrite to the other you can't have the same property twice in JavaScript. So no method overloading, because of that you just have to give it a different name. That's really the only reason they have two different names but they do exactly the same thing. Just different signatures. What is the difference between so there's call and apply and then there's bind, how is bind different than call and apply? Are you talking about JQuery's bind? No just the, is it an active script 5? Like prototype that bind function? Do you want to? When we implement JQuery's proxy, which does the same thing, you'll probably fully understand. What that does. Is there another question? Okay, cool. Just running through all the-- Oh, let's do the rules that's what we haven't done yet. Okay. So we have the base rule, which is if none of the other three rules apply, if no rule is followed, it's going to be the window. So if you're just invoking a function, by default it will be the window. If you're using .call object. some function, it will be the object. So puppy.bark, this will be puppy. The new keyword, will set the context for us to whatever newly created object we have. So if we say new dog, this will create a new object in memory. And we're going to reference it, we're going to point puppy to that, but inside that function this will point to our newly created object as well. So puppy, in essence, at the end of the day. Then we have call and apply. This is where we can invoke a method, but hijack it if you want to think of it that way. We can take the method and say, I will invoke this function but with a context that I specify. I like the fact that dogs can bark, and I want to make my cat bark. You can do that kind of stuff in JavaScript. And this is going to become really, really handy not because you can make cats bark, but because we can take some really, really useful methods that we don't want to implement ourselves, but use their functionality for our own purposes.
The Dot(.) Operator
Let's talk about dot. The dot operator. Here we have, we're going to visualize what this code is doing in memory. As we set it up. So we talk about foo = { }; we're just creating a new object in memory. If you remember from our comparisons, curly brace double equals curly brace, we're creating two objects in memory, so just using the curly brace syntax, we have a new object in memory, and we're pointing the foo pointer to that new object. Then we're going to call foo.toString. Now instinctively we kind of know this is going to work. But our object is empty, there's no toString method so how does it find, how does it invoke toString? We all take, you know we know this kind of stuff just to exist in space but it has to be wired up somehow. So what this is doing behind the scenes, is we have our foo pointer, which is pointing to our object in memory, we're creating, we have our, oh. Thought that should've all come up at once. We have objects, when I say capital object, this object here, this is the base object that everything inherits from. Which is a function, object itself is just a pointer to this function in memory. This function, this is going to lead a little bit, so. Hold on, we'll get through this, has a prototype property which points to an object in memory, it's proto will point to null. This is the base object, so if you've ever heard the term proto-chaining, it's walking up its proto property to look for other properties. Don't worry if this is a lot to digest, we're going to keep diving into this with prototype based inheritance. But this is where toString lives, toString lives on the base object's prototype. Without getting too deep into prototype-based inheritance, you can think of, if you're familiar with the concept of classes, you can think of a class as the blueprint for all newly created objects. You can kind of think at a very abstract level you can think of a prototype as that same blueprint for all newly created objects. So this is the base objects blueprint. And it has a toString method. Then what we're doing, when we created our new object, in memory, all we're doing is wiring up the proto chain we're setting up our objects proto property to the base object. All newly created objects have a proto property that point to the base object by default. Because everything inherits from the base object. And this is how we find our toString method. We start at foo, we say foo.toString, we start at foo, it points to this object, and we say hey, do you have a toString function? This object doesn't have anything, so it walks up the proto chain to the next object. And the next object says hey, do you have a toString function? It does, and it chooses to return it and then invoke it because we're calling it. If it didn't it would walk up the proto again, hit null and just return undefined, we don't have anything, we've walked all the way up the protochain and we haven't found any property that you're looking for. Once it finds it, it returns it, we're invoking it so we're creating a new call object, and this inside of this call object is going to point to the original object that we're calling it from. Because we use the DOT call operator so the left side of the dot is our foo object. So this even though toString lives higher up the chain, context wise this is going to point to our foo objects. Yes, question. There's a question on this just little, those in capital letters are concepts. Are concepts? It's what represents, you're talking about, like prototype and objects? Yes. Okay so, prototype is actually a pointer. I think it was just in all caps, for the style. It should be in all lower case. Yeah it should be in all lower case. We'll just change that. Prototype, there we go. Okay, object is just these circles, we could just use circles, I put a label on there, object just to say what they are, but these are the actual objects in memory. Everything on top of a little arrow is a pointer. And there was a question a little bit back on this, when you're using this do you have to always think about how you will be calling the function in which you are using it? Yes, and that part's hard to say because if you're providing an API, you're still going to have just like any arguments you're going to have expectations of how it's used. But you're really going to want to think of it just as, just as, you want to think of any kind of function just in their own sandbox I would think. Just like you're passing in arguments, you can do crazy things like pass in an object with a toString method. If you're familiar with that function so you could do the same thing with this. If someone is familiar with a popular method like array.slice, we could override the context for our needs that doesn't mean the author of the slice or splice methods on array should've been aware we're going to do things, they would just expect this to be something that they expect. If that, I feel like I used too many nondescript words in that description. I would just say that, it's good to be aware of what you want what this should be, especially if you're using it. If people are using your API appropriately. Yes. And how that works, you should know and that's why we're training it, however if you are, you don't have to guard against unexpected values of this. Like I could create, I could create a prototype function, or something on the prototype of an object that uses this calls this.name or something like that. And I should have to check if like, if this is actually an instance of my constructor function or maybe this is the window or this is something that I don't expect and throw in an error or something like that. I don't think you need to write code like that, and you really shouldn't, but it's good to be aware of how this works. So that you can steal it, and like steal functionality for other things, and kind of do mixing behavior, we'll see how you can kind of exploit changing this, but you when you're writing code that talks to this, you shouldn't have to worry about it. I can name really quickly, here we go, without going too far into this, into this, when you're doing checks like that, when you're checking what this is and then executing some logic after, it actually initially it might make you feel like it might make simpler for users of your API, but the end of the day it creates a little bit of a confusion factor. So, we're going to see a couple of examples of this without giving too much away and the exercises we do I'm not sure we're going to get to the end today or tomorrow, but we're going to see that type of a check. Where you're checking what this is, what it can be and then going one way or branching the other in logic to execute something in a function. That's a really abstract way to say I agree with Justin, but there is a situation, a very popular situation, where it's going to be weird. Okay. There's one more question, is proto the particular instance prototype, as opposed to the static objects prototype? Is proto the particular instance, okay, so one way to remember protos and prototypes cause all those can get really, really confusing really quickly, from our perspective, from the consumers of the API's perspective, functions have prototypes, objects have protos. It's an easy way to remember this. Functions have prototypes, objects have protos. Objects proto points to whatever it is inheriting from. This is the path it's going to take as it walks up to look for properties or methods. A functions prototype is if you're going to construct a new like if you have a foo object and you wanted to create a new or a foo a foo is a function, or object on there, if you wanted to say new object, we would look at the prototype object as, and this is where we would point our new objects proto to. This is how we would set up our pseudo inheritance. It's not true inheritance, it's just a way to look up properties and methods.
Exercise 2: Finding Properties
Let's do an exercise here, I apologize for the crowding, of the slide, there's a lot of text up here. But, let's create some people. We have a person constructor, this is all, available, there's a, test.HTML in the JS folder, exercises, I'll put that up here as well. We're going to make this possible. This exercise possible. We're going to say var person = a function, this is going to be our constructor function, it takes a name, and it's going to set the name to the context of whatever person we're creating. So here we have, person to prototype, this person is going to be true. This is just going to make sure we can, walk up later on. Cause if we're setting something on the prototype, when we use our dot operator, we should be able to walk up the chain and find it. The same way we looked for if we had foo = new object, and we said foo.toString, by invoking toString, by using dot, we're able to walk up the protochain to find where toString actually lives. We're going to do the same thing here for person, so the first four lines is just our boiler plate that we're giving you for this exercise. Excuse me first five lines cause the var person = new person. This is what we're going to do. This is actually a really good exercise to do whenever you're trying to get familiar with the internals of a language. We're going to say dot is going to be a function, it's going to accept person and then name as an argument. This is going to be the same thing I want to have the same functionality as saying person.name. So you're basically going to be implementing JavaScript with JavaScript. To get two to incept your own stuff. We're going to do the same thing for person.isPerson. We're going to say DOT(person, 'isPerson'); as our argument. This is the property we want to look up. So if I say person.name, this would return Smith, I would expect. If I say person.isPerson, I would expect this to return true. This is what our two function calls should do. DOT is going to take the object that we want to look for, that we want to traverse, and the property we want to look up, in this case there's only two, name and isPerson. DOT is going to have to walk up the protochain, right, cause toString isn't at the start, isPerson isn't at the start, you have to walk up to each additional prototype to say hey do you have this method or property? One more hint, there is a way to check if the object that you're on has that property. Like is this property defined on you and not on your protochain? I just want to know do you specifically have this? And there's a method to check for that. That's has own property. That will check to say hey, I do or don't have this method or property. Does that all make sense? I see a lot of blank stares. Cool, do you have any questions before we get started? And this isn't like a closed book we'll be here to help you too. Through the course of the exercise. So, try not to, I always said that for the example, if you're trying to write something that's going to walk up the protochain, you could effectively do this with one great line of code, just simple line code just use the index operator that doesn't just keep walking up the proto property, don't write that way because it's cool to actually walk up the protochain. It's going to be recursive function. Is another hint, and we can help you with that. Any other questions? Cool, let's take what, 15 minutes? Do the exercise, and then circle back? To understand recursion one must first understand recursion. And let's do it. A little bit of advice. And let me put the, Justin just put the paths in the chat. But I'll put it up here as well. Make this smaller. Another cool thing about this is we're going to write the DOT call, the new operator, and I think the instance of operator in JavaScript, which, if you write this and understand you will really get how the DOT operator works. It's not that much different, you'll understand what's happening when the new operator calls a function. The code is only going to be about five lines for the new operator, it's pretty simple, but it is hard to write, and it's going to be kind of hard to come up with, but it's good to kind of flex those muscles trying to think of how you could write a DOT operator.
Exercise 2: Solution
This is one of those exercises where, if you're just shown the answer to it's really simple and it's like oh this just makes sense, but when you're exposed to this for the first time or if you're working in a language maybe you're not familiar with all the constructs this is really, really a good type of exercise to understand everything that's going on. So let's walk through how this actually works. So, I'll close this, okay. So we're going to have, let me open up my test page as well. This is it right here. JS test, alright. Got my console, and we got our failing test, I'm just going to rerun this one single test over and over. Okay so this is a test we want to make sure passes. So the first thing we want to check is if our current object actually has that property we're looking for, if we have it right then then we don't need to go anywhere we can just return it immediately. So right off the bat we can say, if obj.hasOwnProperty(prop)} Then return it. And then otherwise keep walking up proto chain. It's always good to verbalize what you're actually trying to construct. Cause once you verbalize it, once you can get it in this kind of pseudo setup, finding out the syntax to make sure you can access certain things actually makes it just comes a little bit more naturally. So right off the bat, if our object that we're currently on, so if person has a name, in which our case it does, just return it, right off the bat. Now, this trips people up a lot because maybe we're not familiar right off the bat with JavaScript being a dynamic language. This is still sinking in, so, you might be inclined to do this, first. And this is okay, this is actually really common. What this is going to do though, this is going to look for specifically the prop, like P-R-O-P property of obj. Which in our case isn't going to exist for any of this. What we want is the value of prop, so we're going to use our bracket notation. This will look for any parameter that we pass in. So this will return person and name, if that's what we're passing in in our case. Otherwise, keep walking up the protochain. There's a couple ways to do this, you could do this with a loop, although I've seen less and less people even go that route these days which is nice. We're just going to recurse up. So I'm just going to say else, and then we want to invoke our function. That's the first step right? So we want to, we know we want to do at least that much. We want to call ourselves again, except, with obj to walk up the protochain all we want to do is call it proto. And then pass the same prop. This is going to keep looking, up and up and up every proto's pointer until it finds an object that satisfies the first condition, and then it's going to return it. Now this at face value, we're like oh, we're accomplishing all the test's goals. So let me save this file, and we're going to go over to our test, refresh, and it still fails. And this is the weird part. Well this isn't the weird part this is the part where, anytime you're dealing with a recursive function you might get lost, in where you actually are. So let's step through this and figure out what this problem is. There you are, here, let me make this smaller so I can see it first. Sources. Okay. Blow this up a little bit. I think I can do that. And, we'll do this. Okay. So the first time we come through here, I think for our test, let me see what we're doing in our test. Yeah we're doing person with a species and speak. So it's not name in our case. We have a name on, the constructor on the instance. So the first thing that's going to come through is, obj, and prop. So the first things that are going to come through when we step into this is we're going to have the instance of a person, which'll have a name of Alexis. And the prop that we want to look for, which is species. Now we can see immediately right off the bat that this prop, this property doesn't exist on the current object, we're going to have to look for it somewhere. So we're going to step through, so the first condition fails, cause it did not, the object we were on did not have it. So we're going to recurse up with our objects proto, and the same property we're going to look for. So let's step into this. Now we are at the second level of this DOT call. We're going to say does this object, and you can see it over here on the right, does this object have a species property? And it does, this is going to pass. So we've passed our if-statement. So we're going to return obj prop. But here's the trick. It's going to return to the DOT function that called it. It's not going to return to, all the way to the front, which is right here. It's not going to return to the initial invocation of it. It's going to return just one level up. So here, we need to make sure we return. What the recursive call is doing. And then, if I turn this break point off, play, and now our test passes. We're able to go all the way down, which is just two levels in this test case, find, I shouldn't say all the way down, all the way up the protochain, find our species property in this scenario, return it to the DOT call object that initially invoked that recursive step and then return that function is going to return all the way to our test case. Right there. Does that make sense? Let me put up the answer while I talk about that. Now there is the case of a few people a couple people stumbled on it, what if nothing has this? So there is the case of walking all the way up to where it's going to be null. So here, if we were really doing this we should probably do something like you know, if obj.proto and then the actual else case would just be like, return undefined. For catching all scenarios. But you don't have to put the, return undefined. Yeah that's true you could just do this. An empty function will return undefined. Does that make sense? Does this part make sense, I kind of lost over that but if you have a function that doesn't return anything, versus a function that's explicitly returning undefined, you don't have to explicitly do this part. That was just for, me being explicit on a set of slides. Any questions over this? It's relatively simple like when you write it out, it's only a few lines of code, but it's actually covering a very, different concept, I don't want to say complex cause it's actually a pretty simple concept but if you're coming from a statically typed or a classical based language, this is weird. This is very, very different. Talking about protos and pointers and prototypes. It gets a little weird. Cool? Okay, whoops. There's a few questions. Yes. Where are we in the questions, here? Can you call the function of a cursive lead with this call? With this call? I'm assuming they just mean the call operator, but I would say that you could use a call operator called dot dot call but the dot function doesn't actually use the keyword this. So there's no reason for doing that. If you wanted a set context within DOT, yeah. But we're about to touch dot call here in a second so maybe clear some of that up, so. Any questions on this so far, this is just walking up the protochain and finding a property we're looking for somewhere on that chain. That's all this method is doing. That's all DOT does on its own. One thing to mention is just JavaScript is a language of conventions. The proto property on an object is really just like every other property. If I put a foo property on an object that's just like putting a proto property on the object, the only difference is that the DOT operator magically just is programmed to look at the proto property and just keep walking the proto property. That's it, just a normal property called something weird. And it just, the DOT operator works with it, to find stuff. It's that simple, it's just conventionous. I like that. It's a good way to explain that. Cool, okay. So if it hasn't gotten weird enough. Let's take this a little step further. We were just talking about context, and we were talking about what you know this could be in a certain set of situations. And we said remember one of our rules, do you guys remember one of our three rules for setting context? Can anyone give me the three rules? Any one of the three rules, or four rules, there's a base rule too. How do you set this? What are those rules, anybody? New, and-- The new keyword, that's one rule. Any others? Just call, call and apply? If you just call it, oh call and apply, that's another rule, if you just call the function what is it going to be? The window. It's going to be the window, that's the best case, and what's the last rule? Dot operator? Dot, call, yeah, dot and the invoking a function. Dot call is one of our rules, and it will set context to whatever is left of the dot. Okay that's really, yes, question? Just real quick, somebody's asking me can you just show re-debugging in Chrome can you show how you're doing that? Oh , of course, yeah, yeah. So these are Chrome's dev tools. I'm always on the side of use whatever browser you're most comfortable with. Just please make it a modern browser. I use Chrome, I'm very comfortable with the dev tools, a lot of the guys on the team are mostly guys on the team are either Chrome or Firefox, both have really, really good sets of devs tools. And the other browsers have really, really come a long way too, so. But for this, this is really, really nice. I pop open a console, I'm doing this from sources. If you go to the sources tab, you can see all the scripts, all the resources, you can see on the left side a folder structure. This is everything that this page is requesting. So in our case we're requesting an HTML file that's the page you see, and we're requesting a JS file that's what's actually, we're running our tests against. You just explain how you got that up? Oh yeah, on a Mac it's well you can go to over here the little hamburger icon, and you can go down to, more tools, thank you. And developer tools. Any one of these will open a particular subsection. If you're on a Mac I just press Command+Option+I. Cause I have it memorized. I forgot where it was on the menu for a second. And I think Command+Option+I will actually open Firefox as well. Is that, I'm pretty sure the same shortcuts are, everybody's doing the same shortcuts these days. This'll open this up, then you can actually click on the file. This is nice cause if you're familiar with you know C sharp and Java, being able to step through is really, really nice. So these browsers make this part really easy when you want to see what's going on. So you can add a break point, all I did was add a break point over here. I can add a bunch. They'll show up over here, you can see breakpoints you can disable them, which is nice. And then I added a few watch expressions. I'm watching for the obj and the prop variables. You'll notice they're not available at the moment, because we're not in the context of running our page. So those only exist because we have them wrapped in a closure. And at the time of running you'll see what that evaluates to. So if we were to run this again, and I enabled the breakpoints, we can see at the time of this function's evocation, I can see hey the person is this. Like this on the screen, and prop is species. Which is really, really nice especially if you're dealing with loops or recursive or just a lot of modules or a lot of JavaScript on the page you want to see what exactly it is because as a human it's really hard to interpret you know wall of just text and know what the output is. You want to be able to step through and see oh I is not being reassigned, that's the problem. Immediately, so, this is how we do all that. And then you can step through step over, just like most debuggers. And then play to get out. Which is nice, so, familiarize yourself Chrome or Firefox I think have the two most comfortable sets of dev tools they're all getting pretty good these days. They're all getting better.
Exercise 3: Invoking Functions
We've done dot, which is cool. We've done our test passing with the dot exercise. But, what if we wanted to do something more than just find a property, what if we wanted to find a function and then invoke that function? This is the trick. Because remember one of our rules was, dot call, right? Dot and then invoking a function. And the context is going to be whatever is to the left of the dot. Regardless of where that function is found on the chain. So, we have another exercise. Let's write a dot call, let's recreate that same functionality but we're going to use this dot call method. So if you have those same two files open if you have the test page in your browser, and your template file open, and your IDE, we're going to use this type of setup, we're going to create var person, this is the same construct that you already have. And then we're going to say prototype dot speak, we're going to add a function onto our newly constructed objects, prototypes, proto object. So a little bit up the chain we're going to add a function called speak. And it's going to console log hello, plus this dot name. And this, this keyword should be the instance of our newly created object. So we can say var person = new person Smith. And when we should, when we get, person comma speak comma and then an array of arguments we want to pass in, in our case we don't have any arguments we want to pass them. This should be the same as saying person dot speak. These two lines will be equivalent. The part that's grayed out is just the signature, it's our API we want to meet. The big hint here dot call will set context. Dot call will invoke a function and set this inside that function. Does that make sense? Is there any questions on what you see on the screen? Yes? One of the questions was, can we use our previous function dot? You totally can. You totally can. Good question.
Exercise 3: Solution
So let's walk through this, how many people solved it by the way? Anyone get through it? Kind of, one, I know one did, somebody was talking about which type area do I throw I was like alright you're getting really deep in there now. Okay. So the first thing we need to do if we're talking about let me show the exercise real quick. If we're talking about finding, or invoking a method with specified context the first thing we need to do is find a reference to what we're looking for. I love the question that initially popped out in chats can we use our prior method? Totally, we can totally do that. So I'm going to say, I'm going to call this F-N in my example. And I'm going to say dot obj prop. We just wrote a method, to walk up the protochain and find a reference to a property. So this will go through, obj and its entire protochain looking for prop and return a reference if one is found. So in the next case we can just say if something is found, really, if you want to get really into it, there's going to be better checks. I just want to say if something is returned, if we actually have a reference to something, then invoke it. So you could, this is the first place you would maybe think to go it's like okay now I need to call the method. But this doesn't, there's a couple things wrong with this. One, args is going to come in as, in our test case, this is going to come in as an array. So maybe speak takes in our test case speak takes a string argument. But we can't just pass in args itself because speak expects this expects a string, foo, not an array of strings. So this is a little right off the bat the signature's going to be different we can't just pass in args. And, the second problem with this is context, right, if we just invoke a function, like F-N open prin, what is this going to be inside this function? What do you guys think? Window? It is going to be the window. Because, let's talk about our rules. Dot call, new keyword, and? Call and apply? Call and apply. This doesn't meet any of those rules, it's going to be the window by default, so in this case it would just be the window. But, one of the requirements we had and one of our rules really matches up nicely. Right? We have a rule that says you need to invoke this function with a context that we specify. It turns out one of our rules call and apply by definition invokes a function with the context that we specify. So that's kind of nice. So we can do call, or apply. Now these take different signatures, if you remember call takes context, and then arguments such as that apply takes context and then arguments such as that. For our usage here what do you guys feel like we should be using? Or what do you guys want to use? Apply, because we have an array of arguments it turns out being passed in, that matches up really nicely too. It also might match up because we planned this exercise in advance, one of those two things I'm not sure yet. So here we're going to say, obj args. And we need to do one last thing for this particular exercise, what do you guys think that is? There's something still missing, but it's not always immediately obvious. Return it? We have to return the value. Invoking the function is cool but we probably want whatever value is coming out of that. So let's check this out, and boom, we have a passing test. Which is kind of nice. There's also a really nice way to illustrate how this works in memory, a couple of you guys have drawings on your notepads, but we'll have Justin come up here and show you a really nice representation of what's going on behind the scenes. Thanks for suffering through that. Now I'm going to try to explain it like kind of we did this a lot as we were training, beating you over the head with something hard makes struggle and then I try to explain it really good after. So I'm going to try my best to explain a high level of what's going on because we just assembled a lot of different things we had just previously talked about. So again on a high level you were just trying to do was implement, make it so the dot call operator this person dot speak, actually works. Right, so we're implementing that ourselves in JavaScript. And that needs to look up a property in memory, a function in memory like the dot operator does. And then call it in. So let me draw what's going on in memory and why this dot call's doing what it's doing. So if here's our call object, we're creating a person, object, and memory. Let me know if, see it already, I'll try to draw it on this side. So here's person. So person is going to point to a JavaScript object and this, or sorry, person's going to point to a function and this is a prototype property. It points to an object, in memory. And then this has a speak property that points to another function area. So here's that speak function. I'm going to share it like this and then I'm going to make this speak property. That's what we set up with the person prototype speak. Again prototype is just like a normal property. We'll see how it's just like a doppler uses the proto property, the new operator uses the prototype we'll see that in a second. And then what's going to happen is it's going to do new person with Smith. What that's going to do is create a person instance in memory. Who has its proto property, pointing to the person's prototype object. And this is going to be lowercase person. Okay. So the dot poll operator is trying to do person dot speak and then call it with some arguments. The, can I escape out will it take me back to the slide real quick? Yes, hit escape. That'll get you out, now hit Command+Tab. I'd hit Command+Tab until you get to the slide. Okay, so let's see where do I get to this test right here? Okay so here's the, wait. So, quick, okay so we created this person. We had that person has that speak function and things like that. What would happen if I called person.prototype.speak and I called it with, let me show what this is saying up here. I'm just going to copy this function over again which is okay to do. So you can see the function and what I'm doing in the same place. If I called person.prototype.speak like this and I did Alexis, what would this return? Anybody? Anybody confused about this? Like what, I can call like this? All I'm doing is person.prototype.speak and calling it as a function. Isn't it expecting an array? Speak is not, it's just expecting a to whom. It would be hello Alexis my name is undefined? My name is undefined, exactly. Because this is going to be what? Referring to the, window? Good guess, but it's actually going to be referring to the prototype object. Because remember, the dot call operator always uses what's left of the rightmost dot as this. Right so in this case, it's going to be, it's going to still say undefined but this is going to be person.prototype. Now let's say I changed it around a little bit, I did var speak equals that. Now I were to call speak like this. Now what would this return? And what would this be inside this function? You mean to do it to the method instead of to the vocation method? What? Oh sorry, my bad. Sorry, yeah, that's what I meant to do. So I've just set a variable speak equal to person.prototype.speak and I'm just calling it. What would this be? Window? Window, exactly right, and then what would name be? Window, it would be this dot name. It would be, probably it's actually going to be an empty string just because window is name property, defaults to an empty string. Okay so that's all, that's a little quick recap of the dot operator, how it's supposed to work, right? The dot call is supposed to take what's on the left-hand side. Now the reason why this code is the way it is. You can get rid of that. So the reason why this code is the way it is is it going to the person, and it's trying to find the speak value. So we're using the dot operator we already created, which is going to go look for dot sorry look for speak property on person. It's not going to have it, it's going to walk up the protochain, find the speak function, and just return that function as F-N. We would just have this floating function. It doesn't know at all about this person because functions really don't have any, it's all about how functions are called, not about how they're defined. So we force the issue, we kind of force it so that right we're going to call this function, so person, is what this is. That's basically another recap. Does that make sense? Hopefully a little bit better now? Kind of see the bigger picture? And what I can say is that this person object here has a name. Which was, I don't remember in our example. Something, whatever it was in the, whatever it is in the example. Alexis? Alexis. Cool. So hopefully that makes sense, the bigger, hopefully you can kind of start, our whole goal for this is that you guys can start seeing code you know person constructor functions, things like that, the dot call operator, and kind of see what it's doing in this memory diagram. Thanks, sorry for interrupting. You're good. Feel free, if you have any questions at all, even if it comes to you a little bit later today. Let us know, this is hard. This is really hard if you're coming from a statically typed language. Or like a Java. Because all the constructs, all the rules, JavaScript has very simple set of rules but they're very different. From Java. So, cool. Alright, okay. So, in summary, we're going to go through something very similar to this diagram. If we have var d = new Date we just have a new instance of date, d.foo = 'bar'; d.hasOwnProperty(); where all these method and properties are going to live, is something like this. We're going to have a d pointer, pointing to our new object, which is date, it's going to assign we have a foo pointer, this is actually a foo pointer, pointing to a primitive string. Called var. It's not going to have has own property here, it's going to have to keep going up for our date prototype. This is because we've created a new date, r object proto is going to point to the prototype of our constructor. Which is date, it has things like get day and other methods. It's not going to find it there, so then keep going up to the base object. Keep going up to the base object to look for things up here, and this is where it's going to find something like hasOwnProperty. And then it's going to do the same thing we just went over here invoke it with that context. It's got it, and we are good.
Prototypal Inheritance
Shared Properties and Prototype Methods
Prototypal inheritance, prototype based inheritance, Inheritance is a loose term, but how we treat the concept of inheritance in JavaScript. Let's talk about prototypes. Prototype based inheritance, how we can reuse methods or functions in JavaScript in a smart way. So, let's talk about, we're going to talk a little bit about maybe what we would consider unexpected behavior, but we're going to talk about how we can kind of manipulate this to do some really smart things. So, first thing that most people would consider unexpected is the concept of properties on, in an inheritance tree somewhere. So let's observe this code really quickly. We have an animal function, and inside our constructor function, we're going to say this.offspring and it will be an array. So every time you create a new animal it will have a property called offspring which will start out as an empty array. Then we're going to create a dog and when we, the way we link objects together, or constructs together, is by saying something like dog.prototype = new animal this is what is going to link our proto to the prototype of our constructor. I know that's a mouthful when you think about all those big words at once, but that's exactly what we had on this little diagram. Is we're creating a new object with its proto-property pointed to animal's prototype in this case. So that way if you're looking for some kind of method or property on dog, on an instance of a dog and it's not found, it's going to look up its proto-chain and look for those same methods on animal. Which makes sense, that's something that we would want to behave, look for characteristics to all animals, well dogs should have those characteristics as well. Then we're going to do these next three lines are going to create three new dogs, dog1 dog2, and pup. Three new instances of dogs, I think we're good there. But this is the part where it gets a little tricky. dog1.offspring because offspring is an array, dog1.offspring.push pup and technically we can push anything on we want, but we're going to push pup on there. dog2.offspring what do you guys think that is going to be? Anybody? Just an empty array? An empty array? An array with pup in it? An array with pup in it. Okay. Yeah, those are good answers. I would expect this to be an empty array, too. But it's not. It is going to be an array with the pup in it. And that's really weird, just looking, taking this kind of code at face value, but we'll show you what this looks like in memory and it's going to make a little bit more sense. So, let's talk about, this is shared properties. Let's talk about adding methods on our prototype, what this looks like. So, we had a little bit of exposure to it in the last exercise we had our speaks method. Where we wanted to walk up the proto-chain, look for a method and then invoke it with our context. Here we're going to have an eats method. All animals eat things, no matter how far down you are on the chain, as long as you inherit from an animal, you will have the function, the ability to eat things. So here we're going to have animal.prototype.eats and this function will just say whatever this, whatever the context we're using .name is eating. That's all we're going to do. What this does in memory is it creates this kind of structure. We have animal, which is a pointer to a function. That function is going to have a prototype, which is just an object, and we've added an eats function, on there. Eats is a pointer to a new function we've created. This is our footprint. So when we come along and say, sponge equals new Animal Bob, this is our new animal we've created. It's going to create a new object in memory, and it's going to set the proto-property to animal's prototype. It's a really tricky, or maybe it's a hard to memorize distinction, but really, really important. A new object with its proto-property pointed to the prototype of its constructor. So animal in this case is the constructor. And then, we're going to invoke, because animal is a method, we're going to invoke animal with the context of our new object which is this sponge down below. And all we're doing inside the constructor is setting the name property. So this.name this is going to be our sponge. And its name pointer is going to point to this new primitive string called Bob.
Prototypal Inheritance
So let's take a little bit more complex example. So we, okay, if we want to create new animals, that's cool. I want to create a new animal, give it a name, but we probably want more abstracted layers. Right, if you have a shape, maybe you want you know, parallelogram, to inherit from shape, and then maybe you want square to inherit from parallelogram. If you want many, many more constructs, many more layers, we can do that a little bit differently. Well, it's the same concept but, more times. So here's an example inheritance ladder, if you will. We have animal as our base construct. We have chordates which will inherit from animal, and we have mammals which inherit from chordates. This is the structure that we want to create, conceptually. We're going to show you how to do that. So the differences between the three things. All animals eat, chordates are a subclass of animals, they will all have spines, and mammals a subclass of chordates, they will all have hair. What this is going to do, it's going to look something like this. We're going to have our mammal function, which will have a prototype, pointing to this object in space, right now, this new object. A chordate will have the same thing, and so will animal. They will all have, they will all be constructor functions with their respective prototypes. Now this doesn't set up any kind of link between them yet. We have to do that for us. The part that we care about is each object's proto-property should point to where we want to inherit from. If we don't set this part up, everybody's proto-property would point to the base object and we wouldn't really get any kind of cool inheritance. This is the chain we want. That way when something comes to a new mammal, and we want to say, hey I want you to eat something, it's going to walk up the proto-chain until it hits animal's prototype and then invoke that eat function. Okay, that's a cool graphic, but what does this really look like? So, let's set up our proto-chain in JavaScript. We have our animal constructor, we're just going to set the name. And we're going to give ourselves our prototype method, eats. Then we're going to say chordate is a function. This is going to create this little spot in memory down below, not linked yet, it's not doing anything yet. It's just a new constructor function. And we're going to say, prototype = new animal. This is what's going to link our prototype to animal. We've created a new object in memory, with its property, with its proto-property pointed to animal's prototype, and then we're going to point our proto-pointer to that new object. It's going to create this type of link for us. And then we're going to give ourselves a has spine property, which will just say true. And we're going to do the same thing again for mammal. We're going to create our constructor function, have a prototype with a new chordate, this will link the two. And then we're going to give it its own has hair = true. So that way when we finally come along and say something like, M = new mammal, dog, because that's a really clever name for a mammal, is dog. We're going to create a new object with its proto-property and M is going to be able to have all the properties that we have, has hair, has spine, and the eats function will all be accessible on M, because we've set up our inheritance tree. I'm a little confused why you have to use prototype for eats, when you define eats up there. Wouldn't eats be inherited by chordate when you set it up? Would eats be inherited by chordate? So, how would you, how would you write this otherwise? Well if you just removed prototype from animal.prototype.eats. So if you say animal.eats = function, is that what you're thinking? Right, when you set up chordate, would it automatically inherit eats? Let's think about that for a second. So, here's our animal function. If you want to say animal.eats, where would eats go? It would go right here, right? It would be animal and then a pointer to eats. But this is down on this function, so when chordates or anything else tries to walk up the inheritance tree for eats, it's going to go to each proto-object, but it's not going to go down to a constructor function and look for things here. It's going to go here, this doesn't have eats, go to the base object, it doesn't have eats, so it's going to return the type error, method not found, or undefined. Because we've hidden it down here. Now sometimes you do want to have methods or properties on the function themselves if you're building some kind of helper library that you're using internally, but you have to have a very specific reason for this kind of stuff. This is more what we would consider a static method. Not in the strict sense, but you can think of it conceptually as this is on instances of objects, instances of animals, and this is on Animal, capital A, itself. Does that make sense? Cool, good question. Okay, now there's some problems with this. One of the problems you may have seen from this wall of text, is in the constructor, we're doing the same thing over, and over, and over. We have to say this.name. There's a way around this, it's just not, the construct doesn't exist because there's not true inheritance, you can't have methods inheriting from other methods in the strict sense. This is when you see libraries providing things like super plug-ins. But it's not inherent in the language itself. but it would make sense, if you inherit chordate from animal, you probably want to invoke your own constructor logic, you know, set up your spine. But you want to invoke animal's constructor logic, as well. You don't want to have to rewrite that code every single time you're setting up something to inherit from. So, you can do that this way. So here's our base animal, but inside chordate, we don't want to call, well we don't want to set up this.name equals name again. Instead, we just want to do whatever our parent does. So here is a really, really nice use of call and apply. Animal is just a function, so we are going to invoke the animal constructor, but we're going to set its context to whatever we are, whatever this is. And remember, one of our rules for this, is the new keyword. So when you say, varc = new chordate, we're setting the context within this function here, to the new object. And we're passing that into our constructor above so this.name will still be our new object .name. So the same functionality is achieved, we set context correctly, except we don't have to rewrite this.name = name. Does that make sense? This is really useful, because typically you're going to have a more elaborate constructor function than this.name = name. You probably want to actually set up some things. But you don't want to re-implement that same constructor logic over and over and over. Interjection? Why can't you just do chordate = animal? Why can't you do chordate = animal? Oh, I want a wipe board. Why do you guys think you can't do chordate = animal? Or what repercussions would that have? There's everything that chordate has, right? Then you just have a pointer to animal? Yeah, you'd be pointing to the same function. Remember, everything's a pointer. So in this case, if you had animal = function, this.name = name, chordate would just point, these should really be, if you want to consider these functions, an animal points to a function here, chordate would point to the same function. So basically, that would become a problem when you went to the next step of chordate.prototype.spine is true, then you set a spine true in all animals. Yes, exactly. Good question. Okay, and then of course, doing the same, you can do the same thing for a mammal. You get down to mammal, say a core data call, we're setting up the same inheritance link, but without having to reimplement our constructors every time. Okay, let's talk about our shared properties example, our issue with shared properties really, really quick. So, this is, we're going to construct that function we saw earlier, but we're going to do it in our little 2-D representation here. So we have animal = function, remember it's not going to evaluate the function, it's not going to execute it, it just knows that there is a function. So function, by default, all functions have prototypes, again. Not by default, they just do. So animal, we have our prototype, which is going to point to an object. We have dog = function, so we're going to get the same construct in memory. Then, when we say dog.prototype = new Animal, we are going to first, dog.prototype = new Animal, so dog's prototype object, its proto-property is going to point to animal's prototype and we're going to invoke the animal constructor with the context of dog.prototype. This is our context here. Because we're using the new keyword, this newly created object, is going to be our context. So this.offspring will be, this is our array object, here. So far, so good? Then, when we create our three new dogs, here's here's dog1, dog2, dog3, new objects with their proto-property pointed to dog's prototype. Remember, this is invoking the new keyword here for dog, new dog, is invoking dog's constructor, and dog's constructor is not sending offspring to this and it's not recalling animal's constructor with its context. It's an empty function. So this is just creating new objects with proto-properties pointed to dog's prototype. So, when we invoke dog.offspring.push pup, we're saying dog1.offspring, do you have offspring? No, walk up the proto-chain, do you have offspring? Sure do, here's the offspring array. Push, pup. So push this guy. Oops. So when you say dog2.offspring, when you look this up later, you're going to say dog2, do you have offspring? Nope, walk up the proto-chain, do you have offspring? Yes, what is your offspring, and it's going to be an array containing pup. So, you're right, at face value, just looking at the code, I wouldn't have expected this. But in memory, it makes a lot more sense, when you're just drawing it out, you're like, oh, yes, okay, I see what's going on. Does this make sense? Yeah? I really do draw a lot of this out, still. So, it's a very helpful tool.
Exercise 4: Implementing the 'new' Keyword
The last part of our, of this set of exercises, we're going to reimplement the new keyword, as if it didn't exist. So we're going to create var person, this is our construct we're going to give it a prototype method speak. It's just going to say hello. And then we're going to say var Person = new and it's going to have a signature of an object and then an array of arguments. Signature function. It's a function, not a, you said object. Signature of an object. Oh, signature of the function, I'm sorry. And we want this signature, we want this implementation to do the same exact thing as you would say if var Person = new Person with its arguments. And the, at the end, we should be able to say person.speak. Here's the hint to that, I just failed at verbalizing. Does that make sense? One other hint, you're not allowed to use the new keyword in the implementation of this function, because I see that a lot. Yes. So, I'm just walk, walking through the steps Yes, so let's verbalize, let's verbalize aloud, before we put this to code, remember, verbalization is really really important when you want to implement something. So what are the things that new does for us? I'll give you the first one if it's, I mean, edge things along. Creates a new instance of an object. Creates a new object, that is one of the things it does. It creates a new object. What else does it do? Sets the proto of the object to something. Yes, that's right, it sets the proto of the object to something, does anyone know what it sets to? It's exactly right. What does it set it to? To its default proto, if you don't prototype it to anything else. Its default, that answer is technically correct in a very abstract way. Function? Not to the function. You're getting close. Properties? Which function, let me ask that. Which function, do you think? I don't know, I'd call it a class, but, The prototype of, of what? I feel like there's a mind meld that, it's so close. The prototype of person, or the prototype of that. Yes, yes, the prototype of the constructor function. So if you're, I don't know if the function you were thinking was the constructor, and it is, that's the prototype. So it's going to set the proto of our new object to the prototype of our constructor. What else is it going to do? I'll throw an easy, one of the easy ones. I want to get to new object. It's going to call the function. It's going to invoke our constructor. What's the last thing it's going to do? Or one of the other things it's going to do? The last for this academic exercise. Then I'll give you the technicality. What else is it going to do? If you say, var Person = new Person, we've deciphered, it creates a new object. It sets the proto-property to the prototype of person in our case. It invokes person, right, it calls it. And what else does it do? Returns it? Returns what? Returns person, the lowercase person. What is the lowercase person? The new object. The new object. It returns the new object. These are the main things that the new keyword does for us. Make sense? So we're going to write a function called NEW in all caps that does those four main things for us.
Exercise 4: Solution
These are meant to be difficult. Like we said earlier, the are really base or fundamental concepts but they're intentionally hard. But hopefully when you leave today it will be with more fundamental understanding, stronger fundamental understanding of what we're going through. So let's go through this exercise here. Let's build up the new keyword together. So, go over to our new keyword, let me blow this down. Okay. So what we did first is a really, really good first step. I do this a lot, is verbalize. What are the things we need to do? Do you guys remember the four things we need to do? What do we need to do for this to work? Create new objects, what's the next thing? Set the proto to the constructor's prototype. Yep, set proto to constructor prototype. Set who's proto? The object's. New object's proto to constructor's prototype. Then what do we need to do? (inaudible answer) Invoke our constructor with, anything special? New object. Our new object as context. And then what's the final thing we need to do? Return. Return Return our new object. These are the essential points that our new keyword's going to do. So let's create a new object. Var o = {} boom, step one complete. Next we want to set the proto, so we know where to look for things. We're going to say o.proto to constructor's prototype, so constructor constructor.prototype. Awesome. Then we need to invoke our constructor, but we need to set the context to our new object. So we're going to say constructor. we can use call and apply because these are the methods we can use, to invoke a function, but set context we specify. I'm going to use apply because it matches up nicely with our signature here, we have an array of arguments. And apply takes an array of arguments. So I'm going to say (o, args). And then return our new object. Save this, let's go back to our test page. And our new, test, our new keyword test is now passing. Now two of you have stumbled upon this and I want to talk about this a little bit, too. Is, what happens, I'm going to go to our test page here. And we have person, let me copy this up here. Minimize these guys. So here's our constructor. So, in our constructor, what happens if you have a return value? In this scenario, what does the new keyword actually do? (murmuring) Returns foo? Any other thoughts? This is a little bit of a weird edge case. It will return foo, if you're actually for primitive strings, do you know off the top of your head, Justin if this will actually return foo? There's a really weird condition, or set of conditions, not weird, but there's a specific set of conditions. I think primitives are, it still returns the object. It will still return the object for primitives. There's a few conditions here. If, so here, I'm going to actually say, if we were actually doing the true implementation, we would say something like return value, to be very verbose. And then we would pass return value through a little set of conditions. If a return value is this condition, then return it. If it's not that condition, then return our new object. But this is the case where if there's a return value, we need to check what it is. If itself is an object, we will definitely return that object. Not our new object, whatever object is returned from our constructor. So if we did something like this, foo bar. This will definitely return foo : bar. It will forget every, all the things we set up, with proto-chaining, all that's out the window. It's just going to return this object. So be wary if you're setting up constructor functions, even if you're using the new keyword. If there's a return value, this will likely override it. So that is our new keyword. There's a couple things in addition here. Oh, really quickly. So in summary, new keyword, is going to create a new object. Set the proto of that object to the prototype of our constructor. It's going to invoke that constructor, with our new object as context, and it's going to return that new object that we've created. It seems like a lot to remember. This is really, really important to when you're constructing your own applications. You're creating new objects and new instances of things, all the time. A lot of times, when you probably don't even realize it. We're going to go back to earlier today we said, what would be a case where you want to check if this is the window or not? And the new keyword sets this, there's a very popular case where you create new instance of things and you don't even realize it necessarily. Okay. In memory, very simple example. We have our dog constructor function. This is going to why would you assign? Oh, so we had a question online, oh are you handling these, Justin? Gotcha? No, I missed it. I just saw the last one. Why do you assign the proto-property, the question is why do you assign the proto-property and not to the prototype property? Okay, so again, a good way to remember this. One, well there's two things to remember here. One, the proto-property itself is special. When you're looking for a method or property on an object, if it's not there, it knows to walk up the proto chain, not the prototype chain. By it, you mean the .operator. I'm sorry, the .operator. The .operator will walk up the proto-chain. It's not going to walk up any prototype chain or any other property chains. It's just proto that's treated special. So when we assign that, it's a very explicit explicit, path that we want to go down. Yes. You could set the prototype property but it would do nothing. So we have a very simple example here. var Dog = function this is our constructor. This is what it's going to set up in memory for us. We're going to have dog which is a pointer, to a function in memory, and remember functions have prototypes. This prototype will be just a new object. And then when we say pup = new Dog, we're using the new keyword and invoking our constructor. We're going to have a pointer called pup, it's going to point to a new object, who's proto-property is going to point to our prototype of dog, prototype of our constructor. At a very simple level, this is what the new keyword does for us.
Object.create()
I mentioned at the start of the exercise, don't use object.create for this because you could, and then online there was a few questions about object.create as well. Let's talk about what object.create really does. So this is, this has actually been around for a little while. But, it lets us do stuff like this. So here is animal, I put an init function on here. Init is nothing special, it just, our concept of a constructor function. It means nothing, it's just an additional property in this case. But we're, here we have an object with two functions, init and eats, and in memory that's going to create this, that's an animal object with init and eats as properties. Then we can say chordate = object.create and we're going to pass in the object we want to inherit from and any additional properties we want to set on ourselves. Which will create this. It will create a new object, with its own properties, and its proto will point to animal. Now this is the actual memory footprint. You'll notice there are no functions, there's no prototypes, this is just two objects with a proto-property set correctly. We can do the same thing again for mammal. If we say object.create with chordate it will set our proto-property of mammal. It will also set has hair as an additional property on our new object. So when we finally say, m = object.create mammal, this is basically our newest mammal and then we can say m.init dog because we don't have a concept of passing arguments into a constructor function because these are all just objects. So within init, we can say pass in dog because we're using .call this will be m, the new instance of mammal. You'll notice, let me get the last circle, on the graph. This is a lot smaller footprint, it would seem. Right, so why would we never, why would we ever not use object.create. And this is a tricky kind of thing. Because one, there's kind of two philosophies on how this is, whether this is good or bad. But, the truth as far as performance goes, is this is really slow. This is much, much slower, magnitudes slower than just using the new keyword. The reason is, at least at the moment, now this could change in the future as implementations change, but at the moment, internally, object.create is going to call the same methods internally that new calls. When new sets up a new object, object.create is going to do that same thing first, behind the scenes. Then it's going to set the internal prototype, which is the proto, not to make things weird, because behind the scenes its named prototype, with two square brackets, anyways. It's going to set the proto again, after invoking the new functionality. And then third, it's going to call define properties. Behind the scenes. So it's going to do what we had originally, it's not going, you don't need to create all the functions, so from our perspective, from outside, this seems a lot easier to comprehend, than protos and prototypes, but behind the scenes, it's doing everything we did originally and two other steps. Just ends up being really, really slow, at least until implementations change. And this is, when I mean slow, I don't mean in 96, I mean slow like now in Chrome, latest. So, be wary of this. There's nothing wrong with using this. It's completely acceptable, this works. But just be aware of performance implications.
Exercise 5: Creating the Instance Operator
One final exercise for this suite of prototype based concepts. One really important thing we need to do especially when you're setting up your own custom chains, is check whether or not the object you're dealing with is an instance of something you would expect. Or, maybe you have a condition to say, oh if it's a shape, throw it into our 2-D algorithms, if it's a sphere throw it into our 3-D algorithms. Whatever you have to do, but there's a lot of good reasons to check for instance of. If you want to see if something is in an array. You want to probably use something like type of a keyword like type of isn't going to give us what we, the actual information that we need, but if we have an actual array, you can say is an instance of array, and this will give us true or false. So we're going to want that same functionality here. In our case, we're checking to see if our newly created person was constructed from our person constructor. Is little P, or little person an instance of capital P, person. So this is going to be our exercise. We want to create a function called instance of. It's going to take two arguments, one is the object we want to compare and two is the constructor we want to compare it to. Is this object, has this object been constructed from this constructor. Not necessarily directly. We're going to have to check the proto-chain, because is person an instance of base object? Yes, right. Is person an instance of array? No, that's one branch it isn't. Is person an instance of person, big person? Yes, so you're going to have to walk up the proto-chain to check a few properties. Let's try verbalizing this. What is, what does instance of need to do for us? You don't have to give me the actual syntax, or the actual, just using our little graph over here, True or false based on whether it's, not class, but instance of, it was created with a certain constructor. Yes. We want to check, if, I kind of want to draw. If you're going to walk up the proto-chain, so imagine we have little person, little P, which is just an object in space, its proto-property points to person's prototype. That's the first thing it points to. The second, then it's proto-chain goes on to point to base object. What we want to check as we move up the proto-chain, is is the constructor function what we expect? So we're passing in a function here. A big P, person, when we walk up the proto-chain, is this prototype's constructor what we expect. If it is, then we are an instance. If it isn't, keep walking up the proto-chain, until you find something that matches or until you reach the end of the proto-chain. Does that make sense? This method will return a Boolean. It will be true or false. True if it's found, false if it isn't. I think you said it backwards. You were saying if this prototype's constructor, it's if this constructor's prototype. Ah, yes, yes, sorry. Basically what you're doing, is you're walking up the proto-chain until the proto, the next item in the proto-chain is equal to the constructor function, that's passed in. The verbiage works both, because you have a partner both ways. But not. You do have (mumbles) both ways. Not always. Okay, fair enough. You could be not there, (mumbles) Fair enough. Does that condition make sense to everyone? Who does it not make sense at all to? I didn't understand the last part that you said. Okay, that's a specific case, but we're talking about when you're checking your conditions, you have access to the person. You have the function, and you have your object and you have its, wherever its proto is pointing to. So here, you can check your constructor.prototype and compare are those two objects the same. Are they pointing to the same place in memory. If they are, then we're an instance of that, you return true. If they are not, then let's say it's down here, keep walking up the proto-chain, until those match or if they never match, just return false. Does that make sense? Yeah, okay. One way of thinking about it is, if you have a date, and I want to see if it's an instance of object, I would just keep walking up the date instance's proto until it equaled object.prototype.
Exercise 5: Solution
Alright, so I'm going to go through the answer to instance of, this is our last exercise for this kind of stuff, it actually gets mostly, almost all easier than what we just did, for the rest of today and for tomorrow. So, we were just doing instance of, and we wanted to be able to say, hey, is P an instance of person, or is P an instance of object? An instance of person or an instance of object. And the way to do this is start with p and just check when, or person, and check when its proto-property points to the constructor functions prototype. So I'll just check, okay, is person.proto equal to person. p.proto equal to person.prototype. If I were doing for object, I would first check that. Then I would walk up again, to this, this is proto, the proto again to see if it's equal to object.prototype. So let's see this in action. So the first thing I'm going to do is just check if object .proto is equal to constructor.prototype. and then if it is, I'm going to return true. So this would work if I was doing something like instance of P and person. Right, because I'm just going to again check p proto is that equal to person.prototype return true. Now I want to make it work so if I do is p an instance of object. So to do that, I'm going to use a little bit of recursion. I'm only going to do it if there is a proto-property. To make sure that I haven't gotten to the, I didn't draw the proto of this guy, but he has, it would be null. If there is an object proto, I'm just going to return the result of instance of, pass at the object proto, and pass at the constructor function. And finally I'll just do an else, because that means we've gotten to the very top, and return false. Any questions about this? Cool. Alright, so I'm going to do kind of a little high level overview, but try to do it from a different way of just this kind of, the .operator proto-property and the prototype. So let me show something kind of interesting. Again, JavaScript is a language of conventions. You've all created an object like this. Object equals, and you give it some name property. And I'm going to put in foo. And I'm sure all of you have seen object.name and gotten foo back. This is an operator, equal is an operator and the dot is an operator. Right, these things are part of the language that do something, given some data. The dot operator, you've all probably seen it used in this fashion over and over and over again. But, you could also do something like this. I can create an object, with a proto-property, that points to another object, with a name property that is bar. I could just, then if I were to write object.name, this would give me bar. This is all that the dot operator is doing. It is just saying look at on the current object for a name property, if it doesn't exist, look if it has a prototype, a proto-property, look there for the name property. And I could go as deep as I wanted, I could just keep going. Proto, then put in name property and I would still get bar. Now, one thing you don't want to do, and they'll actually warn you if you're doing it. If I were to do something like this, object.proto.proto is equal to object. I don't know which level of proto I'm at there, but if I were to make a cycle with protos and try to look up a property, I think browsers, this used to crash browsers if you try to read the property, but now I think most of them detect cycles and will not let you, will throw an error if you try to do this. But just to show, it's just, there's just this magic property, and it, the dot operator just follows it. That's as simple as it is. You might be, the next question might be, why, why does it do this, why is there this special proto-property that works with these dot operators to make this crazy magic happen? The reason is, is because we like, as humans, typically object oriented programming. I want to be able to create an animal and I want to be able to call eats on it. And I might want to be able to create a million animals and be call, be able to call eats on all of them. But I don't want to manually assign an eats function on every single time a new animal instance is called. Right, so what I mean is, I could theoretically create an animal kind of like this. I could create, make animal function, and that could take a person's name of the animal and I could do something like this return, do for an animal, make an object with a name, as the name and then I'm just going to assign a eats function. Now, if I were to call this make animal, let me put some semicolons so it doesn't look like I'm doing stuff horribly wrong. If I were to call this make animal, to make an animal. This animal object that's returned would behave just like this animal object would behave just like the other animal objects that we were kind of showing, created with the new, if I was doing new animal. So I could do animal that eats. And that would give me eating, food or something like that. But who can kind of see the problem here? Kind of already mentioned it's performance related. The performance problem is that every time make animal is called, it's got to assign an eats function. In this case, it's actually recreating a function every single time. Of course we could improve that by doing something like animal eats and saving the function, so they're only, we're not recreating a function every time. But we're still setting a property every single time. And this problem would just get more, worse and worse as we added more properties. Eats, speaks, so this might be some other function. That we might have defined up here. As we keep adding functions, we have to assign more and more properties every time we want to make an animal. What the proto allows us to do is look on, directly on our object first, but then look somewhere else for potentially shared properties. And when you create a new animal instance, as you already saw, it only assigns one proto-property. There's only one property assignment instead of a property assignment for every single function you want on your instance, your little objects that you want to create. So what I mean is, if I have animal is a function, that does the same kind of thing, it's just going to do the this.name equals name thing. And I had those same animal.prototype.eats is a function, and then I also had a speaks. Okay, so instead of calling make animal, if I were to do animal equals new animal, what this does is it creates a new animal instance in memory, which is pretty much what this is doing, in assigning its name property to name. But instead of having to go through and assign an eats property and a speaks property, it just assigns one proto-property to animal.prototype. And because the new op-, or the dot operator is already wired up to look on the proto-chain for these methods, it will find it. And this way I can create lots and lots of objects very quickly, doing very minimal work. And delay the, and essentially delay the delay the cost. Because we get, make, essentially what we're saying is look up is going to be a tiny bit more expensive for animal. this kind of animal.eats, versus this kind of animal.eats because it has to walk up the proto-chain. But we're making that trade because creating a million of them is going to be so much faster. So that's why there's this proto thing and why it walks up and tries to find these shared properties. It's because you don't want to make every object have a copy of every single property. It's a performance thing. Hopefully that gives you some better context and understanding of why it is this way.
jQuery Functional Units
$.extend()
We're going to start building our own version of JQuery. And the first thing we're going to do is start building a lot of JQuery's functional utilities. Hopefully a lot of you have used dollar extend, dollar proxy or dollar make array or dollar each. We're going to be building our own versions of those, because we'll be needing them for when we build more complex things like, you know, JQuery's html function or things like that. So what the end goal again, is we're going to build this cute tabs widget with this html. So all of this stuff you can find in, so there's, let me, let me go through the set up real quick. and I'll probably have to go through it tomorrow again anyways but we're starting out. If you go to the exercises dom, you'll find a my JQuery js. That's going to look like this. And these are the things. We'll start with implementing dollar extend today and leave pretty much everything else to tomorrow. And then eventually there's a test page too, that you can open, if you open dom test dot html. So I'm going to change my js to dom up here. And I'm going to go to this test dot html. This will run all of those tests. So I'm going to explain the first exercise and, then I'll walk through again the set up. So the first exercise is implementing JQuery, a small version of JQuery's extend. JQuery's extend takes one set of properties and copies them into another object. So it takes one object, goes through all of its properties and puts them on another object. So if I have, a target and I have an object, if I call extend object into target, really is kind of how you read it backwards. It's going to take what's in object and copy it into target. So this is what you're going to be using in a for in loop. If you've never used one of those ask and we'll show you how to write one. So essentially as a result of this, result should be the same as target, so it kind of returns the target, but also result and target should both have, they're the same thing in memory but now they have that additional property. So that's the, Oh so why do you use it? Essentially, a lot of times it's used for cleaning up things. So like even in our examples, that we'll be writing our own JQuery, it's nice to not to always have to write dollar dot something equals function, or dollar dot prototype dot text equals function. Instead you can use dollar extend to kind of clean this code up so you don't have to always be writing dollar each time or dollar dot prototype each time. It's a nice handy reason to use dollar extend. And default values. This is used very commonly. Say I have a move function that moves, that animates one item from one position to another one, and if people don't provide options from and to, I want default values. Instead of everywhere from and to are found and time, having it kind of like this where it checks each individual place, what those defaults are, extend is commonly used to copy, to kind of set up the defaults to change options. So it has the default value so you can just write from that point on. You can just read from options cause it will already be set up at the default if they're, if the value wasn't provided.
Exercise 6 and Solution: Implementing $.extend
I'm going to show you the answer to extend. Again what we're going to do is go through every property in object and copy it to a properties on target. To do this I'm going to use a for in loop. So I'll show you how to write one of those. I'm going to write for, the name of a prop, the name of a variable that i want to take on each property name and object. I'm just going to call it prop. So this is going to be set to, well, I'll just write out for prop in object. So prop is going to be set to a string that is a string for each property name in object, and that's, prop will be different for every loop inside these curly braces for the body of the for loop. So I can read the property, the prop property of object like this. Maybe I'll do like var value. And then I want to set, this is the value of whatever property name proper presents. Ooh, I wrote this wrong. And then I'm going to set value on target. So I'll do target. I want it for target's prop, I want to set that to value. Does that make sense? So I'm reading the value for some given property name and then I'm setting that value on target for some given property name. I broke it up in two lines like this but most of you have just written it this way and I think it's a little bit more simple to look at like that. And then I'm just going to return target. Now some of you, any questions there? Makes sense now? Hopefully those of you who are just beginning with JavaScript or haven't seen this kind of this index operator, are starting to get it. It can be kind of like confusing at first, but hopefully it's starting to make sense now. A few of you also made sure that we were only copying the properties directly on object and not any properties that might be up the proto chain. To do that, people who did this. And this you don't have to have this in your solution for the example to work. It's checking object dot has on property, prop. So it's making sure that it's only copying properties directly on object not innumerable properties up the proto chain and copying it that way. Cool. So that's it for today. Unless there's any other questions. Tomorrow we'll probably start with another quick review of all of the JavaScript stuff and then we're going to burn through JQuery. We're going to do our own version of JQuery just big enough to implement a tabs widget. Which is going to be awesome. And then you can just publish it as your own open source project and call it zepto four or something like that. And you can become the next big JavaScript programmer. First letter of your name, Zepto. Yeah. Query. So, cool. Thank you.
Day 1 Recap
So for today's set up please make sure you have open in your browser exercises dom test html and breeds html. We'll use breeds later. Test is going to test your version of JQuery and then open in your editor , exercises dom my JQuery. which we'll be using right now. Hopefully, you have the extend implemented. If not, I will show you how to get that implemented. We implemented that right at the end of yesterday. And also open my tabs. That's where we'll build the tabs at the end of the day. So today we're going to go, it's really going to be about understanding the dom, but by building the jquery. We're going to finish up JQuery functional utils. These are just a bunch of functional helpers that JQuery adds. This is still more like JavaScripting knowledge, but then once we're done with that we're going to go into the day two agenda. We're going to talk about how you find elements in the page. How you go from one element to another element. How you read elements attributes and properties. Get and set them. How styles are computed out of elements and how layout, a little bit about how layout and positioning works. And then we'll teach you pretty much everything there is to know about events and then take all of that knowledge and our built up version of JQuery and finish the class building our own tabs widget, with our version of JQuery. But first, I want to review this, this hand out that we give. Which is kind of serves as a summary of everything that we learned yesterday. So just going to walk through what it means and what it looks like so if you ever find yourself, uh oh how did that work again? You can remember it. So remember everything, when you create a variable, it's essentially creating a, kind of registering an entry in a call object that points to whatever the value is on the right hand side of the equal sign. That's for the most part what equal does, so that's why we created this val here that points to five and the me that points to an object. And that has a name property that points to Justin. Then next when you create a function, there's a few things that happen. Or sorry, not when you create a function, when you define a function. Kind of synonyms actually. When you define a function, a function object is created in memory The function always knows about its parent call object. And the function has a prototype object that's created automatically. We didn't really talk about it yesterday, but these default prototype objects have a constructor property that points back to the function that created them. So this is what happens whenever you see a function defined like this. Again it doesn't really know anything about what's going on in here. Next when a function is called, or invoked a new call object is created. And the first things is it's arguments are translated. So you can see here it's got arg one, is the val, points to what me points to. And val is arg two, is going to have its own copy. This is the pass by reference in pass by value thing. And then it's also going to have it's value thing for this called. Remember we learned that whenever a function is called without dot, it's always this inside that function. Even though we don't show it in here, if we were to put it in here, this is going to be the window. So that's why this points to the window. So you can see when a function's called, this call object has this inside of it. That's where that comes from. And then the function is actually ran. And any variables declared in this function are also stored in this call object. So that's what happens when you run a function. Finally, let's talk about when you use the new keyword. But to use a new keyword we're going to set up a dog constructor function. So the exact same thing is going to happen. A function that knows about its call object. That has a default prototype object. Then we're going to add a speak function. So we're doing dog dot prototype dot speak. Now if you were being extremely hyper vigilant, we would also, this function itself has a prototype object and it knows about its call object. But we didn't draw it in because it would get too messy. And then we're going to finally do what the new operator does. If you remember from yesterday the new operator creates a new object in memory. Step one. And it's going to assign that objects proto property to the constructor functions prototype object. And then it's going to actually run the function. And again whenever you call a function, a new call object is created. This is going to be set up to point to, this is going to be set to point to the new instance created in memory and name really should be pointing, I just realized, to its own copy of Fido, the way that we're kind of phrasing it. Even though in reality JavaScript could actually, potentially point it here, but for this it should be pointing to its own copy of Fido. And then the body of the function is going to be run. And then it's going to set this name property to point. Actually, set this name property to point to its own copy of Fido. So that's how that gets set up. And this is why we call with the dot operator, pup dot speak, because the dot operator first we'd look up pup. We'd get this object and the dot operator would say, give me the speak property of this. Not find it. Follow the proto chain to this object, which is the constructor functions prototype, find speak and call that. Everything we learned yesterday. (laughs) Awesome. Good job, guys. Okay. So, with that, I want to make sure that everybody is kind of where we ended up yesterday. So if some people I know, left early or left online. We implemented this extend function. Basically, just to recap it just extend, it copies all the properties of from object into target and then returns target. If you're behind, or if any point you guys today, you fall behind, there's in this folder, there's a final folder, that has the final implementation of everything that we're going to be working on today. Try, if you're here working with me don't cheat. It's better for you to try and struggle and then wait for me to give the answer, because you'll absolutely learn better that way. Trying, even if you're struggling because we're giving short amount of time today. Even if you're struggling you don't do anything the struggle is good. It's worth it. It will help you learn better that way. So try not to cheat unless you for some good reason have fallen behind. So for those who are already behind cause they didn't get to do this, please go to my jquery here and copy that extend, code, into the extend code in exercises dom my jquery. And then once you've done that, and everybody should have it so if they open the exercises dom test html page, they see this first test pass. So, quick show of hands, is everybody about there in the room right now? Or a show of nodding heads looks good. Okay. So now we'll move on to the next exercise. So I thinks it's going to, Question. What does a dollar sign mean? What is the dollar sign? Yeah. The dollar sign is, that's a good question. The dollar sign is just like if I wrote, A equals something. The dollar sign is just another character that you can use in variable names and, variable names like you can use the letter A for a variable name. Right, so like I just did var. It is, I mean it's more like I did window dot dollar equals that. Which is really what I'm doing up here. So it's just like, it's often used for JQuery. JQuery's kind of adopted it as their character that you can use to invoke it, yeah. But it's not, but the thing that I want to communicate is, it's not special in any way. It's not like it has some special powers or special ability besides what JQuery either gives it, or we're going to give it. Good question. Okay. So back to this slide. There's a question in the chat room. What is a selector? Selector is just the argument. So, to be clear, we haven't implemented the dollar function yet. We haven't implemented anything except for dollar extend. We will come back to the dollar function and implement it after we implement all of these things here. But we needed like a dollar object so we could add things to it for this part of the training.
Type Checking
The next thing we're going to talk about a little bit is type checking. So it's really useful to know when a something, some variable or some property is a type something else. And how JavaScript provides ways for doing that and what JQuery also helps you with, for doing type detection. So we talked a little bit already about type of, which is great. That you can do type of something that is a number and get back a number. And the instance of function we learned about, that checks if something is an instance of something else. What you mean by an instance of in JavaScript is really that on its proto chain, somewhere on its proto chain there's an object that is the constructor function's prototype. There's other ways that you can kind of check it out too, that more or less sometimes work. But, the weird thing about JavaScript, and this is something that JQuery helps you with, is sometimes you're dealing, you're in a multi frame environment, alright. You've got a pop up window, or you've got an i frame on the page, and you want to communicate back and forth. The issue that I'll show here. So here I've created an i frame. And I'm getting the i frame's array constructor function. And I'm saving it as underscore array. And I'm creating a new instance of underscore array. If I do type of r, it gives me object. As we know arrays are always type of object. But if I do r as instance of the normal array, I get false. So if you're writing code that you want to be able to work with like, you know arrays from other i frames, it can be very tricky, to tell if something is an array or not. So yeah, all these things would fail. So what JQuery provides is a way that you can always know, no matter what host, really what you call these i frames are kind of like host environments. It's kind of like a different, it's almost like the constructor functions in that environment, those array constructor functions are different than the array constructor functions in your main window. What JQuery provides is a way to tell if the array is actually an array no matter what host environment it came from. So to do that, you can do it yourself by doing, object prototype two string call. This is basically stealing object prototype's two string method but calling it on an array instead of an object, and that will always give you object array. No matter what host environment this array came from. This is like the true way of checking if something is an array or not. So we're going to implement our version of dollar is array. JQuery's is array. So this should return true. if it's passed a normal array it should also return false if it's arguments. But it should also return true if you, get an array from a different frame, it should also return true.
Exercise 7: Implementing $.isArray()
So here's the exercise. So we're going to do this first. If the method, did I show.. The method is, the hint is using object prototype two string call. If that seems a little weird, the reason why we have people go through this exercise is because we will be stealing. This is kind of like, this is, I forgot the name for this. The objects that are kind of part of JavaScript. So we'll be stealing array's methods. We'll be using them for our own devices. Here we're using an object's two string method for our own devices on other objects. What is the word? Mark help me out. I totally forgot what the word for that is. I always said (mumbles). There's a phrase. There's a phrase for what this is called. It's not like, yeah I don't remember it. Okay, I'll look it up. It's like drawing a blank. But we do this stuff a lot. A lot of libraries do this stuff where they'll steal, Fork. It's not a fork. It's when you like use splice but on your own, like array like object. But it's not, do you know what I mean? Like JQuery does it all over the place. I forgot the name of it though. It's like not, it's kind of like duck punching, but it's, there's another term or phrase that it's called. I forgot what it's called. I'll try to remember it. Anyways, this is kind of a common pattern, stealing these type of methods but using them on your own type of objects. So we want to introduce that here where it's simple, so it kind of, you're used to it later. So any questions about this exercise before we start? It's, no? Alright so. Just to recap, it's weird to think about but it's more simple than you might think. You're really just using this object prototype two string call method and making sure that it returns object array. And as long as it does then you know, it's an array. And you will be implementing that in here. So that's your object and you just want this to return true or false if this thing is truly an array.
Exercise 7: Solution
Again this is to introduce you a little bit to reaching into hosts object functions and calling them for your own purposes. The solution to this is, this is the potential array like thing, or array or not. We're just going to return the result of calling object dot prototype dot two string. So we're getting object prototype two string method, but instead of calling on an object, we're going to call it, well, instead of calling it on an.. Like this object is two string, normally, whatever it might be, we're going to make sure we're calling object prototype's two string, with our objects. And then we're going to make sure that that is equal to object array. Is that what everybody's got? Let me make sure that that is right. I spelled it right, yep, good. Object array. Any questions there? Yeah. Why does it return arguments if you just say object string? If I say object? I just tried it out, just to see if that would work too. And why do you have to use call instead of just directly calling two string? Instead of just writing object dot two string? Is that what you mean? Right. Because well, let's say I passed in. Let's say I made an, I mean. One reason is I could do something like evil and go. Now this would return true then if I passed this object, you know if this was the object I passed? It would call, if I just did obj two string, it would return the same thing and return true. This is a way of making sure no matter what. Also, I think, but I'm not a hundred percent sure, right off the top of my head, but I think arrays have, I think arrays have, a different two string than, they have their own, on array dot prototype it has its own two string that's different than object's two string method would return. So that's partly why as well. Make sense? It's a, yeah. (laughs) I could, there's a much longer explanation but. Are you just asking instead of calling it on the prototype? Calling object dot two string? Yeah. Oh, I'm sorry. I misunderstood your question. I thought you were asking. I thought you meant this, but you meant why not. Well, no that is what I meant. Oh okay. Yeah. So that's why. It could be faked is for one. And then array's two stringed. As you can see, if I have array. It's two string, returns a representation that joined. So you could think of it as like arrays two stringed. You could think of it this way. Array's two string method just does a join and returns whatever that is. But object prototype two strings method, or objects two stringed method, what that will do is it looks up whatever that special type is. Like it could look up a special type and know the, I forgot there's a term for it (mumbles), which is like the you know, like if it's a regular expression or if it's a. Whatever those base constructors are. It will actually give you the name for it. So it will give you an array back, that's why it does it that way. Good question. Alright, so let's go to the next. Oh, lets, I'm going to first make sure, just like hopefully you guys did. Make sure my test is working. It is. Good. We'll go to the next exercise.
Exercise 8: Implementing isArrayLike()
So the next exercise is going to be making an is array like. And this is an internal method that JQuery uses. It doesn't really expose which is unfortunate, because it would be handy. But it's needed, we'll need it for like dollar each, which we'll do right after this. Is array like, just lets you know if something is like an array. It's something you could innumerate through. It's got number properties and it's got a length property. So things that are array like is, obviously an array is array like but also there's an arguments object that you can access a functions arguments it was called with. That's not a true array, but we want that to be array like and it does have you know, a length property and it has numbered properties. Things like these nodes lists that a document get elements by tag name would return. This is not a true array, but we want it to be array like. Yeah, so things like this. So, there's this concept called duck typing which is that a lot of dynamic languages use. Where you kind of check the shape of an object, and you see, hey does the shape of this object, does it look like what we want and if it does, we'll do something with it. We'll learn about JQuery's each, which just iterates through a bunch of items. If I pass JQuery each arguments, I'd like it to loop through arguments. If I pass it a node list, I'd like it to loop through a node list. I don't want to have to always convert everything to an array for JQuery each to work, but that's why there's this is array like. So we use duck typing to see which way we're going to loop through things in each. So the next exercise again, real quick exercise is you're going to implement an is array like. The way to tell if something is array like that works well, is you're going to check that it has a length property that is a number and you're going to see, you're going to see, okay, you're going to use the in operator to see if the, once you know there's a length, if there's a property that's at length minus one. And there's a special in operator that JavaScript has, that tells you if something is in something. It's like saying, does this have a property there? That's all it does. And I'll write out what the in operator looks like, because we kind of haven't introduced it yet. So if I have an object, that looks like this. Where I've given it an eight property and I'm going to give it. I'm going to make it a string. I can see if eight. I'll make another variable has eight. And I can do, has eight will be true because I'll do, eight in object. Right? So this is, this statement here will return true, if this property is in object. To make it make even more sense I can do foo, as foo, is there a foo property in object. Now I can also do a variable name. And I could write prop. So this statement will return true if the string value of prop which is foo is in object. So all you want to do is check to see that this object has a length property that is a number, and length minus one is in this object. So this is the next exercise. I will put up the, I'll make sure that this stays up. And are there any other questions before we start? There's a question kind of back on what is the difference between all is array and array dot is array? Array, oh, probably nothing. Array dot is array is provided by like most modern browsers now and that's great to use. Just JQuery's is array is going to be like, you know useful everywhere. Like an idea you can use it. But they both do the same thing. Although, I don't know if they work the same way. There might be a, I don't know how array is array works. If it's different, uses a different technique than this does. There's a question in chat. And you could just read it. Is in faster than not, not? That's a great question, Steven. It is going to be faster but also it's going to work better. Cause what if oh, what if I had an array or an array like thing that had a falsey value in it? So if I had like, if I had my object that looked like foo and it had a null. Object foo here, that would not, that would return false, cause it would knock the null ones. Maybe you want to explain what's going on there. The code here? Okay. (laughs) I'm just saying, for (mumbles). Yeah, so here I've got an object with a foo property of null. And I've got, I'm reading the property. So this is going to be the prop value, which is just going to be null. So prop value is just going to be null at this point. And if I'm notting it once, This is going to be, the value of not is going to be true. And if I'm notting it again, (laughs) sorry. This is confusing. I'm not sure how to explain it a little bit better. If I'm notting this again, well now it's going to be false. So what Steven asked is, instead of doing this in operator, why can't I just tell if object has the foo property by doing something like has foo equals not not object foo. You can't do that because if this value is falsey, well it still has a foo property, it is just is falsey so this would return false. It would normally work if it was anything truthy. Now this would be returning true, cause this would be returning false. But it's not a good method. So instead we use foo, whoa, foo in obj. So let me put back up the thing and the hint. And let's do another ten minute exercise.
Exercise 8: Solution
So Steven just answered your question while we were all working here. He asked, a better question would have been, is in faster than object and then reading the eight property double equals undefined. Well, first object double equals undefined would again, you want to maybe make that triple equals, but you can actually have an undefined property, which is confusing but you really can. So it would, that wouldn't be a good test either, but I think what you're really asking is, is reading the property value going to be faster than just telling if the property value exists. So in just tells you if the property exists. It doesn't have to go through actually reading the value. I doubt there's too much of a performance difference, but I would bet that in is going to be faster than actually go through and reading the property. Probably, that would be my guess. And there is no test for this exercise. It will be tested by the next exercise when we implement dollar each. Cause this is a private function inside JQuery that it doesn't expose. Alright, so I'm going to go through the answer. A lot of you guys were kind of struggling with this. That's okay. You know we have to go kind of fast today through the exercises. So just do your best to get through it. Ask us questions. And then follow along with the answer. So let me write out how I would implement this. So what I would do, is I'd first just make sure that the object's length property is type of, number. Okay that's good. Otherwise, it's not array like, so I would just return false. The next thing I'd probably want to do is check if the object's length is greater than or equal to zero. Cause if it's not greater than, well I would just actually I'll do it. If it's equal to zero then we're just going to return true. Cause we're not going to really do anything. And then what I would do, is I'm going to check if the object length is greater than zero. And if it's greater than zero, actually, if it's greater than zero I'm going to just make sure that that property that I'm looking for, object dot length minus one, is actually in my object. So I would just return if object dot length minus one is in object. And then actually, I'm going to delete this, because I want it so that if nothing is hit, I'm just going to return false at the end here. Any questions about this while you guys are all writing it out? If you look in the my JQuery final, if anybody's like just wanting to copy and paste. I'd basically, it's the same thing, just laid out on one line instead of with all these ifs. So walk through it again. I'm just checking that the length, it has a length property that's a number, it has to have that. If the length is zero it means it's an empty array like thing so I'm just going to return true. And then if the length is greater than zero, it could be you know maybe somebody has a length property of negative a million. Well, that's not an array. As long as the length is greater than zero, I'm going to make sure that it at least has a property right at the end. I could if I was doing it, trying to be, you know, extremely precise, I could go through every single innumerable property and make sure it exists, but that would take too long. So JQuery and I think uses this (mumbles) that it's going to have length minus one at least. As a property. And otherwise it will return false. Someone is, so some questions. Could also be written as return type of length, number and object one. Maybe, you could but it wouldn't get this lengthy, Could you repeat the question. Huh? Could you repeat the question? Yeah, okay. I kind of mumbled through it sorry. Yes, the question is could this also be written as, return type of, let me write how he kind of wrote it. He asked could this done as return type of object dot length equals number and essentially this part right here. So that would, the only problem with that is that it would, it wouldn't work if the length was zero, because it would return false. Because zero minus one is negative one and there wouldn't be a negative property in an empty array. So is array like would actually return false for something that was in fact an array. One other probably smart check that this could do, but would just be to actually check is array and then if that returns true, return true. Otherwise, check for all of this. But that's not necessary for this example. There's another question, too. I'm confused about the object dot length minus one in object part, this part right here. Okay so what this is doing is an array. Let's say you had an array like thing, the thing we want to be array like might have a zero property and then some value. Let's say this was name of cats or something. And then it would have a length property of two. What this part is doing right here, is it's checking the length, it's subtracting one and getting one and it's going to check that this object has a one property and return true if it does. Okay, that makes sense thanks. Can't we return directly without any else or else if? You could write it kind of like Steven suggested, and I showed two examples ago, where you could return without any if's or else if's. I just think that this is much easier to read. Cool. And by the way just so you guys know like, midifiers like uglify and all of that will see this code and convert into one line with terinary operators and stuff like that. So writing if's and else if's, if someone's like, hey that makes the code too long, don't listen to them. Clear code is much better than short terse code if it means someone can understand it. Okay, ready to go on to the next exercise.
Exercise 9: $.each()
So dollar each. This just iterates over something. It iterates either over an array like thing, or an object so it's going to go through here it's going to go through an array and for every item in the array, call back with the index of the array. So zero one two. It's going to call back this function. And then also with the value app that index. So A, B, C. And then if you pass dollar each a object it's going to call back with a property. So foos ed and then value bar ted. So, we're going to implement dollar each. So another ten minutes on the board unless there's any other questions. How to do this. So this is where you're going to be being passed a function and you're going to have to call that function. You're going to kind of set up a loop. A for loop or a for in loop depending on if this is array like or not. Depending on if this is array like or not you're going to do either type of loop. You're going to do a for in loop if it's not array like and a for loop if it is array like. And then you're going to call this function back for each iteration of that loop with the index and value.
Exercise 9: Solution
So we were implementing dollar each. I'm going to go through my implementation and please if you haven't finished code along with me. So here's the dollar each function. Here's the collection of either it's an object or something array like and the call back we're going to call with the property or index and the value. So first thing I'm going to do is just check if this is array like. If it's array like I'm going to do a for loop, a normal for bar i equals zero. I is less than collection dot length. And then I'm going to increment i. So that's that and I'm going to go through each item in this collection and call back call back. So I'm going to do is call back, that's my call back. I'm going to call it. I'm going to make it so it's, I don't think it matters for this example, but I'm going to make it so the this, inside this call back. is the value at i. So I'm going to write our value equals collection, that's the value there. So I'm going to call back the value, the index as the first argument and the value as the second argument. And then if this is not a array, I'm going to do a for in loop. And I'm going to do a collection. Or, I'm going to make sure that this collection has this property. So I'm going to do, if collection has own property, prop. Make sure it has, oh not prop like that. Yeah not a string (mumbles). Prop like that. So make sure this collection, I'm only getting, I'm only going to be iterating through properties that are directly on the object not up its proto chain. And as long as that is true, I'm going to be calling my call back again with the value at of the prop. I'm going to call the value. The prop is the first argument and the value is the second argument. And then I'm going to return the original collection. (mumbles) But then it's going to blow away my what I just wrote. Oh, (mumbles). No. And, You meant yes. I meant yes. Okay, now's a good time to go in there and change it. (laughs) line 28 (mumbles). Oh. Line 28. You were explaining an answer. Oh yeah, okay, I'll. So this was object dot prototype dot two string dot call object, okay. Cool. Any questions about this? They're asking a question about the syntax of value, property value. Why is it that way? Value property value, okay. So what I'm doing is I want to call, this is a function that was passed in. And this is the cool thing again, so cool about JavaScript is you can pass functions in. It's cool but abstract. You can pass functions in and then you can kind of call them. We're making our own iterator function here. What this is doing, this is a function. And remember there's the call function on functions. Which takes as arguments, the first argument is the this, that we want this function to be called with, and all of the other arguments are going to be, this is going to be the first argument. This is going to be the second argument this function is called with. Hopefully. The context of the call doesn't have to be value for our exercise and how we're going to be using our own version of JQuery. I could put null in here or make it default to Window or something like that. However, JQuery does make the, this, in its dollar each the value of every item. So we're kind of being closer to what JQuery does here but it doesn't have to be that way for what we're doing today. Yeah. Any other questions? The one question I was, the context of call having to be value. Do you see that question? Yeah that's what I was just trying to answer. The context of call having to be value. Yeah, that's just we're conforming to JQuery's API. You don't have to make it in your exercise for what we're doing today. Just I have to pass something in here so I can pass these arguments. Cool. Everybody there about? Cool, alright. Going on to the next one. I think there's two more. Maybe three more. There's proxy too I thought or did we not do proxy? No it's there. Oh, I can't read sorry. We're not quite done with that one are we? Did I miss something? Let me run my test. Yeah. Passes. Did I, what am I? I thought you had to check, cause I was getting problems with just doing the call and most of them were passing but there was one that. See it runs nine checks and like three of them were failing. Well, I'll, when we start planning. I ran into that before I returned to collection. Oh, okay. When we, I'll start the next exercise, and then I'll fix. So we'll get people started on that and then I'll help you with whatever that was. Does that work? Yeah. Okay, cool.
Exercise 10: Implementing $.makeArray()
Next exercise is make array. This gets something that's array like and converts it into a true JavaScript array. This is super useful because despite us, making our dollar each be cool with if something is array like or not it still will iterate through it, no matter what you pass it. There's a lot of things that really need an array to work and dollar make array will take whatever it is, if this is in case a node list and run through it and copy it into a real array. So anything that you pass this that's array like, that's not really array, dollar array will make it an array. So, that's our next exercise. You can actually use your new dollar each to make this a little bit easier. The test essentially just makes sure that these things that are array like are coming back as arrays. You could, you almost could just cheat and turn your dollar is array to return true and then your test would pass but don't do it that way. So any other questions about how we implement this? Again just to repeat you really just want to loop through your thing that's array like and create another array and you can just push items into that array. Or just add items to that array. There's other trickier ways of doing this too where you could steal array's slice methods. But we're not, you don't have to do it that way.
Exercise 10: Solution
I'm going to go through the answer to make array. There's a lot of high performance ways of doing that, that I'm not going to, or faster performing ways of doing it that I'm not really going to go into. I'm going to do the most simple, I think, to understand explanation. I'm just going to create an array. Let me scroll this up to the top here. And I'm going to use my dollar each. Pass it my array like thing. And I'm going to get the index or the property which I'm just going to call i and I'm going to get the value and I'm just going to push in the value and I'm going to return array. Steven asked on the chat room, what happens if this is an object and not something that's array like? Can anybody answer that? What they think would happen with this code here if let's say, I had an object that looked like like foo bar zed ted? Would it return an array of values? It would return an array of values. What would be in there? Bar and ted. What? Bar and ted. Bar and ted. Yeah, exactly right. Good job. So this kind of works even if someone passes an object. It will just give all of the, it will return an array of all of the values on the object and none of the properties. Which might not be what you want, but most typically you're using make array with something that's array like. Any other questions? Cool, alright so. Let me make sure my test is passing. That I actually, I'm showing you guys how to, to write it right. Awesome. Alright now for dollar proxy. Last one of these. But a very useful one to understand.
Exercise 11: Implementing $.proxy()
What dollar proxy does is it takes a function and makes sure it returns a new function that this will be called with any particular context you pass in. So let's say right here, I have a dog object with a speak function. Now I can create a speak proxy function. This is, by the way if you're familiar with functions bind method, this pretty much does the exact same thing. I can get make a speak proxy. So this returns a function that when I can call that function directly or I could pass it to a set time out, or do whatever with it and it will always, when this function is called it will always call dog dot speak with it this as dog. This is the, this you want and this is the function. So, if I did something like that or if I ran this on the console and hit enter, the time out eventually it would say, Fido says woof, just like we want it to. Alright, the reason, I'll kind of go into this, if it's kind of not, why you just can't pass dog dot speak here. I'll explain that real quick before we start the exercise. I'll actually explain that right now because I think it will be helpful. So, let me copy that code. Okay, so here's my dog. So if do, if I went, if I did something like this, speak equals dog dot speak, and call speak, with something. What's going to happen here? See if you guys remember the rules for the dot, or for the how this works. Is it the undefined says something. Undefined says something. Exactly right. And that's because we're calling a function. If you see a function called just with a call operator. There's no dot. If I didn't do dog dot, I didn't so something dot speak. What's going to happen inside this function is this is always going to be the window. So what dollar proxy does, it makes it so I can go dollar dot proxy speak dog. Actually, this is kind of not the best example. Says, I'm just going to say hi. Get rid of the words. I can say. And then I can just call speak and dollar proxy will make it so when I do this, it's going to say Fido says hi. Alright, because dollar proxy will make sure when this function that is returned is called, even though it's called like this, no matter how it's called it's still going to have this is what you expect it to. Now a lot of times people get confused. They would think that, oh why can't set time out do something similar? If I do a set time out and did dog dot speak in a second why, why doesn't that work? The reason is because, let's say I implemented set time out myself and put in a, it would take a call back and it takes some time. And let's say I had some access to some system timer and I could do like set weight somehow. Time, so this would pause the thread for a certain number of seconds. This isn't even how threading works in JavaScript but let's just say it did. And if I just called call back, well it would just be calling dog dot speak like with the normal call operator, so even though we passed dog dot speak, we're still passing a reference to a function. So when that function is called, because it's called without the dot operator it would be undefined says hi. Hopefully that makes sense. So we're going to try to do is to create a proxy, a dollar dot proxy is what you guys are going to try to create, that or I guess it's up here. And I'll give you a hint about it. It's going to return a function. It's going to return a function that's going to call this function so that this is the context. So that's all the clue I'm going to give you. Let's struggle for another seven minutes and I will, if people have questions or need help I'm here. So is Alexis. Let me put this up. So this is what we're going to try to do, is dollar proxy.
Exercise 11: Solution
I'm going to show you how to write JQuery's proxy method. For the most part it's surprisingly simple. So I already showed you that I'm going to return a function. So proxy is a function that returns a function, that calls another function. What this function is going to do, is it's going to make sure, it's going to call the original passed function. It's going to make sure it's called with the right context. So and, also for any arguments that the original, kind of the function that it's returning is called with. So I'm going to use apply, but I'm going to make sure the context is set right and I'm going to pass in any arguments. So, I mentioned a little bit earlier that arguments is something, it's like a, essentially when we talked about a call object being created I said that there's this inside there, there's also an arguments object that has a reference to every argument that was passed. So this is going to basically take the arguments that were passed here and forward them to this function, but we're going to give it a different context that was passed. And we're going to make sure that we're going to return the result of calling that function for the result of this outer function. And that is it. But I'm going to try to explain it, what's going on in memory, cause this could be a little bit confusing. I'm going to first make sure it works. Cool, Any questions before I do this explanation? Alright, I'll do this explanation. So, let me first show what's going on here. So in memory I've got a dog with a name property and a speak function. So I've made a dog object with a name property and a speak function. We've also created our dollar as a function, but it also has a proxy property that has another function. So this is that proxy, this is our proxy function we just created. Now what is going to happen when we do dollar proxy, oh where is it, dollar proxy dog speak dog? Well, what's going to happen always when we call any function is a new call object is going to be created. Is this the right one here? No, these things keep getting drained. I'm going to have to block your guys' view while I write this out and then I'll show it. So I'm going to create a call object. Try to create a call object. Another call object. And call objects always know about the function that created it, created them. And it's going to get it's arguments. The arguments we're being passing is fn and, fn and context. So fn, is going to be a pointer to this function in memory. The speak function, and context, sorry if this is small for everybody in the back of the room, context is going to be a reference to this dog object in memory. We want to go right in through, that point right there. So we've got function and context are referencing this function in memory, this speak function in memory and the dog object. Now what this function's going to do is create another function in memory. So all functions know about their parent object, or their parent call object. So it's that kind of pseudo pointer knows about that. And then this is what's going to be returned as the speak proxy function. The speak proxy function. I'm just going to write speak p. So then when the speak proxy function is called with woof, well that will create, you know, do the same kind of create a call object with arguments but then it's going to call, where is my code? It's going to call this inner function, It's going to call this inner function, create a call object, create another call object. I know this is getting messy. Create another call object that's going to look up fn. It's going to try to look up fn inside. Could you move the white board that way, the stand? Yep. It's going to, so this is that inner, this is the call object for this inner invocation of a function. It's going to try to look up fn in here, not find it. Walk to the parent call object and get fn from kind of the parent function there, which is this function. And then it's going to do the same thing for context and get the context and it's going to call this function with this as it's context and forward the arguments that this essentially call object was created with. That's what's going on in memory. I don't know if that helps explain it, but that's how I see the world. Maybe I'm going crazy. I don't know. Any other questions about this? Hopefully it makes sense. No? Yeah? Alright. Now we're going to move on to the dom. Get this out of the way of that I guess. New slide. Okay, so. Yeah, there's a question, why do we explicitly return fn dot applies instead of within a function? I'm not sure what you mean, instead of within. Oh I think, he says, at least my interpretation. He might be asking why are we returning a function that calls fn to (mumbles). Why don't we just return fn dot apply in one line. That's a good question, yeah. I think the method signature would be different, cause it would be expecting you to pass in context. Well, maybe. I guess, interpreting what Alexis just said is, I thought, I think he's thinking that you could just do, he's wanting to just do something like this, or something. And what I'm saying is, if you return that function it's expecting context to come in as the first parameter, When you then run your proxy function. Well, this wouldn't even, the problem with this is, this wouldn't even return a function in the first place. This would just invoke that function right, that was passed in right away. The reason you, he might be asking this question is why is there a dollar proxy? That's a fair question if you guys have never needed to do something similar to this. The example that I gave, the shortest example that I gave was the one from the slide. Perhaps you want to call dog speak function in one second. So you want to be able to pass, hey in one second call this, call this function. JavaScript when you would call, if you just pass dog speak here it will mess that up, and call this function back with this set to something different. So JQuery has long provided dollar proxy to make it so you can get your functions called with the right, this. So you do this kind of behavior a lot if you're doing object oriented programming in JavaScript, where you'll say okay in, you know, as a result of this ajex call, complete this to do. You need that sometimes, you often need that kind of, you need to make sure this is set correctly, but you need to pass a single call back function to something else. Pretty common. Cool.
Finding Elements
Finding from the Document
We're going to fill out some set of these, depending on how quickly we move. Some of them, I might just implement for you guys, or show you how to do it. But, this is a big, nice set of jQuery's functionality. And, we're going to use that to explore the DOM. And the first thing we're going to talk about is just how do you find elements in the DOM. So, modern browsers provide a nice set of, methods that given a document, which is really, this document is, represents the HTML structure of the page. Given that, you can find an element by ID, by class name, by tag name, by a CSS selector, by a lot of different methods. So, just to give a quick example of what these do, if you've never seen them before, document getElementById finds an element that matches that, has an ID attribute that matches what's passed in here and will return that single element. getElementsByTagName. Oh, one thing I should also reference. I'm going in order of performance. getElementById is the fastest way to retrieve an element in the whole document. getElementsByTagName is a way to get all elements that match a particular tag. So, if I wanted all LIs on my page, this would get me all the LIs. And, the cool thing about this, fun fact, is this is a live array. Like, it's not actually an array. It's a no list, but it changes. If I insert an LI, whatever this object would, the no list thing is returning will dynamically change as LIs are added or removed to the page, which is crazy. I've never had to use that functionality for some kind of benefit, but that does work. Another fairly fast selector is getElementsByClassName. This will get all elements that have, you see this has this class attribute? It has at least one part matching. So, if I had contact Space important, in quotes, this would still match this element. querySelectorAll gets all elements that match a CSS selector. Hopefully, everybody here is at least familiar with CSS selectors. If not, like ping me or Alexis right after, and we'll explain it to you. But, this will get all elements that match a CSS selector.
Exercise 12: Creating the $ function
So, the first thing we're going to do now is we're going to start implementing the Dollar Function. And, the Dollar Function we're going to treat as a constructor function for now. So, what we want to be able to write is new Dollar, and then, pass it a CSS selector. It get all elements in the page that match that CSS selector, and it's going to add those elements to the instance that was just created in such a way that that instance looks like an array-like object. And, there's a trick to making this happen that I will kind of walk people through. We'll probably give like 15 minutes, a little bit longer because I want people to kind of finish this one on their own. And, let me give a little, let me give a little context to it. So, this hint, is the kind of fast, sneaky way of. Well, let me describe this problem a little bit better. Okay, so let's say I had an array of items. We've all seen an array of items and that could look like, you know, one, two. Let me not use those. Let me do foo, bar, zed. Okay, so that's an array of items, but like we've seen, things can be array-like. That just means that they have a length and they have properties that match that. They have like a zero, one, two, and three properties. So, I could have something that's array-like that equals, zero is foo, one is bar, two is zed. And then, it has a length property of three. So when you use jQuery, it's actually making an instance of something, but it has properties on it that make it array-like. jQuery's this kind of it's. Part of its magic is that it's, it acts like an array, but it has all of these methods that arrays don't have on it. And, probably this next exercise and one more, are the two trickiest exercises today, is how do you convert the instance in here, which would be this, how do you make it, given some elements, maybe given some elements like this, make it look like this. Now, there's a trick to doing it, which is on the slide, which is down here, which I'll come back to. But, you can solve this any way that you can kind of rationally do it. And, maybe the easiest way to understand at first, is just simply going through the array and copying the properties to this. So, making sure that this has a zero property, a one property, a two property, and a length, if you get from the selector three elements. So, think of it this way, the easiest way to solve it, I think conceptually, is give it a selector. Use document querySelectorAll to go get your elements. You'll get an array of elements back. Do a loop to go through each one of those elements and copy. Add properties to this that are zero, one, two, as many elements as you have and a length property. That's what you need to do to make your instances of Dollar behave just like jQuery will behave. Any questions on that? I know it's confusing, but you'll see the answer and hopefully, it'll make sense. So, we'll do...Can you write out like the, your verbalization of what this should do? Just like comment it out for us? Like, you mentioned. Oh, you mean you want me to write it out? Right. Oh sure, I'll write it out. Get elements from the page using selector document querySelectorAll. Then, go through... (inaudible) Well, it'll be the hint that I put up, but sure. I can. Or, I'll...No, I was just, like, you should verbalize the hint. Yeah. Using document querySelectorAll. And then once you have all your elements, go through them and copy to this. Like, go through. Go through each element, then copy to this as a numeric property. And then, also set length property to the number of elements in the array. And, what we'll be showing at the end of this, that's what that hint is at the very bottom. The hint at the bottom is a way that, essentially do these steps with very little code. But, I'll explain that after I explain kind of a longer way of doing it, which is what you guys should try at first, I think. Any other questions? And, this guy. Okay, so. Oh, nevermind. So, one question that some people might be talking about online is jQuery doesn't, you don't have to pass new before you do jQuery, right. So, as you saw, we're making something where you have to do, where did it go? We're making something where you have to do new Dollar. We're going to remove you having to do new. It's just easier to get everything started by requiring people to call new at first. Or, we'll make it work just like jQuery in a moment. So, I think I'll leave this up then, the verbalization. Yeah, because you guys can see the tests if you need to. So, I'll leave this up.
Exercise 12: Solution
So, I'm going to kind of go through again why we're doing it. Well, like why we're doing what we're doing. Hopefully, most of you have used jQuery at some point. And if you're used to jQuery, you do something like this. If I want to get every LI on the page, I can do var LIs equals Dollar LI. And then, I can do something like this. I can go LIs zero, and that will actually give me the LI element. All right, and I can do LIs dot length, and that will give me the number of LIs in the page. What you're doing, fundamentally, when you do Dollar LI like this is you're really making an instance of jQuery. Underneath the hood, that's, that's what's happening. And, we're going to make ours work exactly, pretty much the exact same way as jQuery. But, we're starting with instead of just being able to call Dollar, like that, we're starting with it so you have to call new Dollar. But, we want the same behavior. We want it so you get a list of LIs. You get a list of LIs back. And, there's also, by the way, I forgot to mention the one other important thing, is LIs has all the jQuery methods you've come to love and adore, which is like the HTML method that will give you the HTML of the first LI in this collection. Maybe, it was just like, you know, Hello World, or something like that. All right, so what we want it a constructor function, Dollar, that returns to us an instance of something that has all of these HTML and text methods and stuff like that, that we're adding to Dollar's prototype. So, we have all of these methods here. But at the same time, it looks like an array, right? It's got a length and it has items, kind of numeric properties, so it looks just like an array, but it's got all these methods. And, this is really the secret of jQuery in a lot of ways. It, you know, hit a lot of things right. It was like an array, but it had all these useful methods. It had chaining and all this other nice stuff that made it super useful. That's why it's so popular today. Any questions with that, before I go into the solution? Okay. So, we want to get something like this working, and we're passing in a CSS selector. So, the first thing I'm going to do is I'm going to get, I'm going to make an elements. Get elements from the page that match the CSS selector. So, we have document dot querySelectorAll. And, I'm going to pass it the selector that was passed in. So if LI was passed in, document querySelectorAll is going to give me an array of elements, array of LIs. Something array-like that's LIs. Now, here's the really tricky, hard part is you need to make it so that whenever new Dollar is called, this is going to be an instance of Dollar. The only way I can really express that is by doing this dot proto is equal to Dollar dot prototype. All right. Or, I guess I could write it also this is an instance of Dollar. So, this will already have, I can already write in here, I could write this dot HTML, and that would work. Well, it would exist and it would call an empty function right now. What I want to be able to do is make sure it has a this zero property. And, I want to make sure it has a this dot length property. This dot zero is going to be just like that LI up there. And, this dot length would be the number of LIs in the page, maybe five. So, I want all of this behavior that jQuery adds. The way to do this, the easiest kind of way I think to understand is just brute force, copy every element in here onto a numeric property of this. So, I'm going to do just that. I'm going to go through every element, and I'm going to set this bracket I, so I'm going to set a numeric property, so I'm going to set this dot zero, essentially, equal to elements I. You guys with me there? Everybody? Awesome. And then, I want to make sure that it has this length property. So, I'm going to do this dot length equals elements dot length. Cool? So, some of you might have remembered there is this hint that I said that can make, make this kind of code go away, because there's a nicer way of doing it. The hint is to use push and steal it for our own purposes. So instead of doing all of this, I could, I'll do it above it and then delete it. I could get array. Well, if I want a shorthand for getting array dot push, I could write it like that. Or, I could write array dot prototype dot push. But instead of, you know, making this a normal array, I can. Or, instead of push operating on a normal array, I can make it operate on this and pass it the elements. And, array push pushes code, pretty much looks the exact same as, looks pretty similar to this. So, it really just does the same thing. And, this is a way of, you know, saving some code and maybe performing a little bit better too. Any questions about that in this trick? You'll see this kind of thing reaching out to array's prototype methods on things that are not arrays all the time if ever open the hoods to any open source library. It should be applies to elements as. It should be apply, thank you. I wrote that wrong. And, we might even have to make. In some browsers, I thing you even have to do then Dollar dot make array. (mumbles) Huh? Yeah, but you don't have to. The older ES5s, like IAs, then you would have to do what you said. Yeah, and I think you have to set the length property to zero to make it totally work in all browsers. But, this works right here. Any questions about this? So, I'm going to set it back to the other one, just so we can see what's going on. And, I'm just going to step into a Debugger, just to show what's happening here. Oops, let me delete my code at the top of my page that doesn't work, because I like going through a Debugger with these things. So, is that code big enough, hopefully? Yeah, maybe? Okay, so we are, and I'll walk up the call stack here. We just did, whoa this moves fast, new Dollar with contacts LI con, contacts. So, this is going to get every contact that's an LI inside of our contacts element, which these guys are all up in here, in the test fixture. So, we're going to do a document querySelectorAll, with the selector as contacts LI contact. By the way, one thing I want to just mention. You see here this scope variables? These things match, each one of these little. These are call objects, each one of these little arrows right here. And, if you understand call objects, then you can understand what's going on and why this shows. Because, it has like this inside of it. It has the elements and it has the selector arguments. And, it also has the I, which is currently undefined as well. And then, if we walk up the closure, now we're in the invocation of this function, this outer function that's immediately invoked. Var is array-like is in there. And if you keep walking up, you eventually get to the global call object, which has like everything in it, all right? So, we're just kind of walking up our call objects. So, hopefully now, if there's one thing you can take away from this is that you now understand completely what these things are and how they relate to closures. So, back to this. We saw that it was called a selector. I'm going to step over. Going to kill all this stuff. I that, show in here. We'll see that elements is a no list. So, not a true array, but sure acts very similar to one. It's got each LI in it. And then, we're going to simply, we'll see what our this is. You could see the prototype methods on the proto. And, we're all going to. So, you just added a zero property, which is the first contact. And, it's going to add a one property, and then, it's going to add a length as two. So, this is what our Dollar looks like. In memory, it's got a zero, one, and length property, and it's got a proto property that points to the Dollar prototype function. Cool. So, also hopefully, I hope that connections are starting to be made, even with like debugging tools and things like that. To me, it's awesome that if you understood yesterday's stuff, you can kind of get what's going on in here. Why is that proto? And, why are these things there? Now, it might make sense. Okay.
Exercise 13: Implementing the html() method
So, now we're going to add an HTML method that gets or sets the inner HTML of all of the elements, in a collection. So here if I got all LIs, I could set all LIs' HTML to have a DIV with all dogs, and I could read back the first LI's HTML and get that back like this. So to give a little bit of explanation on what you're going to do, (mumbles) keep doing this pattern, I'm going to go to this HTML function. And going to first, I need to figure out if I'm either getting or setting the HTML. All right, so the best way of getting or setting the HTML is to, well, I'm going to pseudocode this. I'll give this one to you guys. If you do arguments dot length, that means someone passed in an argument. That means I'm going to do setting, otherwise, I'm going to get this zeros HTML. Inner HTML, really. Now for setting, what I need to do is go through each, each item in the in this, each element in this, and set it's inner HTML to new HTML. Now, you can use Dollar each in here on this. This is a really nice way of doing it is to do Dollar each, and then, pass it this, and then, you get a function that will be called back with each element in this. So, I'll just give that too. So, you're going to do function, and this will get called back with the index and the element. And, I'm going to try to use return, and you're also going to want to return the original collections, because jQuery supports chaining. So, you'd want a return here, then make sure it's returning this. So if that was confusing, basically all I'm doing is the same as doing this. Because Query, anytime that there's a setter, if you're always setting the value of your collection, values in your collection, it always returns the instance of jQuery back to you.
Exercise 13: Solution
I'm going to go through the answer in a moment. But first again, I'm going to try to explain the context for what's going on here. Here's my, this is the Breeds page that we're going to make, eventually show tabs and in this page, it has a bunch of links and a bunch of LIs. And, what I want to show is how this HTML function should work. But actually, I just realized I probably should implement it first. Where did that go? Here he is. (clears throat) So if I do new A, it's going to give me an object back with each anchor in it. And, let's say I wanted to change, what jQuery allows you to do is, I'm going to save this as As. I'll save it as Dollar As, which looks like as. You can see each one of these things is an element. And, elements have all of these properties and values, and one of them is inner HTML. So if I were to do Dollar As zero dot inner HTML, that's going to give me the first anchors in our HMTL. And, I could also set it to high there. So, all elements, all DOM elements have an inner HTML method that reads and writes the inner HTML, the HTML content inside that element. So, it's not just text. You can also provide markup, if I were to put like a bold or a strong, that should make there bold. So, this is what jQuery's HTML function manipulates for us, is the inner HTML properties of these elements. Now in fact, it might do things a little bit more complex than what we're doing here, but this is a good start to understanding the most simple manipulation of the DOM possible, setting inner HTML and reading from it. So, what we're going to do. Another thing that jQuery does is, let's say I had those same As, and I got them with my new Dollar As, jQuery behaves differently when you call functions as a setter or a getter. So if I just wanted the first anchor's HTML, I would call the HTML function in jQuery without any arguments. And, this would return doberman, like we just saw. But jQuery, if you pass it, make it a setter, so if I wanted to set everything to like, Hello there, what it's going to do is chain, it's going to call this function and it's going to for every single element in this collection, it's going to update its HTML to, you know, to Hello there. So, let's make this work. So, this HTML function, let me bring back this. This HTML function is going to be called with whatever arguments are passed here. And, it's going to be called with this, you know, this inside this function, is going to be this, what's on the left hand side of the dot, the jQuery collection. So, I can iterate through every item in the collection because we created our Dollar each, and I'm going to get every element, and I'm going to handle the setter. All right, so by checking if there's arguments dot length, I make sure that someone actually passed an argument to this function, and I'm going to enter the setter code. I'm going to go through each element and set its inner HTML to the new HTML. And then, I return this, just to make sure that chaining works because jQuery allows you to set the inner HTML, and then, you can do all this other kind of crazy stuff, like I could bind to every link's click method, when it's clicked by the user. We'll see how chain's used in a little bit. And then, I'm going to handle the case where arguments dot length is zero. Because nothing was passed in here, that means we're doing the getter on the first item. So, I'm just going to return this zero dot inner HTML. Cool, any questions about this? No? All right. Just want to make sure this works. My test. Oops, get rid of that break point. Get out of here. I must have broken proxy. Oh, because I removed the function. There, my HTML works.
Exercise 14 and Solution: val() function
Now, we're going to implement the val function, which works just the same. The difference is that val operates on input elements. So, let me show the exercise, and then, I'll explain the value property of input elements. So, we're going to add a val method that gets and sets the value of an HTML element. So if I have an input like this, I can change, I can read its value property, like this, and I can also update its value property. So for those people who are kind of new, I'm just going to go over, like what an input element looks like and that it has a value property. So if I just create a input here, and I'll give it an ID, age or something, and I'll give it a value of 100, if I open up my breeds, you can see I have that 100 there. If I get my age element, you can see it has an input in there, and you can see, I could do that value on it. It's going to give me 100, and if I set that to 200, it updates the element on the left here. So basically, you're going to implement, this exacts almost HTML. Instead of changing, just like HTML, but instead of the HTML function we did, it's going to change the value property. Other than that, it's going to look the exact same. So, this should take not very much time. So, if we could put like six minutes on the board. Then, we'll break for lunch right after this, I think. The answer's pretty straightforward for this one because all we're doing is instead of using inner HTML, we're just using val, so the easiest thing to do here is just copy the insides of this function, paste it. And then instead of setting inner HTML to new HTML, we're going to set value to new value and then return the value. All right, exact same thing. A lot of jQuery code does this getter, setter stuff. Text will be a little bit different. But, atter and CSS, half of width, half of some of these other functions follow this exact same pattern to make jQuery do.
Exercise 15: Eliminating 'new'
What we're going to do is remove the need to call new when we're using our Dollar function. All right, so right now, to create an instance, you have to use the new operator. But, what we want to do is make our Dollar function detect if new wasn't used, and then, make sure new was called. So, let's take a look at our Dollar function and see if you guys have any ideas on how to do this. So, here's our Dollar function. We need to make it so that if I call something like Dollar LI, that's still going to create an instance of Dollar, and still return that instance, like LIs, so that we can do things like call our HTML method on it. All right. So, quick question. What's going to happen if we call the Dollar function like this? What will this be inside here? Window? Window, absolutely right. So, that's wrong. So, you guys need to figure out some way of detecting if this is incorrect, and then, make sure Dollar is called with the correct, the correct thing. So, I'll kind of write this out. I'm not going to say what correct means, because you can try to figure out what, not correct means. If this isn't correct, call new Dollar selector, otherwise, continue as normal. So, that's what you need to do. Any questions about this? This is the tricky part that I want you guys to kind of think about how you might make this work. The test has, test just makes sure that the same kind of, you were getting the same thing back that using new used. Although, it probably should be testing to make sure that contacts has an HTML method on it. But other than that, it should be testing the same thing. So, I'll put this up and we'll put the. This should be like seven minutes, about that. We'll start with about seven minutes. Was there a question? Yeah, from before, I think, if this makes sense, (mumbles), he was asking about the HTML solution, or even stop length. Can that be explained again. Yeah. Let me go to that. So, the HTML solution. So when we call, we get our LIs, we'll make LIs equal that. And, we want to call this HTML function. If jQuery, if you call the HTML function without any arguments, it returns the inner HTML of the first LI. It might be something like a doberman. If you call LIs with multiple arguments, or sorry, if you call LI, or sorry, if you call HTML with an argument, a string argument such as like, Hey there, that's going to go to every LI and update its inner HTML to this. So, this is the behavior we want. We want this behavior for our HTML function where it does different things, depending on if a value was passed here. Now, there's a way that a lot times people will do it. They'll just say, hey, if we have a new val, or new HTML, then run through this because, hey, they passed something that will do the setter, instead of the getter. But, this isn't a great technique because what happens if someone wanted to just remove the HTML, and set it to, passed in an empty string? An empty string is falsey, so it would return the. It would do the getter code and return the first items in our HTML, where we really wanted to be setting every element's inner HTML to the empty string. So instead of doing it this way, and also, instead of doing it like undefined, which that would actually work for this case, but in case someone did pass an undefined and we actually wanted to set inner HTML to undefined, which really doesn't make sense for HTML, but it does make sense for other places where you might want to pass in a undefined value. The strongest, best way of just checking if someone actually called it with an argument or not, is to do arguments dot length. Now, the reason why arguments dot length works is anytime a function is called along with the other, along with all the values like the arguments, like new HTML being put in the call object and this being put in the call object, there's also an arguments array-like structure that you can access inside of a function, and that gives you an array-like structure of each argument that was passed to the function. And, arguments also has a length to tell you how many arguments that function was called with. So, that is about a thorough of an explanation as I think I can give. Hopefully, that helps.
Exercise 15: Solution
The first thing I need to do is check if Dollar was called, if Dollar was called without this being set correctly to a new instance of Dollar. All right, so there's a few ways that people do this. One way I've seen people do it is they'll do if, well, what if this is just the window? All right, because that's what, if I just were to call Dollar LI, like this, inside Dollar, this would be the window. That's an okay way of doing it, but I'll show you a better way. And then, bonus points for anybody who can explain the difference and why, why the way that I'm about to do it is better than checking if it's a window. So, the better way of doing it is check if this is an instance of Dollar. And if it's not, so I'm going to wrap this in parentheses, if it's not, I'm going to return new Dollar selector. So, that's all they needed to do for this exercise. What this is going to do, again, is just check that, hey, this is the window if called like this. It's not an instance of Dollar, so we're going to force the issue. This is kind of how jQuery does it. Does anybody know why doing it this way is better than just doing if, this is equal to window? It's subtle. The reason is is because it's very possible people do this a lot when they're, you know, adding, you know, if you're trying to make a widget that can work from jQuery, but captained its own like, you know, has its own version of jQuery on some property. For instance, let's just say somewhere else in our tabs widget, for some reason, we decide to make, we wanted our tabs to have a Dollar property that it was always going to use everywhere. So, we're just going to alias jQuery to Dollar. And then, it was always going to write all of its code like tabs, Dollar, LIs. Right, for some reason, somebody decided to do it that way. Well in this case, this is not going to be the window anymore. It's going to be some tabs or some other object. So, doing it if this is equal to window will fail. So, to be a little bit better about making sure that, you know, this is what you want it to be, instead of just checking that it's the window, we explicitly make sure it's the, we make sure it's an instance of Dollar. If it's not, then we force the issue to make it that way. Cool. Any questions in the? Oh, there was a good question that someone wanted me to answer. Okay, so Kevin L asked, can you explain why inside HTML, this zero can be safely relied on if you have an empty collection it will break? So, that's a really good point. So for our example, it's okay to kind of write this because we're not going to really be dealing with empty collections. However, jQuery if giving it empty collection, will make sure that it doesn't throw any errors. This would error on an empty collection because there would be no this dot zero. So, when it would try to read an inner HTML from something that's undefined, this will throw an error. To fix this, and if you guys want to, you don't need to fix this in your code, but if you want to fix it, you would just do a check. You would make sure that this zero exists, and then, call this zero inner HTML. If you haven't seen this kind of code before, all this does is, all it really is doing is an if this zero, because if that's true, then it will execute this code here. So really, that looks like return this zero inner HTML. All right, we're pretty much doing the same thing. But, this is a nice shorthand for it. So, this would make your code more jQuery-like, that it doesn't error if, this dot value, or if this zero doesn't exist, if it's an empty collection and you try to read from it. So, let me go back to the, that. Any other questions? Awesome, okay. I'm going to scroll down here.
Exercise 16: Implementing the text() method
And the next thing, and this is going to be a trickier one. When I said there's two hard ones, this is the second harder one, I think. We're going to add a text method that you can get or set the text of an element. So, if I were to get the text of a UL, which like the UL in our page, which I'll show, it'll return a string with just the TextNode content. So, doberman, beagles, boxer. And if I were to set an element, it will set just the text of it. This is different than setting HTML. See, if I'm setting text here as Teeth, if I put in stuff that looked like markup, well, you would actually see in the page, not in the source, markup. It'll get escaped correctly so you see it. Let me walk through a little bit more explanation of what TextNodes are so that you can understand how. Because, understanding that there's TextNodes is important to solving this exercise. So, let me inspect this element. There's a question that just came in. Why can't we do this equals new Dollar Sign selector? Yeah, so this is. Okay, so someone asked why can't we do this equals new selector in, in here? The reason is is because think about how your new operator works. Your new operator just calls, if you remember the new operator from what we did yesterday. The new operator creates an object in memory, and then, makes sure that that constructor function calls, makes sure that constructor function this points to that newly created object. So, it's going to create a. This code in here is really when it's going to call that constructor function. It's going to call it with this pointed to some, some object that it created. Now if in my jQuery JS, if you have this code here, all that's doing is pointing this to some other object that it's created. This in the context of this function running. But, it cannot reach back into, here and somehow, change O to be returned as some other value. It can't do that. Remember, when you set, this is just like any other variable. Really, like we have in, you know, this function right here has a this, and it's also going to have an elements. What this means in this function is local to that running of this function. It's local in this call object. So, setting elements, changing what this is, won't change what is returned by the outside world. Won't change the behavior of what O is in here. Hopefully, that makes sense. Okay so, let me get back to talking about TextNodes. So, you can see here I have a UL and it's got these three LIs in it. How many Child Nodes does this UL have? It's a trick question. It does not have three. It has six? Close. Seven. Seven, can you tell me why? The three LIs, and then, the four TextNodes surrounding each LI. So, there's one at the top, then in between, then one at the bottom. Exactly, so let me show it that. So, here is my Breeds HTML. So, you might think, like hey, the UL is going to have, you know, three Child Nodes. But in fact, it's going to have seven because it's going to have a TextNode that's created for the text of the line break and any space and tabs right here. And then, it's going to have an LI as a Child Node. It's going to have another TextNode right here, an LI as a Child Node, another TextNode here, and an LI as a Child Node, and then, the seventh TextNode right here. That's the actual structure of the DOM. And, you can see this in your debugging tools. If I were to go to this UL and look at properties, and look at, Child Nodes? Child Nodes, thank you. Just went right past it. You can see, there's seven Child Nodes. Text, LI, Text, LI, Text. And, these LIs will each have TextNodes as children. This text is going to look just like, you can see, it's got a line break and space. So, with jQuery's TextNode, when you try to read, when it tries to read, if we were to read all of, if we were to read the text of this UL, what it needs to do is recurse down through every TextNode, so it's going to get all the TextNodes, it's going to get all of these TextNodes, but it's also going to recurse down through every LI and get all of their TextNodes. Well, and then, through the LI to the anchor, and the anchor's going to have a TextNote and get these TextNodes. So, this is the last, I would say, pretty hard exercise. What I would say, let's split it up in two. Let's do the first part, is actually easier. So, we'll do that first. We're going to do the setting. And then, we're going to do the getting. So to set UL, we wanted to set UL's text, that's really easy. I could just create a TextNode. And, you can create a TextNode, like you might have seen document createElement. That creates an element without or with whatever tag name you want. So if I want to create a DIV, I can create one like that. But, I can also create a TextNode. And, I can give it the text of the TextNode. I can say like, Hello world. Now, I could get my UL. Did I write something wrong? Oh, I maybe didn't save it. There we go. Cool, so I get my UL. (mumbles) something wrong? I have, hold on one second. I have something breaking here. Oh, this thing. There we go. (mumbles) errors on here if you try that. Perfect, so I have my UL and I'm going to create my TextNode. And what I can do, is I can simply wipe out my UL's text, uh HTML, so I'm going to choose a little shortcut. I'm just going to blow away all of its HTML. And now, my UL is empty. As you can see on the left, it's gone. And, you can see it in the DOM as well. And then, what I'm going to do is append to my UL. Actually, I'm supposed to keep this high up as I can. I'm going to append to my UL. Let me grab my UL. Let me grab the raw element. And, I'm going to add, I'm going to appendChild my TextNode that I created. And, you'll see Hello world was added here. The cool thing about TextNodes is that they'll automatically escape any text you put in them. So, I'm going to put a bold in here. In the TextNode. But if I were to append that, again, to my UL, now it's got two TextNodes. But if we look on the page, it doesn't actually put markup. It escapes the markup so you see it like this. So, the first exercise we're going to do is to take our Dollar text, and we're going to have something like, if arguments dot length, and then, we're going to do the setter. And, the setter is going to work just like all of these setters, except it's going to create a new, it's going to empty the inner HTML of each element. Loop and, set the inner HTML of each element. Or, clear. Well, set the inner HTML to empty string, and then, it's going to create a TextNode and append it to the element.
Exercise 16: Solution
If you remember, we're going to loop through every item first, so I'm going to set up my loop. Return Dollar each with this, and it's going to get my item and my element. And then, for each element, I'm going to set the inner HTML to empty string just to clear it out, so that when I append my TextNode, it's the only Node inside the element. So, I'm going to create TextNode with the new text, and then, I'm going to append it to the element with appendChild. So, the DOM has methods where you can, two methods really, appendChild and insertBefore that let you add Nodes to the children of other Nodes. appendChild always adds at the end to the Child Node's array. So, we're going to append the TextNode. So that, I'm just going to check that out and make sure it works. Why is my? There we go. So, I should be able to get my UL and change its text to something that includes HTML just to make sure it's not, it's actually giving a TextNode back. And, you can see input shows up instead of an input element. Any questions about this? Yeah. So, how come the creation of the TextNode needs to be within each, as opposed to right before or outside? So, if you did it outside, the problem would be. That's a good, we can. Can anybody take a guess what the problem would be? Be awesome if we start answering our own. Anybody else? It's outside the scope of the each? The scope isn't a problem. This text, it can, again, it will just walk up the closure and find this text, and use that. So, that text will work, but there's a. There's another problem. There's another problem? (mumbles) Yes, that you're only creating one TextNode, so that every, if you did this on multiple LIs, let's say, you try to set the text of multiple LIs to some text, it would create only one TextNode, and it would append that TextNode to every single LI, if that makes sense. Let me show you what the result is. The actual result is you'll only see the. Well, I'll show you what the result is. It's kind of easier to show than explain. This one. Yeah, okay. So, let me do it will all the LIs. How do I get rid of this again? Someone told me. Escape. It's just Escape? Okay, cool. So if I were to change the text of each LI, to let's just say, Input, what you want is to see three inputs in the page then. Not input elements, but three of this text in the page. But, you're only going to see one. The reason is. Oh, how do I? Uh, elements. Get out of here. The reason is is because if we were to walk through this, it's adding that text node to this first LI. But whenever you append an element that's already in the DOM, it implicitly removes it from whatever its current parent is and it inserts it in its new position. So, what we really need is three input, three TextNodes, one for each LI. We need to be creating three. So, if I showed this happening, it might be kind of cool just to watch taking place here. Oops, oh, I got to hit my Console here. Okay, so let me put some watches so we can see what we got. Here's the TextNode. And, I'm actually going to write TextNode dot parent, uh, parentNode. So right now, the text doesn't belong to any parent. Then, I'm going to do an element dot childNodes. Actually, I'm going to do, I wish I could get the UL. I'm just going to write the UL so we can see it. UL zero dot childNodes. That's going to get the, that's just going to show me all the UL's childNodes so I can see each LI. Actually, better might just be to do. I'll just get each LI. Okay. So, here's each LI. Here's the current TextNode. What it's going to do is going to, you can see, it's going to take the first TextNode and it's going to say, right now, it's got all these childNodes, it's got an anchor. What it's going to do is blow them away. childNodes is now zero. Then, it's going to append our TextNode. So, now our TextNode has that first LI as a parent. But then, this loop is going to come in again, on this LI, and you can see it's got childNodes one. It's going to clear that out and make it childNode zero. But, here's the crazy part. This first one still has this TextNode as a child, all right? That's that TextNode and the TextNode has this as a parent. But, the second we append that TextNode to a new LI, it's going to change its parent, even though we didn't really see it, you can see this first LI now has no childNodes. So, it's just kind of appending it, but then, removing it with the next append. So, the fix to this is to, the fix to this is to create the TextNode each and every time. Really good question. Any others? All right, so now, we're going to work on the setter. The setter, as I said before is going to have to, if we're calling on this UL, it's going to have to recurse through all the different TextNodes, starting with the UL's TextNodes, then the LI's TextNodes, then the anchor's TextNodes. Essentially, accumulate them all, and then, add them all together, or add them while its going and return that to the user. But, for only the first element. So, I'm going to give some skeleton code that helps with this. What's helpful when you're doing recursive functions is to sometimes you need another function that will call itself. I'm not going to make text call itself. Instead, I'm going to have text call a function that can call itself. So in the else case, what I'm going to do is if I'm going to be really good with like with jQuery, I'm going to do something like return this, as long as there's a zero element, I'm going to call a getText function with this zero. So, I'm going to make getText able to, given an element, it's going to go through all of the element's childNodes, find the TextNodes, the ones that are TextNodes, and add them up, but also, call any Normal Nodes, it's going to call getText on those to get their text, which will create this recursion where this function getText will be called on every single Node from whatever element this is down to all of its deeply nested childNodes. Is there a question that someone had? I think what they're referring to as on line 115, can we call this done in our HTML, instead? Oh, I forgot to mention that. That's a great. One little shortcut to maybe save, and it wouldn't really save time, but just to be cool in meta, would be to do just this dot HTML, and then, this will go through on every element and set its inner HTML to empty, so you don't actually need to do this. Yeah, I forgot to mention that. You can absolutely do that. That's kind of cool. You start using your own stuff to implement bigger functionality. So, back to this. This getText function. Maybe, let's implement this together. Because, it's kind of hard and we got a lot of other things. But, I'm going to have you guys talk me through it. So, this getText. I'm just going to put this right here. And, this is going to take an element, and it needs to return that element, the text, the accumulated text of all of that element's childNodes. So, I'm going to give a little hint to start here. I'm going to start with some text. Just some starting text, and then, I'm going to add to, and at the end of this, I'm going to return some text, return the text. And in between here, is where all the magic is going to happen. So, the first thing I need to do is iterate through all of this element's TextNodes. Sorry, not through all of its TextNodes, through all of its childNodes, which will include TextNodes and non-TextNodes, normal elements. How can I iterate through this element's childNodes? What's a good way? How would someone write that? An each? Dollar each is good. And, what would I iterate through? You said all the childNodes, right? Uh huh, to the element. This dot childNodes? Close, it's the elements dot childNodes. And, this would get called with a function that would have each the index, and each childNode. Okay. So now, what I need to do is if that childNode is a TextNode, I'm just going to add its text to text. How can I tell if an element is a TextNode, or a normal HTML element? Does anybody know? I haven't explained it yet. But, I'm about to if no one knows. Anybody? So, how would you guys maybe figure this out if you have never, if you came across this problem and didn't have the internet to quickly look it up? How could you tell, maybe? What debugging skills? Here's what I would do. When I get lost, especially if I'm in situations where there's not a good answer on stack overflow, Look, open your Debugger and just look at the elements and its properties, and see if there's something there. All right, so one thing I might do is, there's sometimes a lot of properties, unfortunately, but it's still a good place to start. So for instance, a Normal Node, I could get one of my LIs like this, and I can, if you reveal it in the elements panel, you can see all of the properties on an LI. Right? And, there's a lot of different things, so I'm kind of going to go right to the one that is the important one. You're going to be like, hmm, there's a Node type one. That's weird, it's got Node type one. Type of a Node? That's weird, and what I might do is then say, oh, well maybe there's a difference between that and a, if I created a. Oh, let me not type down there, sorry. If I created a TextNode, maybe that has a different Node type. Oh, it does, it has a three. So, this sometimes, if you're in a situation, this would totally be something that you should, would search for and kind of find the answer yourself how to tell the difference between different Nodes, but sometimes, you will be in a situation where you're just like, I have no idea how to get this value. What it's called isn't helping. I've many times just been like, okay, is there something that helps me on these elements know what I'm supposed to do. So, Node type is how you can distinguish between a TextNode, which has a Node type of three, and a Normal Node, like an LI, that has a Node type of one.
Exercise 16: Solution, Continued
So, back to this example. I want to see if the childNode is a TextNode. So, what should I do? Check if it has a Node type of three. Exactly, so I would do if childNode nodeType is equal to three, and then if it does, what do I want to do? Get its text and add it. How do you get its text? That's a great question. So, I'm going to look again on my TextNode here. How do I? I can just create one in my watch. You can do a console dot dur. If it's the last thing? Well, you could just do console dot dur and wrap it around that. Oh, okay. It's content. This will give any of the, object. Okay, that's cool. So, this is getting console dot dur wrapped around the, whatever value you want to look at. In this case, we can just look. So, there's some properties that clearly have the text that I passed in. There's one data. There's one node value. I think there's probably like, text content. So, there's a whole bunch. In this case, the best one to use is node value. That'll work kind of everywhere. So, that's where I can read the text of a node is its node value. So, how do I add the text, the TextNode's node value to text. Some people actually might not know how to do this. Seems obvious, but if someone wants to help me out. Just plus? Plus equals, yeah. So, text. Well, there's two ways of doing it. The probably easiest way is for people to understand is text plus childNode dot nodeValue. So, that's going to get the, TextNodes. (mumbles) Old English. Yeah. The Old English TextNodes, yeah. This is going to get the, the TextNodes node text, and then, add it to our kind of accumulator of text. When you guys do recursive functions, sometimes, you'll hear that there's like an accumulator. That's kind of how I refer to the thing that you're starting to like add to a lot of times. Okay, so we handled if there's a TextNode, but if we get something that's not a TextNode, it's going to have nodeType of one, that's a normal node, what should we do? And this is for the big fake bonus points. Big bucks that I will not pay out. How can I make this work, so I don't have to iterate myself? You can call it getText again. Yes, exactly right. I'm going to call getText again. What am I going to pass it? The children of that node. childNode, exactly. And it's going to return something. Huh? You're going to add it to your accumulator. Exactly. Okay. So not only did we learn a lot of Java Script and we're learning jQuery now, we've also done a decent amount of recursive programming. Just a quick question I think about what does that nodeType equal to one. What does that mean? Node, the nodeType again is just a listing of like different types of nodes have different nodeTypes. For instance, if you have a comment, I don't know if you guys have ever seen a comment in HTML. You can actually have HTML comments that look like this. I'm a comment. That is actually going to be a childNode of the body, in this case, even though there is no real body. If I were to put that inside this UL, the UL would now actually have four, eight, it would have nine text, it would have nine total nodes, because there would be a TextNode here, a commentNode, which I think is nodeType something, I don't know. You can actually look up nodeTypes. By the way, if you're looking, wanting to find information about the DOM, use MDN, really, exclusively. Don't use, what's the other site that's? W3 School. Don't use W3 Schools, use MDN. So, anything you ever want to know, type MDN, and then, type in nodeType to Google. And, this is where you'd get actually very well done, good technical information. So, here's all the different nodeTypes, and they'll let you know which ones are not I think well supported, or (mumbles). Huh? Comment Node is eight. Yeah, Comment Node is eight. A normal element node is one. TextNode is three. The only ones the you'll typically see day-to-day element nodes, TextNodes, sometimes a Comment Node. And, I see Document Fragments a lot, which we're not going to hit today. But, document fragments are. If you ever find yourself building a lot of DOM and it's not going very fast, look into Document Fragments. Remember that word. And then, learn about it later. Talk for another day. Okay. So, should our code handle other node types? No, we only need to go. No, you're code does not need to handle that. And plus, other nodeTypes won't have children that would have TextNodes. So, a Comment Node isn't going to have a child that's a TextNode. So, we don't need to like recurse through that. We can just ignore that. We can ignore every other type of TextNode. Or, every other type of node, which we're doing here. So, that's what that three and one means. Based upon. Now, there is a flag. Sometimes, people don't like writing that because they feel, hey, that's hard to understand, so there is, instead of writing a one or a three, which you'll see in a lot of open source code, people will write, what is it, node dot TextNode. Because, node dot TextNode returns one. And, this way you can kind of write your code a little bit more clearer, I think. But, I just, I mean, depends on what circles you're running in. Most people who do open source would just, you'll see TextNode. You'll just see a three and people will know that it's TextNode. But if you're working with people who might not have seen that before, writing it out like node dot TextNode so it's explicit and node dot, what was it, element node, might help people out quite a bit. Because, if you've never seen this before, it'd be super weird just to see a three without any context. Cool, so that's it. That recurses. Let me step through it once. So you can see it working, I want to put a Debugger in here. I'm going to reload my Breeds. I'm going to open up the Java Script Console. And, I'm going to do Dollar, my UL, and I'm going to call text. And, I get an error. (laughs) What did I do? Did break something? Yes, I did. What did I break? Should it be else if? Yes, thank you. Syntax error. That's why pair programming is awesome. Especially when you're pair programming with like 20 people. And, 60 online, or whatever. Okay. Um, Console, clear you, escape you. Okay. Actually, I think I'll just blow this whole thing up, but once I get the. All right. So here, we got into this first getText call. Which I could just show. So, we're passing it. So, we got this return. We're making sure it's got a first element, and then, we're calling getText with element as the UL. Set a break point in here. Hopefully, it hits that. It did not. Why did it not? I'm going to have to put a Debugger in here too. Chrome is being weird. Debooger, Debugger, ahh. All right. Hit my code, okay. So, it's going to be called with the UL. That one's got to step over. So, L's going to be the UL. Let me hide this console. How do I make you go away? And, it's going to start. It's going to create in the accumulator, and then, it's going to step into this. And, it's going to get the first childNode of the UL, which is a TextNode, you can see here because it has like a return character and its data. And, we're simply going to say that, A, it's nodeType is one, or three I mean. And, we're just going to add to text. So, we're going to do text equals text plus the node value, which is a line break followed by some space. If we walk up to our parent call object, we can see text is going to change to have that text in it. So now, we're going to hit the next element, which is going to be an LI. Come on, show me the. It's going to be LI. It's going to be one. And, it's going to step in. So, it's going to step into this. This call is function again. Which is going to have its own accumulator that's going to go through all of the LI. So, if I just write, let me just write a, let me write the childNode dot nodeName, so we can just see what we're going through here. So now, we're going to do the LI's first child, which is an anchor. And, I'm going to set a break point here, so we can see what's being returned. Now, we're going to hit the second LI, and then, we're basically recursing down. This is the first anchor's text, which is going to be doberman. And then, we're going to kind of keep walking up. That's going to be returned. How do I get to that? Nope, one more level. Okay, so now that value is returned and our text should be the first return before the doberman and the text of the anchor. We're kind of recursing down. I don't know if I need to keep showing this. This is kind of hard for me to even follow. I think it's just easier to look at the code, actually. But, essentially, we're just keep calling, going in to getText and get text, down, so hopefully, that makes sense. Let's move on. Any other questions about this? Yeah, I'm going to move my Debuggers. There was one in the back here. Would any of our past looping benefit from detaching the elements from, that you're working, doing the DOM manipulation on? Then he's saying, like in other words, what is the best to temporarily remove elements from the DOM? So, it's best when you're manipulating them. It can be sometimes a good idea when you're manipulating them, but in this case, we're not actually manipulating anything. We're just reading. I'm answering this to you as if you're his question. We're not actually, we're just reading properties, so we're not actually changing anything, so we're not going to create any reflows or anything like that. So, it's best not to be removing it or anything like that. Especially, for get. Yeah. In my text function, I'm doing everything that we're kind of doing, but I'm getting error on the test page that says the appended child is not a function. Let me make sure my test is passing, that I didn't just copy some, give you guys some bad code. And then, we'll take a look. So, my text is where it says append child is not a function, down in this? Yep, right there. Right where you have append child. What does L look like? So if you step in, if you were to like put a Debugger or like a Consoled out log L, is that undefined? And if that is, what I would do is Console Log this to make sure that that looked, there's like an LI. Right, it should look. I'll show you what mine looks like. When the tests run. By the way, for these tests, you can just click on the individual tests and run just that. Just span. So mine will look like, this, yes, span is going to have, looks like the first time it's called, it's going to have a collection of one item that's a span, and then, it's going to apparently look like that. Is that what you're looks like but still getting an error? Mine's just an empty span I think. An empty span. Okay, let me. Let's do the same kind of thing. Like, I'll help you and if it's, if it's like something else other people would have had a problem with, I'll come back after the next exercise and explain it.
Exercise 17: Adding a find() method
Next exercise related to finding elements, kind of giving one element, or trying to find an element that matches a selector, is elements provide a way to go from that element to other elements the same way you can go from the document to find any element on the page, you can start at one element, and then, go find elements inside of it. So element, even though it doesn't make sense, every element has a getElementById method. They also have getElementsByTagName. This will find all elements inside this element that match this tag. Similarly, they have get ByClassName, all classes, all elements that match this class name within this element. And, they have a querySelector and querySelectorAll. This last one's important for what we're about to do, which is jQuery's find method that finds all elements within the collection that match a certain selector. Sorry, elements of the children of the items in the collection that match a given selector. So, what that means, I'll show in a second, is if I wanted to get every, I could get every DIV in the page, and what this would do is for every single DIV I found, look for images inside of it, image tags inside of it, and return a list of all of those. So to do this one, there's two things you need to do. First, you need to go through your collection. I'll write it out again. You need to go through your collection and for every element in your collection, find all the elements that match the passed in selector. And then, given all of those elements, you're going to do that for every single element, so you're going to get a list of elements for every source element. So, for like every DIV, you might have multiple images. And then, you've got to like combine them all into one big array. And that array that you have, you want to make that, turn that into an instance of Dollar. So, you need to make the Dollar function, not only be able to take a string, but take an array. So that given an array instead of a string, it's going to take those items and essentially copy them to an instance of Dollar. Just like we were doing with the elements that we retrieved. So, we'll step through that again with writing. So, here's our find method. You're going to have to create some kind of accumulator or something like that, that's an array of all of the total items found for every single item in the original collection. This will be like an array. And then, you're going to have to go for each item in collection you're going to have to get items, get elements that are within the item for each element, get elements that are within the element that match selector, and then, you're going to have to add them to accumulator. And at the end of this, what you're going to want to be able to do, I'm just going to you this kind of part. You're accumulator is going to look like elements is going to be an array, and at the end of this is what you're going to want to be able to do is return Dollar elements. You're going to want to take this array of elements and create a Dollar out of it. I'll come right back down to this, so if you're copying, I'll leave it on this. Let me talk about how Dollar is going to have to change. So, Dollar really only expects a selector. I'm going to remove these other comments, these old ones. It only expects selector to be a string. So, what you're going to want to do is something like if, selector is a string, you're going to want to do this. Otherwise, assume it's array, for now. We might change it later so we can work with something that's not an array, and just treat those elements that were passed in, selector's going to be an array of elements, well treat it due to each one of those elements what's going on with elements right here. Basically, all you really need to do is say, elements equal selector. So, this part is kind of weird to think about, but not too hard. This might be a little trickier down here. We'll make this one kind of longer because we went quickly through, getText, so we'll do like, 10, uh, let's do 12 minutes. Anybody have any questions before we begin? Can I see what you added to the selector, to the Dollar function? All I added was a comment that said, if selector is a string, you're going to do what you're used to be doing. And otherwise, if it's not a string, you can assume it's an array. And, you really just want the item. This is really an array of items at this point. Well, just, you're just going to say, well, elements is that, and then, just go through the elements, essentially. All right, you're making this function work if it's been passed a string or passed an array. And if it was passed an array, well, you don't need to query the DOM, you've already been given your elements, so just put those elements on this, the way that you're already doing. The reason for this, let me make one more thing clearer that I didn't. The reason for this is so that you can call, you know, I can call DIV, find every DIV, then find every image in it if I wanted, and then eventually, I could. Well, not image. Let me find every DIV, and then, I find every, let's say I'm finding every anchor in it, then I could change the text to whatever I feel like. Right, because we want to make sure find is going to return a jQuery instance, so that we can keep chaining like this. That's why we have to make Dollar. It's not good enough to return the elements. We want to return those elements wrapped in jQuery.
Exercise 17: Solution
Let's talk about the solution to this. So, we have our pseudo code, our comments set up, which again, definitely do this. Anytime you're approaching any kind of new problem that you've never seen before, write it out, try to verbalize it. This is, writing these comments out, are much more difficult than looking up the syntax. But, let's check this out. We have our accumulator. We have our array elements. Then, we need to do something for each element in our collection. So, what do you guys think we should do if we want to iterate between each element in our collection? Anybody have any thoughts? childNodes? Well, I mean, how can we iterate through each in our collection? How, with an each? With each, yeah. We have a helper. So, we're going to go through each of something, right? What is that something? Do you guys remember, from earlier? This? This, yep. We're going to get a function. We'll get our. This is where we're going to get back, and then, we're going to do these three things within our call back. So, the first thing that we do, now we're inside our collection. We're at the first index and we have access to one of the elements found in our collection. So, the first thing we need to do is get elements within that element that match some selector. And, we do have an API for this. This is our querySelectorAll. And, we know this is available on an individual element. So, we know we can do at least this much, L dot querySelectorAll. And, this function is going to take a selector. So, oops. We're going to pass in our selector there. And, this is going to return an array-like object with all the DOM elements that we found. So, we can call this Ls for short. Oops, this comment is from our previous comment. Okay, now that we've found a bunch of elements, nested within our current element, we need to add them to our accumulator array. So, we can do this a number of ways. We're going to do the shorthand way we did on one of the prior exercises. We're just going to say, we're going to overload our. Not overload, but hijack our push method from our array. And, we're going to say, hey, push with a context of elements all of the Ls that we found. All of the DOM elements that we found. This is going to take each on of our found children and push them on to our accumulator. Then, we need to return Dollar elements. Now, this is something else we needed to change for this exercise, we needed to modify our constructor. So, let's go up here and make sure we handle that. Here we go. So, right off the bat, we need to say, if selector is a string, do what we've been doing, otherwise, assume we're getting an array of elements that already exist and just wrap that up without looking up anything. So, let's do this. Let's move this real quickly here, and let's write this out. If our selector is a string, what's a good way that we can check to see if something is a string? Type of? Type of, yeah. We can say if type of selector equal to, and this will just return string, then, we're going to do what we did above. We're going to do the same thing right there. Else, assume we already have this. So, what I'm going to do is I'm going to declare elements up here. Oops. I'm going to declare elements right there, but I'm not going to set it to this only in this case. There we go. So, if we come through, so far, without any extra code, this is a more verbose way, or more, confusing way to do what we were already doing. If you come through, we pass in a string as a selector, it's going to say, if type of selector string, look up querySelectorAll on this document. Return that into elements, and then, business as usual. Otherwise, do this. And, the code is actually already there. I'm just going to uncomment it. Otherwise, we already have what we were looking for. Does that make sense? This part is a little weird. Again, because we don't have method overloading, in Java Script, ideally, you could have different methods. If this was Java or C Sharp, you could have a method, one method signature that takes a string, another method signature that takes an array, and the JVM, or whatever machine running behind the scenes, would be able to figure out which method you're trying to call, based on that API signature. But because Java Script is weakly typed, we don't know or necessarily care at the time the function is invoked, but in our particular scenario here, we want Dollar to accept many different types of inputs and behave differently based on the type of those inputs. That was a very long winded way to say that. Let's check it our really quick in our test. And, we got find is working. So if we go into our beagles page, let me blow up our Console, we should. Let's take a look at the DOM really quick. We should be able to do something like this. I'm going to find our UL on the page, and then, I'm going to use our UL to find any nested list items. And then, I just want to use a helper method. I'm going to use our text helper method to say, Hello, oops. Ah, so our find is not returning something. Let's take a look. I probably just broke something. Yes, our find is returning undefined. All right, let's take a look at what's going on. So, right off the bat, let's check here. See what we're getting back. See if we're passing what we need to into our constructor. So, we are passing quite a few things, so let's get into our individual tests. We don't see so many Consoles. So, we're passing four LIs, which is nice. So, let's take a look at what our constructor is doing. All the way up here. And, I'm just going to put a Debugger so we can step through it. The test is passing, but that might mean we have a weak test. So, let's take a look. Let me clear out our old stuff. I'm going to take a look at elements. Oh, elements coming is coming in as undefined. Let's make sure. What's that? (mumbles) I'm with you. Okay, so elements is coming through undefined, as are, oh, this isn't what we're looking for. So, our selector coming through should be an array. And we have UL. So, this is the first one. So, we want the second one. Let's go through. This should be. Here we go. So, we have an array coming through. So, this should fail, because this is not going to be a string. It's going to go here, elements is going to be our selector array. We're going to go through, and we're going to iterate three times. That should fail, there we go. And now, we have, let's take a look at, this, what our object looks like. We have three LIs. We're about to have a length property. Each of these LIs is one of our DOM Nodes. That looks good. So here, that looks good, all right. It probably is working. I probably just didn't save the page. Oops, play through that. It is working.
Traversing Elements
Exercise 18: Implementing the next() Method
We have the ability to look for elements by themselves in DOM. We have the ability to look for elements within those elements in the DOM, and then modify either collection to our choosing, which is really, really nice. But, there's a lot of situations, let's say we're going to build a tabs which like we are later today, where you probably want to modify some other element based on your location in the DOM. Maybe you want to find an element that's next to you or you're wrapped within an element, you want to find that parent element, there's a bunch of different ways... a bunch of different properties we have at our disposal to make this possible. We're all going to cover this in our traversals. So, let's take a look at... our little dummy set of DOM here. We have a basic unordered list with some items. But let's assume right now, our element that we care about is this li in red. This is the one we currently have access to. Maybe we've done some kind of query selector, or wrapped this in a jQuery object already. And based on this location, we want to find other elements in the DOM. This is what we have access to. So we have a child nodes property, we've seen a little bit of this when we were building our text helper. This is going to give us access to all the nodes within this li. We have first child, which will give us just the, Oh, that's strange, why is it coming black on the projector? Let's reload that animation. There we go. We have the first child which will just give us the absolute first child node we have. We have last child, which will give us the last node in our children. We have next sibling, so if we're at this li, the next DOM node following it would be this bottom li, this will be available via next sibling. Previous sibling, which will give us the prior DOM node. We have parent node, which will give us our wrapping or containing elements. And then we also have children, let me see if I can, there we go. Children is really, really nice. It's going to give you all the child nodes without text nodes. This is a fairly recent addition to JavaScript. A lot of times we are manipulating, let's say you have an unordered list, maybe it's a fancy hover menu drop down kind of thing and you want to manipulate your child in some state. you don't really care about manipulating the text nodes. So up until now, we've had to filter out text nodes, but, with the new children property, the browser will just give this to you. This will give us all child nodes, all the child DOM nodes. Makes sense? Okay, so we're about to build a few helpers, specifically we're going to build the next helper based on our current position, we're going to try to grab the next element in the DOM, our next sibling element in the DOM. But we still want that same chain ability. There's a couple of things: we want to return a jQuery collection, because you don't just want the next element for academic reasons, you probably want to change its HTML, maybe you want to add some text to that element. If right now it's an MDLI, you want to modify it somehow, so we want this to be possible. So we're going to take... our current collection, I'm going to walk you through this, I'll give you a little bit of pseudocode for this, be able to traverse to using a next sibling to get the next node. Now here's the little gotcha in the hints down below. Children is kind of our nice thing that ignores text nodes, but next sibling, and subsequently previous sibling as well, do not. If you hit next sibling, and the next, let's say you have a div, and then some text, and then another div, and you hit next sibling, what jQuery wants to give you is like, "Oh, you're looking "for that div," it'll skip the text nodes. Next sibling will not, it's explicit, it will give you the next node of whatever type. So when we're doing this helper, we want to be able to check for that. So let's write this out. Let's write part of this out. Scroll down to our next. Okay. So the first thing... we're going to do. We have to do something similar here, because if you have a bunch of divs on the page, and you want to say dollar, or you want to do something like this, dollar div.next. This is going to return an array, a collection of elements, because there could be many divs, and you're going to get the next sibling of each one of those divs, and return that as a collection. So to make this possible, we're going to need... our accumulator. Once again, our accumulator array. This is where we're going to store all the elements we found through the course of this function. And then at the end of this, we're going to need to return an instance of our jQuery library, and pass in our accumulator. Very similar to what we just did. We're going to need to go through each element, again, if we found many divs, and we want to get the next sibling, where each element in our collection, we're going to need to go through... and we're going to add things to our accumulator, but only in a specific case. We want to check or, we can say... if element is not a text node... add to our accumulator. This is the basic setup for what we want to do. Also, excuse me, if this is not a text node, just add it right then. We've hit the next div, we've hit the next li, this is what we care about, throw in the accumulator, and we can move on. However... if it is a text node if element is a text node... does anyone know what we want to do in this scenario? What if we have a div and some text and another div? When we say the first div.next, we want to get that last div. How do we get there? Does anyone know? Anyone think of what we might want to do? Next sibling will give us the text. So what we really probably want to do is call our element.nextSibling.nextSibling.nextSibling let's say forever, until we get to that actual next node. But we can't do that directly. So we probably want to recurse... to next... node. We want to keep moving down our next sibling chain until we hit a node that is a DOM node. And there is one last case that we should handle... what if nothing is found? What if we're at the last element on the page, or the last element in our parent, and we say next sibling, what should we return? In jQuery's case, it will return an empty collection, so we should handle something like this, too. If no element is found, if we've recursed and we're at the end of our chain, and next sibling is null, then... return empty col, or just don't add any, rather don't add anything, do nothing. Because we won't add anything to our accumulator in this case, and then our constructor will take care of our empty array, because accumulator will be empty. Does this all make sense... without giving too much away? Okay, let's take, let's see. Let's take 10 minutes, yes a question? There's a couple things that were a little bit before, are we going to go over DOM events today? Yes, we are going to go to DOM events right after this. There's going to be a couple of sections in elements, we have to get through, traversal and then layout, and then we'll be touching DOM events towards the end of this. There'll be a nice section for events. Events are very important, so we're not leaving that out. And the next question was about signatures in JavaScript, just saying that functions don't actually have signatures, it's just helpful to think of them that way, because you can't actually overload functions in JavaScript, is that correct? You can't overload functions in JavaScript, that's why we have like call and apply being called different things, but you do have the concept, you're still creating an API, so the DOM is going to give us its API that we're using internally here, and even though arguments can be anything, you can pass nothing to a function, you can pass a ton of arguments to a function that has nothing defined, so it's not signatures in the strict sense, where it's like a strongly type language where if it requires two arguments, you have to give it two arguments. Not in that sense, but it is in the sense where you could do a function.length. I don't know if you guys have ever done this, like var fu equals function. You could say fu.length. That's actually going to give you the number of arguments that you have defined in that function, which is kind of a nice little shortcut if you're trying to guarantee some length of arguments or optional arguments or currying, if you're doing any kind of currying functions. So I would say we do care about signatures, just not in the strictest sense of the term, but there is no method of overloading the JavaScript, that is very true, good questions.
Exercise 18: Solution
So first off, we're going to start very similar to what we did before, our accumulator. We're just going to call it elements... for originality. And we know at the end of this we want to return an instance of jQuery. So we're going to say return dollar elements. For our iteration, we can use our each helper, so I'm going to iterate through each one of the items in our collection which will give us back... this type of setup. Now here's the part we care about. We want to see if an element is not a text node, but we also want to move on and on and on. So first up, we need to actually find that next sibling element, so we can say, I'm going to call this current for the moment, because we're going to move down this chain of next siblings potentially. So I'm going to say current equals el.nextSibling. And then we want to say, if current dot nodeType... is not equal to three, if it's not a text node, go ahead and just add this to our accumulator. So I'm going to say elements.push(el)... else if current.nodeType... is equal to one, if it's DOM node, oh, excuse me. If it's not equal to three, yes, okay. If it's, I got these backwards. Three. Nope, that's right. If it's not a text node... to make this more explicit, let's just make sure it's a DOM node. There we go, that's what we're going for. If the current node that we're on is a DOM node, go and push it on to our accumulator. If it's not a DOM node, go ahead and move to the next. So we'll say move to next sibling, we'll come back... otherwise do nothing. And this is going to be our setup. Okay. Let me stop here for a second. Did anyone get theirs working before we go any farther? Nobody at all? All right. So for here, now we need basically some kind of check, some kind of loop. So you can do this a couple of different ways. I'm going to use a loop, where you can move through and keep moving through until some condition is met, and then we'll either push, we'll either reach the end of the array, or the end of our next sibling, or we'll just push something on to our... accumulator. So I'm going to comment this out momentarily. Let's write this a little bit differently. And do a while loop. Let's say, while current exists... and we can say current.nodeType, and we want to check for current, let me get to what this condition is going to be here. In this loop we're going to keep moving on and on and on. So next current equals current next sibling. We want to say if our while our current element exists, and current.nodeType is not equal to a DOM node, keep traversing. Let me move this out. We want to traverse. Let me make sure I have that condition correct. Yeah, node type, yep. Okay. So, from where we're at, we're going to come to the next sibling, and we're going to say, "Hey, if we're on one div, the next div is our current, our current node type is equal to one, so we don't need to traverse, so we can say if current is set at the end of this whole chain... go ahead and elements.push current. So at some point, during this loop, we're going to keep moving until either we hit a DOM node or we've run out of stuff and current is set to null. If current exists, if current was set in this process, then we're going to go ahead and push it on to our accumulator. We're going to do this for each item in the collection and at the end of the day, we're going to return our... collection. So let's rerun this for our tests. And now we have the next passing test.
Implementing the prev() Method
For previous, since previous is really, really straightforward, let's do previous together. Now, we had a bunch of different traversal DOM properties, next sibling is one, previous sibling is another one, so, just like we did for HTML and val, the easiest way to kind of do this is just to copy what we have here, and I'm going to copy it into our previous, I'm going to say, previous, previous, and this is going to do the same exact logic, it's just going to go in the other direction from wherever we start. I'll leave that up for a split second. Hope people are typing it out. And just to make sure this is working, I'm going to run over to our test page and now you can see we have next and previous both chainable, they're both returning jQuery objects, and they're both traversing down the DOM accordingly. So... Okay. We also have parent and children. Now parent and children are nice because we don't have to keep moving one way or the other. Children is really nice because now we have that additional DOM property called children. So, let's do parent first. So for parent, we're going to need to, let's think about this verbally first. We need to, let's say you have dollar div.parent. That's going to find all the divs on the page and return their parent elements in another jQuery collection respectively. So first thing off the bat, we're going to need our accumulator. Let me scoot this up the screen for you guys. And at the end of this function, we're going to want to return... a jQuery representation of our array. We know we're going to need to iterate through each element in our collection. So this function i, el. And within this, we need to find the current element's parent and then push it on to our accumulator. Now this one is pretty straightforward. I'm going to type out a comment here, element is our, el is our DOM element, and parent node is our DOM property that points to the parent DOM element. Can anyone in the room or online think of what we should put within this each? Anybody at all? Proto. Uh, no, this one's pretty, if we have... elements, the accumulator will just be an array of DOM elements that we find, so el is the current DOM element that we write in our collection, maybe it's an li. The parent node would be a reference to the li's parent, a ul most likely. So what we want to do is push that ul on to our accumulator. We want to save it, say, "Hey, this element that we're on, "it's parent is ul, and it's going to move on to the next." Maybe the next element in our collection is a div. Your parent is a body, it's the body tag. And we're going to go through collecting all of these parents onto our accumulator. So for this, all we need to do, actually is elements.push (el.parentNode). So, let me refresh there. And now we have passing set of assertions for parents. Oh, is there a lot of questions? Hey, Justin, can you help me out with questions in the chat? It's a friend that uh-- No, no, I mean, can you cop and chat? Yeah. We apologize, we want to get to events, so we're going to start tag teaming this a little bit. Uh, blaze through this. Okay, was there any questions on-- Can you kind of go through next again? Go through next again? Yeah, just walk through how it works. Sure, of course. This is good to understand because all of, pretty much most of these you can see now, we're getting to this pattern of finding an accumulator or creating an array where we're going to accumulate objects, iterate through them, and based on some conditions, push on to that array, and eventually return a jQuery representation of that array. So, for this, that's the first thing we're starting out with. Let's start, maybe, from the outside in. So if you talk about the first part, var elements equals array, this is just where we're going to store all of the elements that we find, all of the elements that we care about. Then we're going to go through each item in our collection and we're going to invoke our conditions on it, for in this case, for next, for each item in our collection we want to find its next sibling, whatever the element right next to it is. So, what we're going to do first, is say current equals el.nextSibling. Now if the next sibling in our collection is a DOM element, this while loop won't even execute. It's going to come here and say current, well that exists, so that's going to be true, current.nodeType not equal to one, well if it is a DOM node, then it will be one, so this will fail, it'll skip the while loop entirely, say if current, which does exist, elements.push our current element, so immediately if the next sibling is a DOM node, it basically skips from line 159 all the way down to 166, and just pushes that DOM node on to the array. If it isn't a DOM node, maybe it's a text node, it's going to start this while loop until it finds a DOM node, or until it runs out of nodes that are next siblings. So one of those two conditions are going to happen in this loop, it's either going to eventually come to the end of its container or it's going to find something that we care about. In either event, once it finishes, if something was found, we push it onto our array, at the end of this we return an accumulated array of all of the next siblings in our collection. This is the same thing that we do for parent, child, or previous. This is just the most complex, this and previous are the most complex versions of this, because we have to keep going to the next sibling, and then the next sibling, and so on and so forth. I hope that answered some of the questions there. Yes, go for it. Super quick, could I see the previous function? Of course. And it's just switching out the next for the previous, right? Exactly. You're going to have the same starting point, and you're going to have the same conditions and same logic, you just want to go into a different direction. Good question.
Refactoring Traversing Code
So you notice we've gotten quite a bit of repetition going on as developers, and as soon as we've repeated ourselves twice, maybe we start thinking about refactoring a little bit of code. So what we're going to do here is a slight refactor. We're going to create a make traverser helper method the same way we had isArrayLike as our private helper method. We're going to create one called makeTraverser and what this is going to do is going to take out a lot of that boilerplates stuff. We had every one of our traverser helpers, we had an accumulator, we returned a collection, a jQuery collection version of our accumulator, we did some function on each item in the array. Those are the common parts of our helper method so far. So what we're going to do is try to strip that out, so that parent, child, next, and previous are a little bit more terse. We don't have to repeat it ourselves. So, let's do that together. So, I'm going to scoot these. I shouldn't have minimized that. I'm going to copy... I'm going to copy two of these, previous and parent... just so we can have them on the screen up here. I'll put it right about get text. I'm going to call this makeTraverser. This will be a function. I'm going to copy these guys. Minimize their each loops, comment them out. So you can see, even on previous and parent, that are doing two very distinct things, the code is remarkably similar, and that's the part we want to kind of strip out. So, first off, we got to think about what is makeTraverser doing? We want to makeTraverser to return, and this is the part where we might get a lost a little bit. We want makeTraverser is going to be a function itself, but we want it to return a function that we can invoke later. So here, right off the bat, we're going to say, return function. Now one of the things, when you're building this kind of API, or any kind of API, you want to think about what does your function need to do what it does. In our case, if all this stuff here and here below is identical, that's all fine, the part that this needs to be dynamic is this middle section. The part that's within the each is what we want to invoke, but it's going to be different if you're a parent or a previous or a next. So what I'm going to do is I'm going to give this a callback that we will invoke for each one of our items here. Then, I'm going to put in our boilerplates, var elements equals array, we're going to return dollar elements. We're going to say dollar each this, and we'll talk about how that works here in a second, because this might be a little bit out there. And then I'm going to say function(i, el) and in here, we want to invoke our callback. So we could say, we could do this and I think for most of what we've done so far in this library, that will probably work-ish, as far as setting context, but we want this to be... explicit in two things: one, when we're passing arguments, and two, when we're setting context. I know I just dropped a lot of information really quickly, you know, just verbiage wise, so let's talk about this. So... one thing we want to do, we'll talk about context here first is we want to invoke our callback, but we want it to behave like it was before, like it was defined on the method itself, on the object itself. so here, we have the callback, this is something we want to invoke, but with a context that we specify. I'm going to use apply, because we're going to use arguments here in a second. And the context is we really want it to be what it was prior, the collection was prior, but within each, we change contexts. If you remember in our each helper itself, we actually changed contexts. If you remember the value comma i comma value, so we set it there. And this is actually one of the biggest, really common things we see slip up is what is this refer to. So I'm going to save a reference to it. This is a really common pattern. I'm going to say self equals this, because I want the context before this whole thing gets started. What's up? In the final, I thought that context is the actual element? Uh, the context... oh, in the final version? We could do that, too, that would reduce code. That would change our callbacks... to just be the element itself. Yeah, we could do that. I like that. Okay. Let's talk about this, what we just said here. Okay. I'm going to say el as our context here. Now, like we did earlier, this function itself is going to be different in different scenarios, and it can accept any number of arguments, whatever that happens to be, we want to make sure we pass that down. Now I can't say, I'd like to do... you know, in a very abstract way, I might want to do something like this, but this arguments is actually going to refer to its function call. We don't want those arguments, we really want... the arguments that are passed in to this function here. So this will be our signature. And now I'm going to go down to, I'm going to go down to parent, because parent is probably the simplest one of this. I'm going to comment this part out. And I'm going to say, parent is makeTraverser pass in a function... and our callback, makeTraverser in our context, because we said cb.apply with the element, we're just going to return... this.parentNode. This, in the context of this callback, will be set to the instance of the element within our loop in makeTraverser. So here, we have... let's see what we're doing here. So within makeTraverser, we're coming through... or we're going through each in the collection here. That's console log... what we're actually setting here. We are two li's. This is right. We got cb.apply, we're invoking our callback, but we're not pushing anything on to our elements, so here, we probably want to say, we're not modifying our accumulator, so let us do this. Let's say var, I'm just going to call this return, whatever our return value is. And we can say if... isArrayLike, this is a collection coming back. I'm going to say elements, I'm going to say array.push.apply. Elements our return value, else if return, if it's not null being returned then elements.push... return. Now we're adding stuff to our collection. You didn't close the array element. What's that? isArrayLike expect. Oh, I'm sorry. Now, with our check, we're setup to handle all three scenarios: parent node if it's returning a single node, or... next and previous if they're returning... I'm sorry, children, if it's returning multiple nodes. So, children, I'm going to say makeTraverser function... for this, we just need to return children. For previous... we're going to do the same thing, except we're going to do all of this... with previous sibling. Those can just be this... previous sibling, yep. And this will be a return. And that should be all the changes there, and then that, and we can do the exact same for next. This will be nextSibling. And we go back to our test page. Oh, we got parent and children working, but I broke next. Current equals this nextSibling, we'll go iterate... otherwise. Where was the error, what was the length? Uh, length of undefined. Language. IsArrayLike. Oh, yeah, I bet you it's a problem with isArrayLike. Probably with length undefined, I think pass isArrayLike is not working. So just make sure you're putting that, just handle that in your cursor. Oh, yeah. Make sure ret exists. Make sure ret exists. Yep. A few people commenting that we are kind of moving really fast. (student and teacher drown each other out) Yeah. We apologize, we are definitely picking up the pace. Uh, so now, that's all changed, we have next, previous, parent, and children working.
Attributes and Properties
Implementing the attr() Method
Real quick, just to recap what Alexis just did, it was all about meta-programming, right. I didn't want to, we didn't want to write that same code that would do for the parent method to give them the original collection, go with the parent of every item in the collection and create a new collection. I didn't want to have to write all of that code every time so we're trying to teach meta-programming so that instead, well I just give the relationship, I just make a function that gives the relationship between the source elements and the elements we want in the final collection. I can just describe that relationship and I have a function that does all of the repetitive work for us. And that's what we were showing so if you look back at our example, if want to learn about how to do meta-programming which is very common in open sourced frame works this is an example of it. Our make traverse are simply given a function, returns another function that goes through the source collection, calls the translation function to get the new elements out of it and eventually compiles them all into another jQuery collection. Cool. So now, we're going to finish up and try to talk about how get and set properties on an element, and how to read styles from an element. Yep. What about when you said someday removing the domino? Don't you need to read it when you're done? Depending on what the context is but we can talk about memory management if there's time at the end. So, getting and setting attributes. So the DOM provides a bunch of methods for getting and setting attributes. You've all seen like, a type on a, a type attribute. Sometimes those are properties like you can see below, but you can get and set them as attributes, alright. So real quick, if I were to take a look at this page. And at this point also, I'm going to do all the exercises. You guys don't have to follow along coding them, and we'll just use the final example to build the tabs at the end. If you want to do the tabs, we'll do it at the end. So I'll write all of my Query for us, but the tabs you can use my Query to write the tabs with it. So every element here, there's attributes. These are the attributes and I can get and set them. So if I get my wrong button, if I open my console, I get the input element. I can change it's, I can't changes its attribute. What I want to be able to do is change its attribute. I can call manually the DOM methods, set attribute to change its ID to input-ID, and if I look in the DOM, you can see the ID has changed. So jQuery's attribute method allows you to call attr, give the name of the property, and the value you want that attribute to be set to. So the name of the attribute and the value you want to attribute set to. So if I did like foo-bar, I'd expect this input to get I'd expect this input's ID property to be set to foo-bar. And if we don't do it, I should expect to be able to read it back. But that doesn't work because I didn't implement attr. So you can probably guess how to implement attr. Can someone guess real quick, it's going to be just like the HTML, it's going to be very similar to the HTML and val functions. Where is it? What am I going to be doing when I set an attribute? What was that method called? Set attribute? Set attribute! It's good to repeat because I want you guys to remember this stuff so if it seems like I'm giving you an obvious question, it's just to hammer it home. So I want to know if I'm in the setter. So if I'm going to be doing a set that means I'm going to be getting two arguments so I'll do arguments.length is greater than one meaning two. If it is, I'm going to go through each item and set its attribute to value. Make sense right there, just simply setting the attribute? And then if I'm not doing that, I'm reading, it's again the same thing as we did before. I'm going to return, make sure there's a zero, a first property in our collection. And I'm going to call what? This zero get attribute. Awesome. With the attrName.
Creating a css() Method
To read styles, first we actually do have a little bit, talk about how styles are applied to an element. So here in my page, let's say I had a link or a li, list item, with an anchor inside of it and I'm going to have the CSS of li display inline-black. I'm going to get my li as Doberman, and if I do doberman.style.display, what is that value going to give me back? Do you think? This display inline-block? You would think display would give you back inline-block but it's going to give you back an empty string. This style object here on an element that's when a lot of times when people think that it's, oh, it's going to have all of my element styles that are applied to it. But that's not the case, so if I were to get my, an li the same way and do console endure on it. You can see all of the style properties are emptied out. I'll explain why this is. Even though, if I had li, if I had any style sheet that was styling li's, these things would still be all emptied out. The reason is because there is a different way to get the computed style of an element and there's this kind of complex way of going about it which is called document default view, get computed style with pass of the element and get the style property that you want to read, alright, this is how you get the actual current CSS value as, kind of, coordinated from the element's style property, which might be set. There might be properties set here, and any styles defined in the style sheets. Like, if you read it this way you get what the actual value is. The style, you might be wondering what the heck is this style object for on elements then if you can't read it. It's only there so you can write it, it acts as an override to any styles in your style sheet. It's only there for JavaScript to really to write to, if you really want to read the full value you should do it this way. It's kind of weird, but that's how it is. Or if you create an inline styles, you could read inline styles. You could read them, but if, only if that property was set is that value actually going to be the actual value that that element takes on. Cool. So I'm going to write jQuery CSS method, which allows you to write a style on an element and also read the style on an element. And this is going to work just like all of these other things have. To read a style, we're going to use this but to write a style we're going to use that style object. Make sense? So I'll do this real quick too. So again, it's going to look just like the code before if arguments.length is greater than one. One thing I should point out is the attribute one list, it's missing a return. Thank you very much. I'm going to kind of copy this so if we're setting what are we going to do to each element that we're setting? How do you set a style? How do you change an individual element's style properties? Element.style. Element.style, and then how am I going to change so if this is, if I'm calling this like... I'll just copy this code here. If I'm calling this CSS function with padding, the CSS property is padding and value's 20 pixels how, this is the style object, how do I set something on it? How do I set a property on it? With bracket CSS prop name and set that to value. Exactly right, so this is how you can change an element's styles. Now to read it, I don't even have this memorized and I've written this exercise out so many times. What I'm going to do is it's document, default view, get computer style with the element. So I'm going to do the same kind of thing where I do return this zero and, I'm going to pass in the element whose computed styles I want. And I'm going to get the property value that I want to return to the user. Make sense, hopefully? So again, all that you need to take from these last like, 10 minutes or what I've been talking is to read and write attribute properties directly on an element, you use these methods or if you're using jQuery you use its attr method and if you're reading the computed value of CSS, you're going to use this computed style get property value. Or you're going to set the style property. If you're going direct to the DOM and if you're going to use jQuery you could just read this CSS, you can use this CSS method. So I'm going to demo all of this real quick to show you how fun it is. Let me Refresh. I'm going to get the input and I'm going to change its color to green, and now it's green even though it's not very big but it is green if you can tell. And then I can set its attribute. Let's just set some data attribute to bar. Now if I look at this element in the page it's got a data foo attribute of bar. And I can use that to read and write.
DOM Layout and Positioning
Given the HTML on your page, the CSS and actually the dimensions of your browser window how does the browser lay everything out? Right, especially block level layout. Right, and it lays that out somehow. It makes this div a certain width and then once the element has been laid out, often it's important to know how big that element is. If you're creating a slider or something like that, you need to know how big this element, what the room to slide around in is. Right, so there's, the DOM provides methods that you can get an element's dimensions and location in the page. So, the first thing, oh yeah. I have a slider demo that basically, when you're making widgets complex, we just like, on the order of something like jQuery Y, you typically have to read the current dimensions of things so that you make sure your slider can move around like in the exact right area, I have a demo but I'm not going to show it but suffice it to say when you start building very serious widgets whatever their styles might be, you should learn to adapt to them and that's why it's important to understand how dimensions and layout work in the browser. So let's start with the simple example possible. You've got a body element with a div inside of it that says hello world. And I'm going to paint this green, I should have a style with green but I couldn't fit it and we're going to start changing some properties around on it. So when you first render this page, if I gave the div a background color of green it would just be laid out right here and this yellow represents the default margin of the body. So this, if you open up a hello world with a div you'll see that it doesn't quite extend all the way to the outside of the page. Then if I were to give this element a width of 30 pixels and a height of 30 pixels, it would then take on that dimension. And if I were to give it a padding, this padding would be the same color, they'd be the same color green. I just changed the color green to illustrate that padding goes around the width of the, so I give a pixel width of 30 pixels and a padding of 4 pixels, the total size of the element would look like it was 38 pixels big. Alright, with the default box sizing of content box padding and border and margin is laid outside of the width of the element. So if I gave it a border of 4 pixels, the border would be added around and if I gave it a margin of 10 pixels on the top and bottom, and 3 pixels on the sides it would be laid out like that. And that's a little strange, too. So one thing to know is vertical margins are collapsed but horizontal margins push up against each other. So you can see here that there would be the margin is 10 pixels so it's going to be 10 pixels away from the top but the margin distance here would be 8 plus 3 pixels, 11 pixels. Alright, so it doesn't collapse the margins this direction which is a little, a little strange to me but that's how the DOM works. Now, I had a whole spiel here but it's going to take a while, so I'm just going to skip it. This is how a layout happens and just to say on a high level layout happens, horizontal dimensions are calculated first and then vertical dimensions are calculated second. But I'm going to skip over that. It's just not worth explaining right now. If I have time at the end, I'll come back to it. So the DOM, once it's laid everything out gives you some information about the dimensions of elements in the page. There's properties that you can read such as elements offset height and offset width. That gives you the element's dimensions from border to border. Vertical border and horizontal border to border. It also gives you a client width and client height so you could do element.clientwidth and element.clientheight and it will give you how wide the element is with just it's padding. What's weird is there's nothing that gives you the width of this content area. Strange, but jQuery does. jQuery gives you an inner width, an outer width, a width function and an outer width if you pass it true, it gives you the size of the margin. Right around the area, and also gives you these things for height, um...for height... it gives you height, inner height, outer height, and outer height true to get this, the corresponding.
Adding width() and Offset Methods
I'm going to implement a width function that gives us the width of an element. Given what you know, what the DOM gives you, how could I implement this width function? So I'll go back a slide, so I need this dimension here of available content area, I want that to give me that back, how could I implement, how could I implement it? Clientwidth minus padding? Minus padding, exactly right. So what I'm going to do is I'm going to make it so I'm going to read the content with value and I'll subtract out the left padding, the left padding and the right padding giving me the actual width of the content area. And I'm going to use my CSS method to do it. So, let me kill that. So I'm going to read my element's client width by doing this 0.clientwidth, and then I want the left padding and the right padding so I'm going to go left padding equals, how can I read the left padding? Anybody? How can I read the left padding? It's a CSS value. The computed... Well I could use my CSS method. So I'll use my CSS method to read the padding left and I'll also read the right padding. And then what do I need to do? By the way, what's your name? Chris. Someone other than Chris. What do I need to do now? Take the client width minus the left padding minus the right padding. Exactly, now one thing you should be aware of is these things are going to return. Left padding is going to be set to something like 10 pixels. What's a good way of converting a number to, or sorry, a string to a number? Parse ent. Parse ent. So I'm going to return clientWidth minus left-- parseInt leftPadding minus parseInt rightPadding. Boom. Now, if I refresh my page, I should be able to get a width of my UL. It says 301 pixels, let's check out what the inspector gives us so we can actually look at an element and it will tell us the computed styles, 301. Was that what it gave me? Yeah. Awesome, we are collectively geniuses. Good job. Couldn't have done it. So, let's do offset. That's the next one. So that's the dimensions, jQuery gives you all these ways to figure out the dimensions of your page, of your elements. The next thing is where is your element located? In the page or relative to other elements. So this shot here means I've scrolled the page down. Here's my browser window, it can't show the entire body. Here's the top left corner of the body and I've scrolled down a little bit, does that make sense? Like I've scrolled down, so here is the, kind of, hypothetical of where the top left corner of the body is but this is the only part I can see in my view port. Now let's say I have a div that's positioned relative right in this location. And I have another div that I'm going to position relative within this other element. And it's going to have a padding, a border and a margin. Now we want to know where this element is in the page, maybe where it is relative to its parent. Let's see what the DOM gives us to know this stuff. So the DOM on every element gives you an offset top property and an offset left that tells you your distance from your offset parent. So your offset parent is not necessarily always your parent element, but it is for this element. Your offset parent is the first parent element so if you look at an element, start walking up its parent elements until you find one that has a position property set to something like relative, absolute, static, sticky. Basically anything other than position static. That is an element's offset parent. So every element you would know it's coordinates from its offset parent, like this. Now if I were to remove position relative on this element, all the sudden because this is not positioned anymore its most direct parent, the offset parent would actually be the HTML element and this element's offset top and offset left would be given relative to the page as a whole. So the old way of having to figure out where your element was positioned in the page was to be, sum up all your offset tops and offset lefts by recursing up each offset parent until you got to the HTML page. Alright, so previously, if offset parent was still this, we'd get this offset top and offset left and we'd add that to this element's offset top and offset left which would probably be the, its offset parent would be the HTML element, so you just keep recursing it up and adding these numbers together. Fortunately, you don't have to do that anymore because elements also now have a get bounding client rect method, so you can call on this element, get bounding client rect and that returns an object that has a top and left, a top and left dimension that tells you this element's position relative to the view port, not to the page. So here's how far down this element is from the page. To figure out where it is, sorry, to the page, relative to the view port. To figure out where this element is relative to the page, how would we do that? So I want to know where this element, I want to know this dimension from this point to this point here. Figure out how far we've scrolled down. Exactly right, and I'll show how, I'll show how to do that in a second. Okay, so let's also talk about what jQuery gives us. jQuery gives us a position method you can call on an element and it will give you the offset, basically it's just returning an object that has the offset top and offset left values, that's jQuery's position method. jQuery also has an offset method that gives you the position relative to the page. it gives you an object that has a top and a left that's relative to the page. In my opinion, jQuery named these properties backwards. jQuery's offset method should be giving you the position relative to the offset parent and it's position method should be giving you the element's position in the page. It's got it backwards. So let's see how these all look together. So, jQuery's offset gives you the position in the page. Get bounding client rect on an element gives you the position relative to the window and then all of these things give you the position relative to your offset parent. In terms of performance, you can pretty much go whatever's closest that's going to give you the faster performance so position, offset left and offset top are super-fast to get the count of this dimension. So sometimes it's okay just to get your dimension relative to your offset parent. In those situations, it's nice to use these methods if you have like, really fast slider or something like that. It's better just to be calculating off of this information. Get bounding client rect is next very fast because that like, now everywhere and then finally get offset is fast in most browsers because it's just using get bounding client rect and just doing a little addition to it, but it used to be pretty slow. To get the scroll amount you've scrolled, the approved way apparently is doing the, is getting the page Y offset, it's how far you've scrolled down. So if you do window page Y offset, that gives you how far you've scrolled down. I prefer to use scroll top because that's what on other elements your scroll top and your scroll left is how far you've scrolled other elements. But this is more widely supported. So that's dimension stuff. So let's say we want implement jQuery's offset here's how you might do that. Simply given the first element, you're going to read the position of that element relative to the window, or yeah to the window, to the view port. And then you're going to include how far you've scrolled in each dimension to give the final value of the location in the page.
Adding show() and hide() Methods
The final thing, to make your tab's widgets work I'm going to add a hide and show method. This one is really easy. Hide you just set to display to none, and show should make sure that there is no display is set to empty so it will show itself again. jQuery's hide and show is a little bit more advanced. It can work even if the element style in the style sheet had a display none its hide will work, or its show will work to show it but I'm going to, I'm not going to do that. So let me make a hide and show, and this is the last thing before we hit elements. Or events, so hide should just be doing this.CSS display none, and show should be doing this.CSS display, empty string. So by setting to the empty string, we're wiping out the display none because maybe in this CSS someone had displayed inline-block to say display block. We don't want to overwrite it by assuming they wrote block of something like that.
Events
Event API
To listen to an event in the DOM, you do element.addEventListener, you give it the type of event you want to listen to you give it a function to call back, and then there's this capture flag, which we'll talk about what that does. To remove an event, you call element.removeEventListener, and you give the same event name and the same handler, and the same capture flag. We'll talk about what that means. So, that looks like this: if I want to listen to when someone clicks "Breeds" on the page, I give the, on the element, I say addEventListener, give it a click, give it a function, and we'll talk about what this means in a second. Pretty straightforward, hopefully. Who's...are there people who have never seen this? Has everybody kind of seen addEventListener? Most people? Good, cool. To remove EventListener, you always have to pass the same function that was used to bind in addEventListener. All right, so if I did addEventListener like this, so I want to listen on breeds when it's clicked, I will console log clicked, I cannot do this, I can't just pass a function that looks the same as the function passed to the addEventListener, because these are two different functions in memory. You have to pass the same function back. So, the way to do this is to typically make sure you save a reference to your function in a variable, then pass that variable, and therefore that function, to addEventListener so that later you can remove the event listener. So let's see this in action. So, I'm going to get my breeds. I'm going to add an EventListener to it. But wait, first, I'm going to save my Listener. I'm going to do a handler, I'm going to create a function, and I'm going to console.log clicked. Then, I'm going to add an EventListener, and say when someone clicks it, call back this function. Actually, not this function, sorry. Handler. Now, when I click this UL, I get clicked, awesome. And to stop listening, I'll do removeEventListener. Now, when I click, nothing happens. So, I think we're about to see all the different types of events you can listen to. Oh, no, we're going to do Add a bind method.
Adding bind() and unbind() Methods
So, jQuery has a bind and unbind method that lets you-- This is not right-- You have to pass it a function, but the same function in memory. jQuery has a bind and unbind method that lets you listen to a click event or any type of event on an element, and also unbind stops listening. So I'm going to implement that; it's pretty easy. So, if you guys can walk me through it, I'm going to do the each, which we all know, jQuery is always doing. I'm going to get the index and the elements. (typing) So, what do I need to do for bind? Who's going to be the new Chris? Who wants it, the title? You need to add an event. Yes! Question, what's the third parameter in addEventListener? Yeah, we will talk about what the difference between capture and bubble does, what that third parameter does in a second. For now, I'm not going to talk about it. I will be there in a second. So, I'm going to register a handler, and I'm going to type, put "false" in, because that's what jQuery always has, is false there. And for unbind, it's going to look the exact same. I'm just going to write removeEventListener, and that's it. Go through each element, bind on it, go through every element again, unbind on it. Now, I should say one important thing here. If you guys do feel confident, like, "Oh, I implemented jQuery after this. "Ah, you don't need jQuery, you can just do the DOM." Understand that jQuery does a lot of-- There's a lot more going on in jQuery than what I'm showing here for this kind of stuff. All right. So. So, event handlers are always called back with an event object, that's this "ev" right here. So, whenever I click on something, the function handler is going to be called back with a single argument, and that's going to be, have a lot of data on it. It's going to have stuff like: what is the current element whose events are being dispatched? What is the target? Like, what element was actually clicked on? What type of event was triggered? That kind of stuff, a lot of fun stuff, and even some methods that allow you to control how that element moves around. Because when an element is clicked, it actually like-- If you click on an anchor, that element will actually fire off events on the body, anything in between the bo-- like, the anchor element and the HTML element. It also will even fire off a click on the window. So, you can control how that flows. We'll get into that in a second. There's a couple questions that are coming up here. Is jQuery taking, also taking anonymous functions? Because if you register something anonymously, you can't unbind it? So jQuery has the ability to, has some nice ways of, even if you register an element, that you can, without keeping a reference to it, you can unbind it. One way is to, if I had an el-- if I had a bind on a UL, I could just call unbind, and that will unbind all event handlers jQuery has ever done on that element. So, yes, you should always, I mean, in general, it's good to keep your handlers around so you can unbind them individually yourself, but jQuery does have things that make it easier to deal with. The next question was does JavaScript support namespacing of events, like jQuery? No, it does not. Okay, so let me quickly go through the different types of events. (typing) Have that in Chrome... So, there's a bunch of different events that you can listen to. This page has a lot of them. I'll try to put this up, we just kind of cleaned it up. We'll try to put this up online at some point. So. These are the different types of events. You can listen to a click event, and that happens when someone clicks on an element, and this is the data that click event comes with, and we'll go through some of these properties, but if you do want to explore, this is a good page to do that. A double-click, you can listen to when someone double-clicks a context menu and the right menu comes out, mouse down, as someone hits the down, mouse up, when someone releases the mouse. Mouse out happens when someone comes into, over an element, and then leaves it. So you can see here, I'm leaving. And mouse over comes when I come from outside into the element. Mouse move is someone's moving. You can see it's-- you can see that offset X and offset Y changing like crazy with every mouse move. This is good for drag and drop. Mouse enter, I'll explain the difference between mouse enter and mouse over and mouse leave and mouse out in a second, but these are kind of similar. Mouse enter, mouse leave, mouse over, and mouse out. But they do have an important difference. And generally, you should always use mouse enter and mouse leave. So these are the events that deal with the mouse moving, but there's also a bunch of other events that deal with, like, HTML events, like when someone selects text in an input element. So I'm not going to go through all of these events. I will put this up so you can explore. The big ones I will talk about are the change event. This happens when someone changes a form value, and it loses focus, if it's a normal text field. Submit happens when someone submits, clicks a button, or hits Enter key in an input that will submit a form. Focus and Blur, as an element receives focus or an element loses focus. What about normalizing between mouse events and touch events? Is there a good library or a good way to do that? There are a bunch of libraries that do it. I've, like, you know-- A lot of people use jQuery Mobile. I've not actually had the pleasure of using that. I've done it myself, and most of the projects I've worked on for Mobile, but if other people have suggestions, good ones. jQuery actually doesn't do any event normalization to my knowledge, it's also a UI band, but I'm talking about, you know, that way you can have a tap that handles plinks and touches and taps also. There is a lot of good stuff, I know QRes, JS, is up there. There's just a ton of different libraries. There's Passbook, I think. That doesn't on tap. There's a bunch, but-- So, key events, you can also listen to, you can also listen to the keyboard, so there's a key down event, whenever, like, the mouse is on a down, or not the mouse, the key is on a down. And a press, if you're on a Windows machine and you hold a key, it'll keep writing key presses, but in Mac, by default, it's only like as the key is pretty much is being written out. The input event is actually very similar to that, the key press on Mac, but these behave differently in Windows, I think. Actually, I have to remember that. Don't take that literal, I have to remember what the total difference-- I think you can cancel input. (sniffs) Key up happens when you, when the key, like, when the person releases the key. Ready events happens when the whole body, all the HTML, has been loaded and is ready for you to start manipulating the HTML. And finally, the difference between mouse enter and mouse out. Unless, on the left, I'm doing mouse enter/mouse leave, which is what you should be using, and on the right, I'm doing mouse over/mouse out. Look what happens when I do mouse over and mouse out. See, there's a mouse over event, but there's also a mouse out event on the blue, when I go from here to an inner element, which is almost what you never want. If you're trying to do like a mouse-over effect, or something like that, you typically don't want the mouse out when someone goes to an inner element. Mouse enter and mouse leave, they do what you expect. As I go to an inner element, it doesn't trigger a mouse leave until I actually leave the element. So, use mouse enter/mouse leave, not mouse out/mouse over. So those are the events. This page is actually available in your demos. jQuery is page four, and that mouse over actually has I think a bug (unclear) of the same kind of demo, so be careful on the counter, because they're doing something a little different. (mutters) Now, how many of you have ever wanted to do a form that uses AJAX to post to a server, but doesn't actually refresh the page? Probably a lot of you. Have you ever had it where someone hit Submit but it's still, the whole page is submitted and goes to another page? Well, that's because the Submit event of a form has a default behavior. It has a default behavior of getting the form's data, and posting that to a server, and going to a new page. Just like when you click a link, it has a default behavior of going to a new page. You can prevent these default behaviors on an element with preventDefault. So this is why, if you ever wanted to prevent, like, allow someone to click on a link but not actually take them to that page, or allow someone to submit a form but not actually go to another page, you'll listen to the submit event, and you'll call event preventDefault. There's a bunch of default actions. This page lists them. And preventDefault is what prevents all of them for a particular event. So, I think I have an example of this. So, you would, in your event handler, call event preventDefault, and that's basically it, and you would register this event handler. Simple. So, let's talk about the event data that comes. I'm not going to go into it in detail, but like we showed in the, in this, every event has a lot of data that you can use. Like, if I held the shift key while I did a mouse up, Shift key, I just hit a million other things, should be true. The most important ones are the type of the event. This will be, basically, the name you put here. The target, this is the actual deepest event that the, or deepest element that the event happened on. So if you have a DOM and you have a link way deeply, or, I guess, from your guys' perspective, way deeply nested, that you actually clicked on, that's going to be the target. But that event is going to bubble up, and whatever event handlers, whatever element's event handlers are being dispatched, that's the current target. We'll see that in a second. So, there's also mou-- For mouse events-- This is kind of a-- Actually, I'm going to skip the events, because this is boring. Let's talk to the good thing. Let's really understand how event propagation works in the--
Event Propogation
Let's add a DOM structure like this. I have my window, it had a document inside of it, it had a body element, it had a div, and it had an anchor element. I'm going to click on that anchor element. What's going to happen is the browser is going to dispatch every event handler for click that's on the window's capture phase, (tapping) and then the document, and the body, and the div, and then it's going to dispatch all of the event handlers on the anchor element, and then it's going to dispatch on the bubble phase all of the event handlers registered on the div, the body, the document, and the window. So when I talk about-- Remember that last argument we passed to addEventListener? It was true or false, it said use capture? That controls whether you're listening on this side or this side of how the event propagates when an event happens. So, to kind of repeat that real quick, when you click on that anchor-- Actually, let me, I think we have a good demo of this. What is the demo page? It is Events Propagation? (tapping) Okay, here's that same page. Let me show you the HTML for it. (tapping) Where is it? Slides? This all combined...events...propagation. Okay, so, here, I'm listening on the body on its-- If you don't put anything here, it's the capture phase. And that must not be true. I'm sorry, if you don't put anything here, it's the bubble phase. So I'm listening on the body's bubble phase, so I'll go false here, and I'm listening on the body's capture phase. And I'm doing the same thing for the div, for bubble and body, ah, sorry, bubble and capture phase, and the anchor, for its bubble and capture phase. So when I click on the demo, I click on a link here, you can see it says body captured, div captured, then it's going to do the A, all of the A event handlers in the order that they were registered, and then it's going to do div bubbled, body bubbled. So let's go back and explain this again. So, by putting capture true, I can listen, so when someone clicks here, I can listen before that event actually gets dispatched on the EventListeners on the anchor. Does that make sense? Like, I can listen, I can preempt, if I wanted a logger that logged everything a user was doing, if I listen on the windows, for window clicks on a capture phase, that will get called before any EventListeners on the anchor are dispatched. This is called Event Propagation in the DOM. Because when you click on a link, events are dispatched on the window's capture phase and bubble phase listeners. Does that make sense? Any questions about this? This is one thing I would like it if you guys retained and made sense. Could you give a real-life example of one that might be useful? A logger? On the capture phase, a logger is where it's really useful. If you want to know every event that someone's doing, you would listen here, because you can stop events from reaching the window by calling stopPropagation, that prevents the bubbling. If you listen here, no one can get to the event and stop it before you get it, if that makes sense. Good question. Yeah? I'd ask you about what about attaching custom events to DOM nodes and triggering them. Is there a way that you can do that with that EventListener? Yes, the DOM does provide a way to dispatch events. I can't remember if dispatchEvents is the IE you do. It's this weird kind of, you do some kind of at initEvent, and you provide all the properties for the event, and then you can pass that event object to some method on an element, I forgot what it is, and that-- You can do that, with Custom Events. You can dispatch your own custom events. So, let's move on from Event Propagation. Basically, the short thing to take from this is that, when you listen, let's say you're listening on the window for clicks, you're still going to be responding to clicks on an anchor element, because these events work their way through the whole DOM. So I'm going to skip through-- Can you stop propagation on the Capture phase? Yes. As well as stopping propagation on the-- Yeah, you can stop on both phases. That's a good question. So, stopPropagation is this method that prevents events from going from one element to the next. Actually, I'm going to open this up in, well, we open up here. Okay, so, again, when I click on this, the body capture phase listener is going to be dispatched first, the div capture phase is going to be second, now it's going to dispatch all of the anchor element's event handlers, but in the order that they were dispatched, because there's this weird target phase thing that happens. But then the event is going to start propagating back up, dispatch the div's bubble phase and the body bubble phase. Now, the crazy thing here is, in the capture phase of the body, the thing that's going to be done first, if I do event.stopPropagation, and I do this example again-- I am loading the wrong page, I'm sure of it. I'm in the wrong, this should be slides, demos, Frontend masters, (unclear)... (tapping) There we go. Okay, so, now if I do that, it only hits body captured, and nothing else is dispatched. So, a few more things I want to talk about with events. Just to kind of give you an overview, even if it's not going to sink in, my apologies that we're kind of running out of time here. I at least want you to be aware of it. There is a stopImmediatePropagation, so stopPropagation only prevents a single, it prevents propagation from going from the current element to dispatching the next element's event handlers. So, if you call stopPropagation, and let's say the anchor has like five event handlers, it won't prevent any of the other anchor's event handlers from firing, which is kind of weird. To show what that does, let me just show the example again. So let me just remove this stopPropagation, and if you remember, again, when I click this, a bubble actually happened before the capture phase, so let me, in the bubble phase, which was registered first, I'm going to call ev.stopPropagation. So, you see here, even though the stopPropagation happened here, this event was still fired. That's because stopPropagation only prevents it from the next element's events from being fired. All of the events on the anchor will still be fired. To prevent those from being fired, I could call stopImmediatePropagation, and this would stop all the events on the anchor from being fired, any other on the anchor or any on the parent from being fired. Yeah? If you attach click handlers to different elements, like all links, and as well as the body tag, how do you tell the difference between what was clicked on? And then someone mentioned current target, which is the answer, but-- Yeah, current target is the answer. So, these, like I said, the event object has-- There's two interesting things on the event object. Here I'll listen on the, I'm listening on the body bubble. I'm going to put out the ev.currentTarget and the ev.target. I'm going to write those out. I'm going to remove my stopImmediatePropagation, too. Okay, so, when I click on this, the body bubbled is going to tell me the current target, that's whose event handlers are being dispatched. Well, the body's event handlers are being dispatched. That's why it gives me the body, but I still get, as the target, the element who I actually clicked on. So that's the difference between current target and target. So, the cool thing we could do is, essentially, even if we have the same handler, and I think I could write phase or something? What is it, Alexis? I don't remember. (unclear audio) Ah, well, never mind, don't worry about it. Here, I could put the same handler over and over and over again, and this way, even if we're using the same handler, we can still kind of tell, the function can still kind of tell where it is and a little bit what's going on by just looking in the event object. So, same function is going to be called back every time, but it's going to have, first it's going to be in the body, the target's always going to be the anchor, then it's moved to the div, then it's on all of the anchor's registered event handlers, and then it's moving to the div, and then to the body. Back up to the body.
Event Delegation
So there's one other thing that's good to be aware of is Event Delegation. It's this cool thing in jQuery that allows you to listen, instead of listening on every, let's say you wanted to listen to when all anchors in the page are clicked on. Instead of listening, instead of listening on, going to every single anchor and setting up an event handler, you can set up an event handler on the body and check if the target was an anchor. So, registered event handler there, and then what you would do is wait for that event to propagate up to the body, dispatch the body's event handler, and then you would check the target to see if that was the element you were looking for, to do stuff on. So, to give an example, if I wanted to know any time an anchor was clicked on and say you just clicked on an anchor, here's the code. I can listen on the body for a click, check if the target was an anchor, and then say you've clicked on an anchor. Kind of handy. That's way faster than going to every single element and setting up an event handler. And, this works if people add or remove anchors at will. So, I have an event delegation, but I'm not going to show-- I'm just going to say jQuery has an event delegation, has event delegation that lets you listen on an element, but listen for any time a div might be clicked in the body, and will call this back for you. So, this is super useful if you have anything high-performance, if you're trying to draw 1000 rows, like, TRs, and you want to listen to any time one of those TRs is clicked, don't register an event handler on every one of those table rows. Set up on some element something that listens to when a TR is clicked, and only set up one event listener. Much faster. So, what jQuery's on click does, just to walk through it again, a little bit better, is it listens to, it has its event listener on the body, and then it's just going to check if this matches the selector div. And if it doesn't, it's going to go to that element's parent, and check if that matches the selector div, and if it does, then it's going to do the call back. It's going to call some call back. And I have a, there is an example of this in place, but I'm not going to walk through it, unfortunately. I don't know if Mark will let me send in a personal video that I could add to this. Huh? Later? Okay. I'll make this last, like, half hour of content, and then I'll clean it up good, and I'll send it, and then you can append it to the... if that works. Cool. Other teachers have done that. Just link it to the, you know, underneath the video. Or, underneath the course. (inaudible) So I'll go through how the event delegation is set up, and I'll probably do a run-through of this whole events so that you guys can get it. My apologies for kind of running late. There's a lot to squeeze in, if you're going to learn everything there is to know about JavaScript and the DOM and jQuery in two days. So, thank you for hanging in there. Yeah, don't-- The one final point: don't use don't use DOM 0 and DOM 1 event handlers. You might see people sticking onclick in the page like this. Now, if you're doing it with Angular or one of the frameworks, it's a little bit different why it's okay there, and not okay here, but this is how people used to add event listeners. Don't do that; I still see that once in a while. And instead of doing this, use the addEventListener, because that allows you to listen, have multiple event handlers, instead of just one event handler on an element.
Building a Tabs Widget
Building a Tabs Widget
So here's my jQuery. And here's my tabs Okay. There was one final thing that I kind of slid in this exercise, how many of you have written a jQuery plugin? Where you do the $.fn, yeah, Mark's the master of it. Where you've done the $.fn. yourplugin name thing? Just Mark, here, so when you guys, if, I hope you become jQuery plugin authors, or you know, maybe other open source frameworks start contributing to (sweatshirt muffles), oh, sorry, trying to make a joke and I, is it all right? I don't know, did it catch? No, it didn't catch, it went over the... Sorry about that. (laughter) So, when you write a jQuery plugin, there's a standard way of doing it, you write $.fn.tabs and what that does, is it automagically makes it so, if I had my breed's UL I could call tabs on it, like this. That's what I want to be able to do. Alright, in reality, what you're doing when you write $.fn.tabs is you're writing $.prototype.tabs. Pretty darn close actually. What you're really writing is, You're writing $ dot, I think it's init.prototype.tabs. I can't remember where it is anymore. The prototype. It is somewhere slightly different but what you're, All this time, jQuery is just trying to hide the fact that you're doing prototype that will, that like, $, there's a constructor function in there. And you're just adding methods to its prototype. So in ways I feel like it did the world a little disservice, because would know prototypes, prototypical inheritance, little better but at the same time it would confuse people. So I understand why they did it. So what I want to do is make a tabs widget that's going to read, that's going to take this UL here and make it so when I click on doberman, it's going to show this div with ID doberman but it's also going to keep all of these other elements hidden. Right. This is your standard Hello World tabs widget. Let me open up DOM tabs or DOM reads. Actually I've got it open in Chrome, I think, already. Okay. So, yeah, I just want to be able to click these things and have it take me to, but I want it to have it close these other elements. So this is kind of, we wanted to progressively enhanced tabs widget, for those who know what that means. That basically means the DOM works without anything and then we add the JavaScript to it and it makes it work like, the HTML works if JavaScript is there or not. But JavaScript is working in this case so we're going to make it into a tabs widget. So when you click on doberman here, it's going to know to open, show this doberman because the href is pointing at the id of this element, so let's make this work. So the one thing I had to add, which I forgot to add when I was talking about it, was we're just going to add fn, an alias, to $.prototype So that allows us to write $.fn.tabs, just like jQuery. So the first thing I'm going to do is each UL, I'm going to call the tabs on the UL 'breeds', and what I need to do is go through every LI and hide all of the LI's panels, except for the first one. So I'm going to, given my, I'm going to go through my collection and for every UL I'm going to create an independent tabs widget so this is going to be the i, and this is going to be the UL and then for each LI, I'm going to make a UL into a jQuery wrapped item. So I'm doing it this way because we didn't make our $ constructor function work so if you just pass it in element it also will make it a collection but we did make it work so if you pass an array of elements it will create a jQuery collection for you. So I'm going to get the children, which is going to be each LI, and I'm going to go through each of those. This is going to be the LI and I'm going to do the same kind of thing to create that LI so it's nice. And all I'm going to do is I'm going to say, hey if the first, if LI is zero, then I'm really going to do nothing for right now and then if it's anything after the first LI I want to get its tab panel, the div that belongs to that LI, and close it or hide it. So to get that tab panel I'm going to make a little helper method but I'm going to call it like this, tabPanel. I'm going to pass it my LI and I'm going to expect it to give me back the div to close. And I'm just going to call it div.hide. So I'm going to make this little tabs panel helper. Now I'm going to really, I'm going to try to do everything like, the way I think it should mostly be done. I'm going to have a self-invoking function here, because I want tabPanel to be private to this tabs widget. And again, this is going to get an LI and it's going to need to return the div for it. To get the LI, or to get the div I'm going to have to get its anchor element so I'm going to get its children. I could use find if I wanted to be really fancy, I would use find. It's going to find the anchor element. We're going to read its href attribute. So I'm going to be given this anchor. I'm going to read it's href and get #doberman. Well fortunately for us that looks like a CSS selector that I can use to get this div. So I can write selector, what this is going to return. And I'm going to return the div using that selector. It'll go get that div and with that we're going to hide everything. So I'm going to start there and do a sanity check just to make sure that, at least, this much is working. This should hide all of the panels except for the first one. It did not. Let me quickly make sure. Let's look at property of tabs. What's going on? It's probably the CSS. I think it's before CSS. Before CSS? What do you mean? I think it's probably. Oh it's probably my deeproot. It's the same thing I ran into. I don't think we're going to be able to empty it. Let me try in my little trick here. See it's easier to do this, if we'd gotten through it all, my tests would be running, super easy to count on the, my version jQuery. I might switch to the final version just to, this &.fn is undefined. Is this the right version of my jQuery? Let me try it like that. Alright. Are you making changes? Oh sorry, I was going through. Go ahead. Just overwrite my stuff. I was just trying to find it. Okay, there we go, error's gone. And it worked! Okay. I don't know why that is. I'll check out why I had to do it differently than expected. Because $.prototype should exist. Oh maybe it's because we're overwriting $.prototype. Anyways, those are gone. Good. So now I'm going to make it so the clicking and everything works. So I've hidden all of the other tab panels that we don't want to show. I'm actually going to save the first one as our active LI. And what I'll do is I'm going to listen to all the LI's click events and, when they're clicked, I'm going to hide the active LI's tab panel and show the, and show the new LI that was clicked, its tab panel. So inside an event handler, like this, this is always going to be the event that was clicked, that was not clicked on, but the current target, whatever you're listening to. So if I'm listening to an LI, this inside of here is going to be a raw LI element. So what I'm going to do is, first, I'm going to hide the active panel, the current active panel. I'm going to say, get its tab panel for the active LI and hide it, then I'm going to get the current active LI. I'm going to update it to be the new LI that we just clicked on because that's the one that's going to be active now. That's the one we were trying to show. And then I'm going to simply show it by getting its tab panel and showing it. Hooray! And that's it! (chuckles) If you want to clean it up a little bit more, we'd remove, We'd make sure we prevent default so we stop changing the URL because this URL, you see how it's changing every time I click? I don't like that because there's no need for that. Now the prevent default prevents the default event from changing the URL. And that's it! That's the tabs widget. Uses a lot of what we learned. Hopefully, I mean, I'll post the cleaned up events stuff but what I like, one final spiel here, is I like knowing what's going on underneath the hood when I'm programming. I think it's really important, writing big pieces of software. You have to do it. You have know what's going on or else you'll make something slow, unmaintainable, etc. So that's why we put together this training. Because we want to show people, as quickly as possible, like what's going on underneath the hood. Too many people just learn jQuery and not the DOM. So we try to create a bridge where you can feel like you're learning jQuery, you are, but you're also learning a lot about how the DOM works. Yeah. So I've heard that return false also executes prevent default and, on top of that, it does a few other things too. Does it prevent stop propagation? I tend not to use it. I used to, like five, six years ago. I would always write return false, but I think that stop propagation and prevent default is so much more explicit in what it's doing, like I know I am preventing default, I know that I'm stopping the propagation, versus just some return false that happens to be in some function. There is also one problem with return false is, if there's an error in your code before it comes to return false then it's going to actually visit the length because you didn't, you didn't stop the propagation, you didn't prevent default. Because you didn't return false, you threw a JavaScript error and it just does something unexpected and then goes and refreshes the page when you didn't want it to. If you notice I just intuitively put the prevent default, the first thing inside this function because of that exact reason. If my tab panel for some reason threw an error it would not be preventing the default behavior. So typically it's a good idea to call those things right away, inside a function, if you really want to make sure they're going to happen. What I was going to say, too. I know there are other cases, too, where that's beneficial or, sometimes, return false is beneficial because, say for instance, they had JavaScript disabled and you want them, therefore, to go to the link. If they don't have JavaScript working, because for some reason, like I know, we have like a support page that is a modem, but if they don't have JavaScript enabled we want them to go to the static support page. And so it actually, the link behaves two different ways so we use return false. I have one quick clarification. It was in my mind, it was bugging me. So in for what most people see is, within jQuery, if it happens so it didn't bind click, now in real world jQuery, return false will stop everything. It will stop propagation and prevent default. But a negative event will start it will only prevent default and it will still propagate. Interesting. One thing about, you said, return false if Java is disabled it will It will prevent Huh? Prevent default would be the next cue. If JavaScript is disabled. Yeah but there are cases, maybe, maybe you would want it at the end just because hey, if there was an error, , maybe you should be going to that link, or maybe you should be submitting that form and fall back to, you know, whatever the server can do for you at that point. So there's different cases to have this up on the top and the bottom but I still like prevent default just because it's, a person has to, can read it and it's a little less arbitrary to me.
Course authors
Alexis Abril
Justin Meyer
Course info
LevelBeginner
Rating
(140)
My rating
Duration8h 59m
Released5 Jan 2016
Share course