字幕列表 影片播放 列印英文字幕 - Hi everyone. I am doing something very ill advised, I think, in this video. I'm a completionist, and I'm returning to something. I made a video, apparently, almost, today is February 20th, 2019, and I made this video, February 22nd, 2017, almost to the day two years ago, about prototypes in javascript because, I was on this path, towards explaining a concept known as inheritance and also another concept, known as polymorphism. Now I do have videos about object oriented programming, inheritance and polymorphism, in java with the processing development environment, you could go and watch those, and I also intend, what I really should be doing with my time right now, is making a video about inheritance with ES6 classes in javascript. And that's coming, and that's the video you should go and watch. But I just can't let this go. At the very end of this video, I said, and then I'll make a follow up one about inheritance using prototypes in javascript and I never did. And perhaps, perhaps there's a kernel of value here, in that, ES6 classes is really just what's refferred to as, like, syntaxic sugar, I do have a sweet tooth, over truly everything javascript is still a prototype based object language. So understanding how these prototypes work, and how this concept of inheritance applies to them. Is perhaps useful, so if you're still with me, I'm going to try to explore inheritance with prototypes in javascript as a follow-up to this video 9.19 from two years ago. So if you watched, maybe you literally just watched that video, and somehow ended up here which would be kind of amazing. If you did you might have seen that I had this diagram. And the idea of this diagram, was I was trying to explain that I want to, I'm programming a particle system, and there's going to be particles moving around my canvas. And I have multiple particle objects. Each of those particle objects, has it's own x/y position. p1, has an x/y, p2 has an x/y. But the functionality is tied to partice.prototype. So I've added a show function that draws the particle, as part of the prototype, and there is this idea of a prototype chain, meaning that everything descends from object.prototype. So if we call a function or look at a property of an object, we first see if it's that object's own property, or is it somewhere up the prototype chain. So, what would it mean, now, if what I want to do, is create a new kind of object, I think in my nature of code book, I call it confetti, which is kind of like a random, weird thing. But, just use that that for this, cause I can't think of anything else right now. If I were to create an object, something called confetti, and a new prototype, a class, again ES6 class, the way I do this now is with ES6 classes, I don't do this anymore, but I'm just exploring cause, I can't help myself. Contfetti.prototype. What I want is, I want confetti.prototype to inherit everything from particle.prototype, but maybe have it's own additional function. I don't know like maybe it has a function called burst. So it gets show, somehow it's going to get show, I don't have to rewrite the show function, it's a special kind of particle, that somehow inherits that. So let's see how would we do that. Alright so, let's go to the code. The idea here is, okay, I am going to write a new class called confetti, but it's not a class, this is an old, old way of doing stuff with this idea of a constructor function. Cause the idea here is I want to say now, I'm going to have, and look I was even using var, so I'll keep using var, cause I'm living in the past today, c, and c is a new confetti. I want to be able to say it like c.show, for example. I want to be able to call that function. So right now, if I were to run this code I have, this loaded here, c.show is not a function. Okay. So how do I have confetti inherit everything from particle? The first thing that I'm going to do is, in the constructor function, I'm going to say, particle.call(this), oh this is so weird but, (sounds of disgust) I don't like this at all. But what this is doing, is it's basically saying execute the constructor function of particle. Just do what I do when I am a particle. So let's take a look, let's not do c.show, but let's console.log(p) and console.log(c). So we're going to look at the particle object, and the confetti object now. Hit refresh. So look at this, both particle and confetti, both have an x and a y at 99. You can see they have those properties, they both descend from object, and if we go into here, we see that particle has it's own show function, and then it gets a whole bunch of other things from object. But confetti, it doesn't have the show function, it just has all the things from object. Okay, so how, how, how, how, how, how, do I link the two? So one way to link the two would be to say, you know what, confetti.prototype should be the same as particle's prototype. So I want to set the confetti's prototype to particle's prototype. Now this is not a good idea, I don't think, but let's just, for the sake of argument, put that in our code. And let me refresh this. We can see okay. Oh look! The show function showed up there fascinating, amazing. Well maybe we're done. We inherited the show function. While this looks right, I have now have a confetti object that inherits show from particle because, I've tied the prototypes together, this is actually a terrible idea. So I'm going to show you in a minute why this is a terrible idea. But let's leave it this way, just for a little bit longer. Why, am I doing this in the first place? The idea is that, the idea here is that this particle prototype, this particle object, if you're looking at some of my other examples, has a lot of stuff to it, maybe it has this whole set of physics algorithms built into it. And I want to just create a new kind of object that includes all of that physics stuff, but I can just draw it in a different way. So, let's just try to simulate that for a little bit. By what I'm going to do is, I'm going to add now another function to particle, called update, and what I'm going to do in that function is I'm going to say is this.x plus equal, and I'm using p5 so I can use random, and I'm going to just move the x and they y around randomly. So imagine this is, like, a really elaborate physics simulation, that I've worked out for how this particle should move, really I'm just moving it randomly. So now what I want to do is, I'm going to now add the draw function. The draw function will loop, and I can say p.update, p.show, c.update, c.show. And what I'll have now, I'm going to say background(0). I'm going to just make sure I can really see this by saying stroke(255) and strokeweight(8). So I should see, if I go back to here, two little dots, dancing around. One is the particle object, one is the confetti object. The wonderful thing here, is my confetti object, which sorry, I'm going to now, which is now c. So, I have c, a confetti object, I have p, particle object, this, links to confetti.prototype, but confetti.prototype, and particle.prototype, right now, are equal. They're the same thing. So it's actually as if this is linking directly to particle.prototype, so the show function it's getting, is right here and there's also now an update function. So my confetti object, has both an update and a show function, it's own x and y, the particle has it's own x and y, and an update and a show function. So what I want to do is I want my confetti object, to inherit this update function, but I want it to have it's own show function, I want it to have it's own show function I want it to draw itself in a different way, maybe a square or with some color, or something like that. So let's go back here. And what I'm going to do say like, okay, no problem. What I want to do now is say that, confetti.prototype .show equals function. And I'm going to just do something totally different. I'm going to give it I'm going to say stroke(255,0,255), I'm going to say nofill, and I'm going to draw this as a square, with a sidelength of 50, and I'm going to hit enter. And, (scoff) what's going on? Why, why, why, why, isn't the confetti calling it's show function? The reason why it's not, well, okay, well maybe I need to do this after I do this. Confetti.prototype equals particle.prototype? (yelp) Wait now they're both showing my confetti. They're both, I want them to do the same update function, but I want them to do different show functions. So why is that not working? It's because, I can't actually, they way the prototypical inheritance chain thing works, is I can't set confetti.prototype equal to this, I've basically overwritten it. So, its as if, there aren't two separate ones, I want to base this on that, not overwrite it. And the way to do that, it kind of ridiculous, and this is why the ES6 classes methodology, that you should just turn this video off and and go use instead. Is I have to say, right here object .create particle.prototype, it's basically making a new prototype, based on the particle's prototype but I can modify it. So once I've done that, and I hit enter, now you can see I have both of them are using the same update function, but one has it's own show function. And let me show you we're going to see this on the console in a way that, hopefully, will bring this all together in a way that makes sense. So look at this, they each have their own x/y, that's good because, that x/y property is added in the constructor function, which both the particle constructor function, and the confetti constructor function call. The particle object has a show and an update function as part of itself. But look at this, now the confetti object has it's own show function, but, oops, sorry but it's update function is down here cause, it points to the particle. So this is the chain. Particle is kind of has it's own show and update, confetti has an x/y, it's own show but it also has a show and update which it copied from particle. Now the reason why it doesn't call this one is that it always looks for the first instance of something of that prototype chain. So this is wildly confusing and convoluted. Hopefully this gives you a little background in sense, of how this works. There's one other missing piece of this, I believe, which relates to this here. The confetti object doesn't actually have it's own constructor, really it should. So, for example, if I wanted to do something like, I'm just going to add right here, like, I want to do something else, like console.log(hello this is confetti), like, in addition to initializing this object the way a particle does, I want to do something else. Actually maybe, what I want to do is give it a color. This.color equals a new color that is pink. And then actually, what I'm doing, is I'm calling that, under stroke. I'm referencing the confetti has a color, the particle gets an x/y, the confetti gets an x/y and a color. Let's see what happens here. Oh, weirdly that worked. (laughter) Interestingly enough, this worked anyway. I thought I needed this other step in order for it to call the confetti constructor properly. Here if I'm saying, new particle versus new confetti. Looks like it works anyway, but I'm going to show you what this step is. Really one thing that's kind of missing here, is that in if I look in the prototype here, the particle's constructor is pointed to this particle function. And if I go here into the confetti, you can see like, oh there is no constructor, it's getting it from the prototype chain, which is incorrect. The confetti object should have it's own constructor. And so a way to do that is to say, I think it's to say. Actually I have this line of code here, from my example, I'm just going to copy it in. Is to say this, confetti.protoype constructor equals the confetti function. Right I want to like specifically assign it that. And it seems to me that this is just a convention to kind of clean things up, I can't actually find a place where I need that in order for my code to run correctly, but I'm going to leave it in there. And so now I'm going to hit refresh, and we can see here that a confetti object inherits everything from particle, including it gets it's own x and y, and it gets a show function, sorry, sorry, and it gets a show and update function. It has it's own constructor and it's own show function, because, I wanted to modify the confetti show function, from the particle show function. Don't worry, if none of this made any sense to you, that's okay. This is confusing and weird, but this is underneath the hood how all of this stuff is linked together in implementation of the javascript programming language itself. This is the prototype inheritance chain. I can basically create a new object, with it's own function calling the other object's constructor function, and then attaching it's prototype to a new object based on another object's prototype. It's really weird, and kind awful. But this is how I used to make my examples, but don't worry. (heavenly choir) There's a new way I make these examples. You don't have to worry about this anymore. You can skip to, I haven't made it yet, but soon enough, within the next week or two, I will be uploading and publishing a video all about inheritance in javascript, using ES6 classes. And in those videos, I'll really talk about the theory behind inheritance, why it's useful and how to put it into practice in javascript. So if you actually made it through watching this video, thank you. Hopefully this helped add a little something to you day. And I'll see you, maybe in the ES6 classes videos. Thanks goodbye. (ding) (upbeat music)
B1 中級 9.20: 看開點!JavaScript中的原型繼承 - p5.js教程 (9.20: Look away! Inheritance with Prototype in JavaScript - p5.js Tutorial) 4 0 林宜悉 發佈於 2021 年 01 月 14 日 更多分享 分享 收藏 回報 影片單字