STEVE_EDWARDS: Hello everybody and welcome to yet another exciting episode of JavaScript Jabber. I am your host, Steve Edwards, the host with the face for radio and the voice for being a mime, but I'm still your host. Today we're doing a panelist episode and with me is the man in the new house, AJ O'Neill.
AJ_O’NEILL: Yo, yo, yo, I'm coming at you live from secret undisclosed location and my mountain fortress.
STEVE_EDWARDS: And Dan Shapir coming from Tel Aviv, Israel. How you doing, Dan?
DAN_SHAPPIR: I'm doing well. Springtime here, and aside from some minor allergies, it's pretty nice weather. So enjoying myself. AJ, new house, but still a purplish pink wall.
AJ_O’NEILL: So I am confused. Do people actually think that my wall is purple? Yes. That was a joke.
DAN_SHAPPIR: No, it looks purple to me.
AJ_O’NEILL: No, it's the white.
STEVE_EDWARDS: Same to me.
AJ_O’NEILL: Have you never watched YouTube before in your life? It's a light.
DAN_SHAPPIR: Ah, okay. I just go by what my eyes tell me. It doesn't really matter if it's the color on the wall or the color reflecting from the wall, you know? It is what it is.
STEVE_EDWARDS: There you go. It's purple, at least to me it is.
AJ_O’NEILL: It's a light. It's just, it's a light.
STEVE_EDWARDS: Well, I asked you if you painted and you said yes, so I...
AJ_O’NEILL: Well, I thought we were going along with the joke. Oh, oh. I thought I was just playing along with it with the joke, because everybody on, everybody that has a YouTube channel has accent lights, you know?
STEVE_EDWARDS: Everybody does? Yeah, everybody.
DAN_SHAPPIR: Okay.
AJ_O’NEILL: Everybody. Pick up any random YouTube channel. Okay, not Joe Venezuela. Because I have one of his videos often and he doesn't have accent lights, but you know. Just open up youtube.com, look at the thumbnails and you're going to see the lots of accent lights and all the videos.
DAN_SHAPPIR: So that's kind of like a prerequisite. You're saying?
AJ_O’NEILL: Yeah, yeah, more or less. It's one of the first things you get is I think, I don't know, mic, first mic, then camera then lights.
STEVE_EDWARDS: Okay. So now that we've established that AJ's room is not painted purple, even though it looks like that, let's get on to the topic of the day. And Dan's going to be driving a lot today and we're going to be talking about some of the nitty gritty things of JavaScript nooks and crannies as Dan likes to call them.
Hey folks, this is Charles Max Wood from Top End Devs. And lately I've been working on actually building out Top End Devs. If you're interested, you can go to topendevs.com slash podcast and you can actually hear a little bit more about my story about why I'm doing what I'm doing with Top End Devs, why I changed it from devchat.tv to Top End Devs. But what I really want to get into is that I have decided that I'm going to build the platform that I always wished I had with devchat.tv and I renamed it to Top End Devs because I want to give you the resources that are gonna help you to build the career that you want. Right? So whether you wanna be an influencer in tech, whether you want to go and just max out your salary and then go live a lifestyle with your family, your friends, or just traveling the world or whatever, I wanna give you the resources that are gonna help you do that. We're gonna have career and leadership resources in there and we're gonna be giving you content on a regular basis to help you level up and max out your career. So go check it out topendevs.com. If you sign up before my birthday, that's December 14th. If you sign up before my birthday, you can get 50% off the lifetime of your subscription. Once again, that's topendevs.com.
STEVE_EDWARDS: So one of the things we talked about before we started recording was proxies. So Dan, first let's start out by giving us an update on or a description on what a proxy is.
DAN_SHAPPIR: Well, actually, I'd like to reverse the order if you don't mind. And I would because proxies are like the ultimate. Okay. And before we get to like the hammer. So before we get to the, to the heavy hammer, let's start with some more, gentler tools as it were more because proxy, you could literally do everything, but some, you know, tools that are more task specific. And I would like to talk about these first. So I would actually want like to start with a feature that's been in JavaScript for a very, very long time. But for some reason, I hardly see people using it. Maybe it's used in inside libraries, but in user land code, I hardly see it being used. And those are getters and setters. So getters and setters are something that were really popular in object oriented languages a couple of years ago and still are in some programming languages. For example, I think I've said on a previous episode that I'm actually learning Kotlin and in Kotlin, everything is a getter and a setter. That's not how it works in JavaScript. In JavaScript, if you're accessing a property, you're just accessing that property. If you want to use getters and setters, you need to do it explicitly and you do it by using the get and set keywords. Now I won't go too deep into the syntax because if anybody just wants to see how it's done, then all they need to do is search the wonderful MDN for getters and setters, and they will find example code that shows how it's used. But basically, you can associate a getter function with a property, and you can associate a setter function with a property. And then when you access that property, instead of just accessing a field, as it were, you're getting the value from that property with a getter function, and if you want to change the value, you use the setter function. A great example of something that works like that is the length property on an array. It's obviously not some field because it reflects the actual length of the array or of the string, so it actually needs to be like the face of some calculation. There needs to be some sort of a calculation behind. And the way to do that is to basically specify a getter function. So it behaves syntactically like a regular property, but behind it, semantically, it's actually a function call. Have you guys ever used getters and setters in your own code in JavaScript?
AJ_O’NEILL: Only to test it out or to work around basically a breaking API change You had to do something nasty so that between the two versions, people could still use the API the same, even though that something different needed to happen.
DAN_SHAPPIR: By the way,
AJ_O’NEILL: I've seen it abused. I don't really know that there's a use case for well-designed code to use it.
STEVE_EDWARDS: Well, I mean, it's something that I use frequently in PHP, for instance, Laravel, you know, for instance, where you've got a class, you know, and so you've got your class members and you use a getter to set it and or a getter to retrieve the value and a setter to set the value.
AJ_O’NEILL: But why would you do that if there weren't side effects? Why would you just set the value or get the value?
STEVE_EDWARDS: Because I like side effects. They're fun to have. They make things more interesting.
AJ_O’NEILL: Well, that's true. That is true. But no, I mean, like going back to first principles, why in the world would you want all the extra ceremony of a getter and a setter in any language? Where does this idea even come from? Cause I know I've seen it a ton in C sharp and I guess that's why Kotlin has it is cause it's, it's trying to be the more modern Java try to be more like C sharp or something. But what, what is, why would you want a getter in a setter rather than just to access a property in general, in a language that isn't JavaScript, let alone JavaScript?
DAN_SHAPPIR: So the most,
STEVE_EDWARDS: well, I can think in some cases coming from PHP, let's say you don't want to, you don't want to buy a class value to be changed publicly. You only want it to be used internally, right? So within the class, you need to change it for whatever reason, but you don't want anybody who understands each and object to be able to change it randomly, because that could have side effects. So in that case, then yeah, it makes sense to have some sort of function that sets it, but is restricted to only within the class.
AJ_O’NEILL: Is that real, though? Or is that just academic? Because all that I mean, I remember meeting in college, they talk about, you don't want unauthorized code to access the blah, blah, blah. I don't know about you, but I don't send my code around the office and ask people to make random changes.
DAN_SHAPPIR: Yeah, so building on what Steve said, so you can use getters and setters as a means of access control. So for example, if you want a property that's read-only, you can do it by just giving it a getter and not associating a setter with it. And then you can read that property using the getter, but you can't modify it. You can even do the inverse and also only have a setter. So you can have a write only property, although that's kind of rare. I've hardly seen that used.
AJ_O’NEILL: But it would be like a credit card.
DAN_SHAPPIR: Yeah, but actually in JavaScript, you don't actually need those because in JavaScript, you can actually specify that the property is read only. So you don't need to jump to the hoops of a getter and a setter to specify that the property is read only. So that's. That's not the motivation in JavaScript, but it is a motivation in some other programming languages. But the motivation that the creator of Kotlin actually gave is actually exactly what you previously said yourself, AJ, which is to preserve an API. You know, in these object-oriented languages, you implement an interface when you create an object, and interfaces are ideally kind of set in stone. So if you've specified a certain property in an interface, and all of a sudden you say, oh, it actually needs to be, it would have been better as a function call, but I can't change it because I've already specified it in the interface as a property. Well, because it's the properties of getters and setters, I can change what the getters and setters do. So that's kind of the motivation that these programming languages have for this type of a behavior. And that kind of also explains why it's less popular in JavaScript because, well, JavaScript doesn't have interfaces.
AJ_O’NEILL: Well, to say it doesn't have any. So I'll back up first. I think Go does this really well because interfaces are simply a definition of functions. If you define a set of functions, you have defined an interface. That's, that's, it's that simple. And I don't think that, that you're precluded from doing that in any language and any language you can, well, know that you are precluded from doing that a lot of the hierarchy based languages that don't follow the more strict object oriented sense like Go and to some extent JavaScript do. But you don't, I think this is kind of like the SQL argument, right? Like just because, just because you can have indexes doesn't mean that you must index everything. You know, just because you, just because you can do something doesn't mean that you must do it. And likewise, just because you're not forced to do something doesn't mean that you shouldn't do it. So having a definition, a documented definition of interfaces, I think is great, but I don't, I could see, yeah, the original argument I brought up is you made a mistake and now you need to fix it and this is the way that you fix it. One thing that comes to my mind, which I don't necessarily think is a good idea, but I know that some people do validations inside of those getters and setters. So, I mean, I think you should always have a function call. If you're going to actually do an operation, if you're going to, if they're going to perform an operation, it should be a function call. You should not create an accessor that to the outside observer looks like it's a property, but is actually a function using the getter, setter, syntax sugar. But if you need to pass an age and you want to make sure age can't be a negative number it makes sense to have a function set age, but not just to do age equals and have age actually be a function that's then taking in the number that you're doing the assignment on and then possibly throwing an error because that's really unexpected that if I were to do person dot age equals negative one, that it would throw an exception. It would be expected if I do person dot set age negative one that that could throw an exception.
DAN_SHAPPIR: So basically what you're saying is that you're going by the principle of least surprise that most JavaScript developers expect user land properties to be just simple properties and would be surprised if a certain property behaved like a function when it was either read or written to.
STEVE_EDWARDS: Yeah. And that's where I don't, I don't know why that would be beneficial to to do it that way in any language except for the case of, oops, I made a mistake. I locked the API. Ugh. How do I handle this? Maybe I can shim it this way.
DAN_SHAPPIR: Well, look, first of all, I basically agree with you. I hardly use getters and setters in my own code. I'm hard pressed to think of any situation in which I have. I personally even dislike the set H. I prefer a more kind of a functional approach, so I kind of avoid setting properties individually. I tend to pass in, let's say, an object, call it a structure or a property bag containing all the values that I might need into a more general function. That said, I have seen a lot of JavaScript developers use kind of setX or getX as specific methods on objects. So I guess most JavaScript developers do it the way you described it for no other reason, that they're simply not familiar with the built-in getters and setters. In other programming languages, like Kotlin, where everything is a getter and a setter, it's kind of mandatory knowledge. You can't get away from it. It's kind of like what they teach you upfront about the language, so that there is no surprise in the fact that if you set an age property, it can throw an exception. So basically, it's an expected syntactic sugar that instead of set age, you just write age, and there's no surprise there.
AJ_O’NEILL: Well, I think that's still surprising from the perspective that it that's not the way most programming languages work. But yeah, I get it that if you're in if you're in that ecosystem and you would know that. But I still if you want to set age, just have a set age. It's not a big deal.
DAN_SHAPPIR: Yeah, that is true. Anyway, so setters and getters do exist in in JavaScript. Like I said, you can create them using the set and get keywords or you can actually use property descriptors, which is something that we discussed in one of the episodes about the things JavaScript developers should know. I won't even go there if our listeners want to hear it. I really enjoyed those episodes, so they can as well by just going back and listening to them. So like I said, again, going back to the example of a setter having a side effect, you know, again, going to the length property on an array. If you can, a lot of JavaScript developers don't know this and are surprised by it, but you can actually set the length property of an array, which changes the length of the array. So for example, if you do.length equals zero, you've essentially removed all the elements from your array. You've, the array now becomes an empty array. So that's a surprising behavior of arrays that a lot of JavaScript developers aren't familiar with and again, exactly goes to this concept of getters and setters where the length is a property that has a getter and a setter on it. And these do something when they're used.
STEVE_EDWARDS: So technically, if I'm understanding you correctly, if you let's say you have an array of five items, whatever they are, objects, strings, numbers, whatever, and you want to trim it down, right? Okay, I want to make this array. I only need three. So are you? Am I understanding correctly that you could use this length setting to get rid of the last two and say, okay, now my array is three and it's only going to give me the first three?
DAN_SHAPPIR: Exactly. Although I would personally recommend that you use splice or slice or whatever,
STEVE_EDWARDS: right?
DAN_SHAPPIR: Then rather than modifying the array in place, it might be, you know, if you're really looking to, to do some micro optimizations because you've determined that some certain code is super hot.then maybe, but otherwise just don't go there.
STEVE_EDWARDS: Well, like you said, just because you can doesn't mean you should. I was just sort of fleshing out what you can do with an array like that. So conversely then, let's say you wanted to, you could just add some blank spaces on the array then and say, okay, going from fives, now my blank is seven, so I've got two empty items in the array. I would imagine that can throw some errors somewhere down the line though, if you don't fill it, couldn't it?
AJ_O’NEILL: It depends on what method you're using. This is one of the differences between four and for each for each. If correct me if I'm wrong for each skips elements in sparse arrays, whereas four does not. So with a
STEVE_EDWARDS: four in like a four in or four of, or something like that.
DAN_SHAPPIR: Yeah. Four in and four, four in and four only goes, yeah, the whole concept of sparse arrays, which we also discussed in the previous episode. Yeah, with sparse arrays, if you leave blank spaces within the array, then 4 in or 4 off will skip over them because they don't exist. Whereas with a regular 4, you're just going by the index. So you're just going relative to the length. So it won't skip. It just goes through all the numbers. You're incrementing the index by one, regardless of whether that element exists or not.
AJ_O’NEILL: And I think it may be different whether you push undefined or whether you because there's two undefined. There's undefined and there's not defined.
DAN_SHAPPIR: Well, in that regard, arrays are not different from regular JavaScript objects. I mean, you can have, you know, if I create an empty object, then let's say I put it in and I reference it with X, I can do X.p and I'll get back undefined because the property p doesn't exist. But I can also do X.p equals undefined, in which case, property P does exist, but has the value undefined. Uh, so it's sparse arrays are kind of similar in fact sparse arrays exist because originally at least they were just object with the index as proper values as all as properties. Right.
STEVE_EDWARDS: Oh boy. That's fun.
AJ_O’NEILL: I have done some testing with using new array and giving it a number versus doing array.from versus doing array dot length. I've played around a little bit with trying to micro optimize some things, just goofing around, uh, playing basically code golf or, or one of those leak code type challenges to see, well, can you get this benchmark to perform faster if you do this type of thing? And basically what I have found has been that If it's something that would be unexpected to a human, how it will be optimized will basically be at random. You can make a change that can make your code twice as fast or twice as slow, and then change something else, and then the same code that you had made twice as fast or twice as slow by changing from doing a dot push to doing a dot length and then indexing in, that same code that was faster can actually become slower because you added different code somewhere else. So I don't understand all of what's going on under the hood, but I would never suggest that someone look at a micro benchmark on something like that. And even in your own application, if it's something janky like that, where it's not part of the spec and it's not something that is intuitive, if it happens to make it faster in one benchmark, it might make it slow in another.
DAN_SHAPPIR: Lies, damn lies, and micro benchmarks. JavaScript micro benchmarks are really problematic because unlike other programming languages where you have a head of time compilation, which is pretty determinate, in JavaScript land, the way that the engines work, they identify hard code. If they have time to, then they optimize it. And it depends on how many times it executes before it's determined as hot. And if the and if the optimization might then get invalidated. So the whole concept of optimized JavaScript code is really, really difficult and challenging. And again, unless you have profiled your code, determined that a certain point is super hot and would greatly benefit from optimization and there's nothing better than you can do, like let's say changing the algorithm or something, because the most optimized bubble sort in the world will not be faster in the general case than a less optimized quicksort for sufficiently large datasets, then avoid these sorts of microoptimizations is what I'm saying. Anyway, so those were getters and setters. The next topic that I wanted to mention kind of goes back to that episode that we had talking about the const versus let versus var, where UAJ made the great point that const is a very as the term is really misleading. It's a misnomer because most developers, when they see const x, they expect the thing that x references to be immutable, not the reference itself. So a lot of, again, going to the principle of least surprise, developers are surprised when they see something like const x equals an object and then x. p equals three to modify that object because, hey, we thought that x was supposed to be const. And that's not the case. And there is a way to make objects in JavaScript effectively immutable, but it's kind of different than how it works in other programming languages, surprise, surprise. And generally, it's a lot less useful than in other programming languages because of it.level, you have on the object, you have a static global method called freeze. So you can do objects with a capital O dot freeze, pass in an object, and it will make that object kind of immutable. And it also, by the way, returns a reference to that same object. So it modifies in place and then returns a reference to that object that it modified. So it doesn't create a frozen copy. It freezes the actual object that you pass to it. And what does freeze mean? It means that you cannot modify any of the existing properties. If you try to modify an existing property by, let's say, changing its value or by deleting it, then you, in some cases, it will just do nothing. So it might fail silently. And in some cases, it will throw an exception depends on whether you're in strict mode or not strict mode and what you're trying to do and So forth because you know backward compatibility and whatnot, so it's it's not necessarily pretty but it does work So if for if for some reason you want to make sure that an object will not be changed Then that's how you can go about it And by the way, the dome uses this mechanism because some of the objects that the dome returns are effectively frozen, they are read-only, and you can't change them. And so this is a way to create a JavaScript object that behaves like certain DOM elements or objects. It could also be useful when returning something from, let's say, an API, and you're saying, this is the data that I'm giving back to you, and even though you're assuming ownership of this data, know that you can't change it because it is what it is. So you may want to do something like that. If you want to change it, then you'll need to copy the values over or something like that.
STEVE_EDWARDS: Yeah, that's something you would do with like object assign. Meaning when you're talking about copy the values.
DAN_SHAPPIR: Yeah, or these days you can also copy by using the spread operator when creating a new object later on. But yeah, object assign is a good example. If you might say, this or for example you might have some global that you're creating for some reason and you know you don't want and once created you don't want anybody to modify I don't know let's say some sort of let's say a session ID or whatever that's what that yeah that once specified cannot change throughout the lifetime of that session then you might put it in some sort of a global object and then freeze it so that nobody changes it by accident and
STEVE_EDWARDS: so when you're freezing stuff do you want hopefully you don't run into the problem of getting water in your computer. Cause out too much.
DAN_SHAPPIR: Yeah. Uh, there are, you don't get into that problem, but you do get into other problems. Yeah. I was waiting for that. So before I get there, I just want to mention that object also has another property called is frozen, which takes an object and basically returns true if it's frozen and false otherwise. So that's a way to test it. Because as I said, In some cases, if an object is frozen and you try to modify it, it might fail silently. So you may want to validate that something is frozen in order to ensure that you're doing the correct thing. But there are also a couple of other funny things around frozen. But you know what? Before we talk about these, there are actually some additional methods on objects that are kind of similar to frozen, to freeze, sorry. But are slightly different. One is called seal and another one is called prevent extensions. And each one of them covers a subset of freeze. So like freeze is both of them together. Seal means that you can't change what's in it already, but you can add more stuff to it. Prevent extensions means that you can change what's already in it, but you cannot add new stuff to it. And freeze is both.So where are these practically useful? Hardly ever. What I've seen, for example, so I saw one, the way that I learned Redux was by taking by watching a video course that Dana Bramov presented in the Redux model. You never modify the state. You take the current state, you take the current state in an action, the reducer takes two parameters, the current state and action, and then creates a new state that's essentially a copy of the previous state with some modification based on the action. So you're never supposed to modify the previous state. And the way that Dan kind of forced that, or...illustrated that was by freezing the current state to make sure that it's not modified accidentally and also to highlight the fact that it's not modified. Now we actually, and that kind of goes to one of the limitations of freeze, we actually use the library built on top of freeze called deep freeze because freeze in JavaScript is shallow that object that you freeze that is a reference to another object. You could, let's say, you think about a JSON where you have a hierarchy of objects. If you freeze the root, you're not freezing the entire tree. You're just freezing that root. You can traverse down the tree and then start modifying stuff. And deep freeze is just some user land code implemented on top of freeze that just traverses the tree recursively and freezes all the objects that it encounters.
STEVE_EDWARDS: I'm having visions of Arnold Schwarzenegger and Batman right now. Yeah, so freeze puns.
Hey folks, I'm here with JD from Raygon. JD, we were talking just a second ago about empathy, and it seems like a common concept within the programming community. And yet, when we're building features for customers, a lot of times we call it done when it passes CI, deploys and doesn't give us errors that really doesn't seem very empathetic when it comes to our customers because we're not looking at what they're doing. Do you have thoughts on this? Yeah, absolutely. I mean, at the end of the day, until, until your code actually hits the customer, um, you don't really know if it's any good. Uh, you know, everybody uses things in so many different, weird, wonderful ways. You can only really debug in production. Um, yeah, I've been there. It's done. It's not done. Oh crap. It's not done. I gotta go fix it. Now it's done. Yeah, absolutely. When we see things like error reports flowing into Ragon, a lot of the time it's things where you just kind of go, oh, that was a configuration that as a developer I didn't think could exist, but actually here's an example. And so it's connecting that code to customer and your development team through to real users and their experiences, which to your point builds real empathy and the best software teams care a lot about how their customers are experiencing their software. Right. It's kind of the feedback from the app, but it's also kind of this meta feedback. As we do better, we tend to get less of this negative input back from our customer, which really does reflect empathy. Yeah, absolutely. And I also think to your point earlier about CI CD pipelines, like we've done an amazing amount of work as an industry to automate getting to prod really fast. But if you really want to go super fast, you need to close that loop with real-time feedback from prod back to the dev team. And that allows them to do things like fail forward and just do. You know, really leverage that investment in CI, CD and, and it can turn into a real superpower. Yep. Absolutely. So I'm going to encourage you folks. Yeah. Set up your CI CD, but then go sign up for Reagan. They'll actually give you a free trial and you can get it at raygun.com.
AJ_O’NEILL: I'm looking at the MDN for these three freeze and seal and prevent extensions. And it breaks my heart, but not too much because already pre-broken. They behave differently. Whether you're using JavaScript or ES modules?
DAN_SHAPPIR: Well, it basically it behaves, you might say that it behaves differently if you're in strict mode or not in strict mode, I think.
AJ_O’NEILL: Here, it doesn't document strict mode. It documents ES module versus JavaScript, but it may be a mistake in the documentation.
DAN_SHAPPIR: Basically a reminder that when you're inside an ES module, you're strict by default. In fact, since you're not, you can't disable strict, then you're basically just strict. For those of you who don't know, string, and again, this is something that-
AJ_O’NEILL: Well, in ES modules, it's more lax. And in JavaScript, it'll throw a type error. In ES module, it will return an object that, or return a thing that can't be frozen as itself. So if you do object.freeze1, in JavaScript, it'll throw a type error. One is not an object, which makes sense, because you can't freeze that, and that's what I think you would want. That would be the strict interpretation of it but in ES modules, it will return one, which seemed to be, I don't know how to interpret that.
DAN_SHAPPIR: But they do something called-
AJ_O’NEILL: Did something wrong, you should have an error there.
DAN_SHAPPIR: Well, in JavaScript really, JavaScript has the concept of boxing. Boxing is something that, again, is a term that goes beyond JavaScript. It exists in other object-oriented programming languages as well, but not in all of them. Basically, boxing means that when you take a literal value like one, which is self, not an object, and then you try to use it as an object, the programming language automatically wraps it inside an object so that you can use it as an object. Because in fact, in JavaScript, you can do one dot dot two string, open close parentheses, to convert the number into a string. So you can actually.
AJ_O’NEILL: You can.You'd have to put it in parentheses so it gets evaluated as the number of dots.
DAN_SHAPPIR: No, you can do... I noticed that I said dot dot. Like not just the one dot, two dots. Try it out.
AJ_O’NEILL: Oh, so you're taking advantage of one of those parse error things where...
DAN_SHAPPIR: Oh, not error. It's specified in the language.
AJ_O’NEILL: Well, but it's like semicolon insertion, right? You can do these little tricks that will cause the parser to goof up and then the parser will backtrack and then it'll try again. So if you do a dot dot, which would make literally no sense it's some sort of hack that will cause it to evaluate it with parentheses.
DAN_SHAPPIR: Let's put it this way. You could have done 1.0.2 string and that would have obviously worked because the second dot is, you know, there's no point in putting two decimal points within a numeric literal and dot dot is just a shortcut for that. But basically, but again, we're kind of straying. What I'm trying to say is that in JavaScript literals, can behave as objects. And the way that it implements it is it does what I, like I said, the term is boxing. It automatically wraps the literal inside of an object. So in this case, it's as if you've done new number, open parentheses, one, close parentheses to wrap the numeric literal inside an object. So I guess that is what Freeze does in that case. But I hardly use freeze. I certainly don't use it on literals. So it doesn't matter much to me either way. I have recently, I've never used seal or prevent extensions. I have used freeze in that scenario that I described before, where I had some sort of a global object that, let's say, on the window that had some global data for the entire session. It didn't matter. supposed to be created at the beginning of the session and then never modified throughout the lifetime of the entire session. So I created and I freeze it so that if somebody doesn't does accidentally try to modify it, that won't work.
AJ_O’NEILL: So it's kind of, I see some of these as more, they seem like they're a retrofit for not having good tooling, right? Because instead of, instead of relying on your tooling to look at your JS doc and say, oh, this is a read only property. If anywhere in the code you're trying to change it, I'm going to put a little linter warning, Hey, you mark this as read only, but now you're trying to write to it. We have these things that are executing at runtime when they're basically doing what would, what wouldn't should be compile time and linter checks at runtime. Because if you access a property with freeze that's been frozen, that's a bug in the code. You wrote bad code. That's not, that's not, you're using a feature of the language. That's that somewhere there's a bug and you don't know where it is, and so now you freeze it, you can get a stack trace to find out where that bug is.
DAN_SHAPPIR: You're absolutely correct, but here's the thing. In some statically typed languages, not in all of them, constness is a part of the type system. So for example, in C++, let's say, I think it's in other programming languages as well, but I remember it from C++. In C++, you can specify that, when you specify that an object is const, that's part of the object static type. And then when you pass it around, you can only pass it as a const object. And then when you try to modify it, the compiler sees that part of the type is that it's const, and then it basically doesn't compile. It's a compilation error. And in JavaScript, obviously, we don't have compilation ahead of time. We have just-in-time at best.
AJ_O’NEILL: Well, not in JavaScript, but in ECMAScript everything is compiled.
DAN_SHAPPIR: Well, no, that's not correct. I mean Chrome isn't...
AJ_O’NEILL: Transpiled.
DAN_SHAPPIR: Well, I don't know. That doesn't necessarily, that's not, I don't, I wouldn't take, I won't say that. I mean, you've got, let's say V8, which is a JavaScript engine that implements ECMAScript, and it doesn't transpile your ECMAScript into anything. It just executes it.
AJ_O’NEILL: Well...What I'm saying is if you most people are not writing in JavaScript They're not writing in the language that runs in the browser They're writing in a different language such as JSX or even view now has a lot of its own things where you compile it if you're running node and you're not using top typescripts then you're actually running the JavaScript that runs on the engine. You're not taking a compile step but if you're using typescript if you're using react or JSX or any of these extensions or alternative languages you are compiling them or transpiling them down.
DAN_SHAPPIR: Oh yeah, I totally agree. And one of those programming languages could decide to implement const safety as a feature of whatever language they're transpiling from to JavaScript. But JavaScript itself does not have the concept of const as part of the type system. And consequently, if you freeze an object, what you get back is just an object and you can pass it around anywhere. So obviously, there won't be any compile time errors because there's no compiler to know about it. And like I said, it just looks like a regular object. In C++, again, you can literally specify that a certain, if you know that a certain method, it only reads values from the object and doesn't modify the object. You actually put a const on the method definition, and then it knows that it can call these methods obviously on mutable objects, but it can also call this method on immutable objects. If you don't put that const keyword, then if you try to call that method on an immutable object, the compiler will actually throw an error. That's something that just doesn't exist in JavaScript.
AJ_O’NEILL: I think the reason that Freeze originally came about was for exactly the case that I said, oh, this is theoretical, this isn't real, which is that you have untrusted code running with your regular code. Well, if you have ads on your site or you have, you know, these widgets or these plugins that actually aren't part of your application, it is possible that they can traverse objects that are part of your application and then go find something and modify them or steal a key or something like that. So in the web, I have to go eat my own words because in the web, it actually is possible to have cases where you don't expect code to be exposed to a third party, but it actually, it can be if it's in a browser.
STEVE_EDWARDS: Hey guys, before we get too much farther down the rabbit hole here, let's, uh, I'm going to kick us in the pants and move us on to your next topic. Again, are we getting close to proxies or you got other stuff to cover first?
DAN_SHAPPIR: Proxy is the one that's, that's the next one.
STEVE_EDWARDS: Alrighty. Let's do it. Okay. Cool. So like, by the way, I wanted to say that. In regards to the seal and all that stuff that gets my seal of approval. I was waiting to throw that in. Anyway. Anyway, so let's get cereal.
DAN_SHAPPIR: So proxy is the sledgehammer proxy is, is like this tool that lets you do like everything in anything you remember in the past, we have topic that comes up fairly frequently, often from you AJ is the fact that in, in browsers, the, the DOM itself looks and often behaves like JavaScript objects, but in fact it's implemented in C++. And it even has its own separate garbage collection in most cases. And one of the reasons that it's implemented this way is that it just does things that you normally cannot do in JavaScript, that you have objects that behave in kind of weird way, that again, property access has weird side effects and or the style object that you can get for an element. You can access it via the property names, but you can also use different names if you put them in brackets and strings, like whether it's camel-cased or what's the other term, kebab-cased. So you can actually access properties both ways. And that's not something that you can normally do with regular JavaScript objects. And it kind of caused an unease within the JavaScript standard committee, the TC39, that JavaScript is using within the language, is using things that you can't actually implement in JavaScript. And there was even an idea at a certain point to try to implement the DOM in JavaScript in order to maybe, as a performance measure, because you will need this bridge to jump from the JavaScript code to the C++ code and back again it would just be all JavaScript and all within V8 and everything would be great. So the idea behind proxy was to make it possible to have all these weird wacky behaviors within the JavaScript language itself. And the proxy interface is actually fairly straightforward. Proxy is a constructor, so you do new proxy. You pass in the object that you want to wrap as it were, they refer to it as the target. Because at the end, you'll still be reading and writing and performing operations on that object, but you'll be getting through it, to it, through the proxy. And the second parameter that you provide to the constructor is like this, another object that specifies methods that handle the various access operations that you can do on the original object. And what you get back is this proxy object that wraps the original objects and controls access to it. So you can still access if the original object is unmodified. If you work with the original object it works in the same way. But if you use the proxy object then you've got total control over how things are accessed. You have control over property reads, property writes, function calling vocations, whatever.
STEVE_EDWARDS: You know, I'm looking through the MDN docs on proxy, and I guess I always like to sort of put this, trying to understand the concept is to put it in a way that uses something that I'm already familiar with. So listening to your description and reading the documentation, the way I sort of see it in this, you know, they say all analogies fail at some point. So this might fail, as I see it almost like either like a middleware or something like a cloudflare worker, right? So you're handler gets the target before it gets to wherever you're going to use it. And you can tweak it. And, uh, well, actually, I think you said that the target itself doesn't change, but you can munch it, do whatever you want and then pass it on. Right. So like a cloud for worker, for instance, is, you know, something you is deployed out on an edge, uh, in a CDN, right? So you're getting something coming in and before it gets to your core code and database, you want to change something or maybe bounce it off if it has a certain property. And like a middleware in Laravel or even Nuxt is, you know, something's coming from your back in your front end and you want to intercept it and maybe bounce, you know, since, sorry, this isn't, you can't do this because you're not validated or logged in or you want to change something or tweak something. Does that sound like a correct analogy for a proxy?
DAN_SHAPPIR: Exactly. And it's a property name feature because it exactly is a proxy you're getting a proxy object that through that proxy you get at or to the original object. You're not supposed to access the object directly. So you gave an example of a cloudflare worker as a proxy between the browser and the actual server. And then the proxy can block certain operations or modify certain operations before they get through. The original server itself is not modified and you know not necessarily even aware that it has a proxy in front of it.
AJ_O’NEILL: Now, is this actually different from just using defined property? Because what I'm seeing here, well, I guess it's different in that defined property only works on properties that are defined, whereas proxy can work on things that aren't defined. So you can make those really nasty things like Rails has where find by username or ID gets parsed into the properties username and ID, and then it knows the parameters or username and ID or something like that.
DAN_SHAPPIR: Exactly. Like you said, if I can use the getter and setter mechanism that we originally mentioned, but then I create getter and setter on a specific property. I say I'm creating a getter for the property length, and that getter will only be used for that length property. With a proxy, I can create a general getter so that any get operation...Any property get operation on that, that goes to the proxy is intercepted. And the get callback that I provide to the proxy gets three parameters. It gets the reference to the original object that's referenced so that, you know, ultimately can pass along things to it. It gets the name of the property and it gets in reference to itself. But the bottom line is you've got, you've got the actual name of the property. So I can do funny things like I can play, let's say I want to support all, I want to make an object that is case insensitive for all its properties. Well, I can do that by via proxy. I can just, the proxy before it passes the property onto the original target object, just does a two lower case on the property name. And then it doesn't matter which the casing that you use on the property when accessing it, for example. So yes, you can do all these weird and wacky things. So you can specify a general handler for a property get, which is unsurprisingly called get. You can also set, obviously, use specify handler for set. You can also specify a handler for apply. So you can wrap a function as I hope our listeners recall in JavaScript, everything is an object. So that includes functions, functions are objects that can be used as functions. So you can pass a function as the first parameter to proxy. And then if you want to intercept the function call, you give the proxy an apply handler. And that apply handler will get, again, the reference to the original. So you can invoke the original, but also get the this argument and the argument list. So for example, you might modify the this, or you might modify the argument list before passing them on to the original object. Now, an example of what proxies might be used for is something that you mentioned, Steve, which is for observables, for observing things. If I want to have something that looks like a regular JavaScript object with regular properties, but that any time any of the properties are modified, I want to actually run code to, for example, update the UI or something like that. I can wrap that object in a proxy, specify a getHandler, and then everybody's not using the actual original object, they're using the proxy, and then the proxy is aware whenever somebody modifies a property and can do whatever with it beyond just modifying the original object. It doesn't even need to modify the original object if it doesn't want to.
STEVE_EDWARDS: Yeah. I'm talking about practical uses of this in my world, Vue, this is how Vue 3 operates. So in Vue 2, which is what's called the options API, which had to do with how the single file component code is set up, we use getters and setters. Somewhere we've talked about that before, I think, right? But with Vue 3, they went to proxies and went away from getters and setters and are using proxies. Now, from a Vue developer's standpoint, the proxies alone don't change how you write your code. It does to a certain extent how you define your single file components with what's called the Composition API. But it's using proxies behind the scenes to manage the reactivity and handle the reactivity of your code.
DAN_SHAPPIR: Other examples that you might think about, I can give two more examples. There's this concept in some programming languages, the word suddenly escapes me that you may want to apply certain functionality across the board to unrelated types of objects. So for example, let's say I want to log all access to certain properties, and I don't want to modify the original objects to do so, then I can just wrap them in a proxy that logs all the accesses. Oh, this is called aspect-oriented programming, where you can apply cross-cutting aspects discrete types of objects. So this kind of cost cutting concerns that have nothing specific to do with the main functionality of the object. Again, I want to take an existing object and I want to modify it to log all accesses to it. I can easily do that using proxy without having to modify the original object. Another example that I can give, something that I actually did once, I had this large legacy code base that had the certain global object and some code somewhere within that code base was modifying that global object in a wrong way. I couldn't find it. I just couldn't find where it was doing it. There was the window.globalData and some part of the code was modifying some property on that global data thing and I just couldn't find it in the code. And what I did is I replaced global data with a proxy that had a debugger statement in the property get or the property set on the set. And then when something tried to modify that object, that set triggered and I had the call stack to show where it happened. And that way I was able to find that evil bit of code that was doing the illegal modification of that global object. I could have frozen that as nuclear as the freeze option. Well, yeah, I could have frozen that object and then hope that that modification would have thrown an exception, but you know, you can't always easily catch exceptions. Sometimes bits of code are just wrapped in try catch, which silence exceptions, or it might, you know, we also spoke about the fact that in some cases freeze just fails silently. So either way that wasn't such a great option. So with by having a proxy in the actual debugger statement in that proxy, I was actually able to trigger the debug on that modification. Now in DevTools, you can actually trigger breakpoints on attribute modifications of the DOM, but you can't trigger breakpoints on property modifications of JavaScript objects.
AJ_O’NEILL: So wasn't there another name for something really, really similar to proxies before proxies?
DAN_SHAPPIR:I don't know.
AJ_O’NEILL: Okay. I'm trying to remember.
STEVE_EDWARDS: Are you thinking observables?
AJ_O’NEILL: Observables. I think that's the one. No, but that's what we said. Yeah. That's what we said that in JavaScript proxies are a way to implement observables. Now, but that, that was not standardized in the language. Is that what happened?
STEVE_EDWARDS: I think it was, isn't RxJS sort of the dominant way to do observables?
DAN_SHAPPIR: It is, but it's not part of the language. Now there's a-
STEVE_EDWARDS: Right. It's an external tool, library, or you have to implement.
DAN_SHAPPIR: When we spoke about, we recorded recently an episode about JavaScript proposals that are still being evaluated, stage two, stage three. Well, stage three are effectively essentially accepted. But stage two, even stage one, one of the new features that, potential features that we mentioned is building in observables into the language. But currently, it's not part of the standard. And it may very well be that if observables are baked into the language that internally they'll use the same mechanism as proxies. Maybe they'll be built on top of proxies. By the way, I would like to say that for a long time, JavaScript developers avoided proxies, even those that were familiar with the concept, because they could not be shimmed. The functionality that they provide to the language just can't be implemented without them. You know, you can transpile maybe the code by modifying it a lot, kind of like what we do with a sink and a weight, but it's really difficult. So effectively, they can't be shimmed, certainly not by a library. Well, it can with defined property for known properties. Oh, for known properties, but if you want it generically, then it can't. And like I said, it can also do things beyond properties. It can modify the behavior of the in operator, for example. It can't really be shimmed and because of that it was avoided for a long time because you know not all browsers supported it. Now effectively all browsers do support it which is why Vue 3 can you know uses it and if they're not worried about their code breaking on certain browsers. So it's mainstream. Let's put it this way. But it's still fairly uncommon and the only you know the users that I've seen are within frameworks and within libraries where they want to expose some sort of really simple, deceptively simple interface to something that's a lot more complicated on the inside. All right. So hopefully that clarifies what proxies are, AJ. Have you any additional thoughts, comments, or questions about them?
AJ_O’NEILL: No, I think I've got it. And again, I hope that most people never use them. But I do believe that because of the other flaws in the way that primarily the tooling works, it sounds like they can be useful and discreet. I'm a little bit, I like the idea of two-way data binding, which is essentially, I'm guessing, that's what Vue 3 is using it for, right?
STEVE_EDWARDS: Right, yeah, data binding, monitoring the changing, the reactivity so that when something changes underneath and it changes your data, where you want it to be changed.
AJ_O’NEILL: I think that the general concept of hooks as implemented in React Hooks meaning specifically the idea, not that you're hiding away where the thisness is, I think that's bad, but that you're explicitly developing the dependency chain of what things depend on what other things so that you can easily detect cycles and have obviously correct code. I think that that is good. And that's the one thing about using observables indiscriminately, I think is, well, we'll see how it works out if view three has good patterns that help you not get into those situations. But well,
DAN_SHAPPIR: other it's worth noting that other frameworks do use the compiler to do that for you. So it what happens is you modify something that looks like a simple JavaScript variable. But the compiler actually changes that into a function call. So you don't need observables at runtime because the compiler generated different code for runtime. Svelte does something like that. Solid kind of does something like that. So, you know, it feels like, especially in Svelte, you define, you declare a variable using, let's say, let, but it's actually, but that actually is a data bound variable, even though it looks like a simple JavaScript variable.
STEVE_EDWARDS: Alrighty. So with that, we are going to end our geek talk for the day and move to Pics.
Hi, this is Charles Maxwood from Top End Devs. And lately I've been coaching some people on starting some podcasts and in some cases, just taking their career to the next level. You know, whether you're beginner going to intermediate and intermediate going to advanced, whether you're trying to get noticed in the community or go freelance. I've been helping these folks figure out how to get in front of people, how to build relationships and how to build their careers and max out and just go to the next level. So if you're interested in talking to me and having me help you go to the next level, go to topendevs.com slash coaching. I will give you a one hour free session where we can figure out what you're trying to do, where you're trying to go and figure out what the next steps are. And then from there we can figure out. how to get you to the place you want to go. So once again, that's topendevs.com slash coaching.
STEVE_EDWARDS: So for the uninitiated picture, the things we get to talk about that aren't necessarily tech related, but could be tech related depending on the whims of the day. So first today we will go with AJ. What do you got for us, AJ?
AJ_O’NEILL: I don't know, but basically not, not much, but let's see what I can pull out of my hat here.
STEVE_EDWARDS: I have faith.
AJ_O’NEILL: Now. Okay. Now that I have a home, of course. As a proud believer in the constitution of the forefathers of this country, I fly the American flag and there is a company called Valley Forge, which sometimes you can get their stuff on Amazon, but they seem to be the best flag company in terms of creating durable flags. And not only do they have flags for America, but they also do flags for the other nations maybe a bi-cultural family. You could fly two flags and get them from Valley Forge, the flag that represents other countries. Anyway, so we got that. And then, I don't know, it seems, the books, movies, games. Ah, you know what, I could pick Frog Chess. Frog Chess is a really fun game. If you...If you wanted to try it before you buy it, you could probably look up the rules online, but it's, it's simple, like checkers in terms of the movements. All you can do is jump another frog. You can jump exactly one frog. So there's, there's, there's basically two rules. The board is a grid that is, um, I forget what size it is exactly, but let's say it's, uh, maybe seven by seven or six by six or something like that. And then there's the border all the way around it. All of the board gets filled up with frogs. You take turns placing your frogs, so say blue and red or whatever. And then the first person that goes, the rule is that you have to jump over exactly one frog. And if you land on the outermost squares of the grid, then the frog that you used is now out of out of play, it dies as well. So any frog that you jump over, you have to jump to an empty square dies as well as your frog, or any frog that lands outside of the main grid, because there's the main grid and then there's one extra layer on the outside so that you have room for the initial moves. And the objective is simply to be the last player to jump a frog. So it's not about how many frogs you have left. Your last play could be to jump over your own frog, one of your own frogs into the swamp area, the area outside of the grid and lose both of your frogs. And your opponent could have three frogs on the board, but in a place where it's not possible for them to jump one of their own frogs or one of your frogs. And in that case, you win. So it's not about having frogs left over, it's about being the last frog to jump. And it's the Binary Coco is the company that's invented the game, and they have this nice colorful board that you can get. And I got one of the earlier revisions of the game, and now it comes in a little bit of a nicer box, and they have a little bit better colors and whatnot. But I'll put the link in there. And it's something, you know, you could play it with checkers. You could set up a chess board with checkers, and you could play this game to try it out. But, you know, kids love the little or frog characters and that sort of thing.
DAN_SHAPPIR: I have to say that in terms of the gameplay that you're describing, it sounds really similar to some really ancient games. It sounds like a game that I read somewhere that ancient Egyptians played, like 4,000 years ago, something like that. This concept of being the last one to jump over some other piece or something like that.
STEVE_EDWARDS: Well, you know, what it reminds me of is that little triangle game with the pegs, you know, where you start out and you've got...one hole and the ideas that you only have one piece left. I think I've done that once in my lifetime too, and I didn't write down my pattern. But anyway, that's what it reminds me of.
AJ_O’NEILL: I think the best I've ever gotten on that is two. I may have gotten one once, but that's a tough one when I go to Cracker Barrel.
STEVE_EDWARDS: Right, exactly. That's where I thought last. Yeah.
AJ_O’NEILL: One last thing. So Binary Coco, the funny thing about them is that they actually were doing video games first when I met them. And they do have a few video games, but they actually have. I think they've had more success with physical games than video games. Straight for is another one of their games that I like. It's kind of like tic tac toe. But again, in the same way that frog chess is like checkers, it has this elevated cerebral, solid cerebralality to it that makes it feel more strategic like chess. Straight for kind of takes the the tic-tac-toe approach and raises it up by another dimension where it's still very simple to learn and play but very difficult to master. It looks like they've got a whole bunch of new physical games that I had not heard of. I'll have to check out one that I know that they've been working on for a long time was cubes with different triangles on it and that affects how they can move and how they can turn and whatnot. But again, all of their all of the games of theirs that I've played, except for maybe the card games, Wet Blanket and Slamarama, I think they're a little bit more just fun, silly, like other ones you would have experienced the what's the one about the exploding kittens or something like that. But they're they're tabletop games that I've played that have a border or moving pieces all seem to be in this realm of very, very simple concepts, easy to learn, very difficult to master and get great at.
STEVE_EDWARDS: All righty, well thank you for those picks that you pulled out of thin air. You did a good job with that, AJ. I just know they're always buried deep in your brain. You just gotta find them. Dan, you got any picks for us?
DAN_SHAPPIR: Yes, so my first pick is that for the first time in a long time, like over two and a half years, I'll be speaking at an international conference overseas. During this whole COVID thing, I've hardly done any conferences, and what conferences I did do were either virtual or local here in Israel. There was one actual physical conference that was here that I participated in, but that was the extent of it. So I'm really happy that things are opening up, and I'll be flying to Budapest in the beginning of June. The conference is JSConf EU will be taking place in Budapest in Hungary. And I'll be talking about surprise, surprise web performance. And that would certainly be a lot of fun because, uh, my wife will also be joining me and we'll actually be taking advantage of, of that to do a bit of touring in Europe right after the conference. So we'll be rent, taking a rented car and just, you know, driving through some European countries and it should be awesome. And I'm again, really, really happy about being able to take a vacation like that after such a long time. So that would be my first pick. My second pick, the stock market seems to be actually going up today. But overall, it's something like down 15% this month of the time of this recording. And I know and I'm seeing on Twitter, for example, that a lot of people are kind of freaking out. Because the last time we had any sort of a crisis in the stock market, especially associated with tech, was like way back in 2008 and before that, 2000, 2001. So a lot of people are just not used to this situation of tech stocks continuously going down instead of going up. And it seems like the end of the world for some. And you know, I've been there doing the previous quote unquote crashes. And I can tell you it comes and then it goes. And tech is here to stay. So it might be the job market might be more challenging for a bit. It might be more difficult to find great salary, but do you know, a year or two, three down the line things should be back to normal, at least I hope, unless we get into some sort of nuclear war over Ukraine or something like that, in which case it really will be the end of the world. And again, that brings me to my final pick, which is the thing that I pick on every episode these days, which is the war in Ukraine, which just keeps on dragging on and on. And it's so terrible and so horrible. And I just wish that it will end already. But unfortunately, I'm not seeing it ending anytime soon. So those would be my picks for today.
STEVE_EDWARDS: Excellent. Excellent indeed. Well, maybe not excellent. Good. Just kidding, Dan. So now to the high point of the show, the dad jokes of the week. I can already see AJ cringing. So these ones might really tick you off, but wait and reserve judgment until you hear them. So what do a tick and the Eiffel Tower have in common? Anybody?
DAN_SHAPPIR: I don't know. What do a tick and the Eiffel Tower have in common?
STEVE_EDWARDS: They are both parasites. Bum, bum. Okay. So what do you call a depressed tick who lives in Rome?
DAN_SHAPPIR: I don't know.
STEVE_EDWARDS: He is a hopeless Roman tick. Romantic, romantic.
AJ_O’NEILL: No, you didn't have to do it. You didn't.
STEVE_EDWARDS: Oh, OK. Just let it go? OK, got it.
AJ_O’NEILL: That one was good. That one was good.
STEVE_EDWARDS: OK. OK. And then finally, what do you call a tick on the moon?
DAN_SHAPPIR: A lunar tick. Yes.
STEVE_EDWARDS: Thank you. It's lunar tick. But yeah, that's very, very good. That one seems to be easy. Other people have gotten that one too. So that was great. And then last night, my neighbor knocked on my door at 2.30 AM middle of the night, he's knocking on my door at 2 30 a.m. But lucky for him, I was still awake playing my drums.
DAN_SHAPPIR: Uh, yeah.
AJ_O’NEILL: Ah, that was good.
DAN_SHAPPIR: Kind of rude though. His behavior, I would say,
STEVE_EDWARDS: no kidding, man. He's interrupting my drum playing. Anyway, that is all that we have for the week. Thank you for joining us on this deep dive into JavaScript. We will talk to you next week on JavaScript Jabber.
DAN_SHAPPIR: Yeah, who would have thought that they've dived into JavaScript on a JavaScript podcast. Happy to oblige. Crazy we are. Crazy we are.
AJ_O’NEILL: We're the radicals. Yeah. For the square pegs in the round holes.
STEVE_EDWARDS: Okay, that's it. Talk to you later.
DAN_SHAPPIR: Bye.
Bandwidth for this segment is provided by Cashfly, the world's fastest CDN. Deliver your content fast with Cashfly. Visit c-a-c-h-e-f-l-y dot com to learn more.