字幕列表 影片播放 列印英文字幕 Souders: All right, welcome, everyone. It's great to see a big crowd here. My name's Steve Souders. I work here at Google on latency. And I wanted to do a couple plugs for these talks. I'm trying to see about starting up a series of tech speakers coming in. So a couple weeks ago we had John Resig come in and you can see that talk up on the Google developer channel up on Google code. And next Thursday at 11:00 A.M. right here is Rob Campbell who works at Mozilla and he's one of the people leading the Firebug effort. And he's gonna do a talk next Thursday at 11:00 right here on Firebug and the new releases that are coming out and some of the new features. And-- But today-- So today we have Doug Crockford. Um, I worked with Doug at Yahoo. That's where I met him. And I remember the first time I met him and he told me his name, I said, "I know that name somewhere. I know that name somewhere. Oh, yeah, I've been using the stuff on your website a lot." And so I was really excited to meet him. And he's a really nice guy. I enjoyed working with him at Yahoo. Um, I-- I, uh, have a little bit of hesitation because when my book came out, it did pretty well. And then Doug's book came out and just kicked my book's butt. And so I just checked. And I'm, like, at 6,000 and you're at, like, 4,000 on Amazon sales rank, Doug. So that's really good. And I believe that this talk is largely based on his book, "JavaScript: The Good Parts." And so we'll run for about an hour and have time for Q and A. So without any further ado, please help me welcome Doug Crockford. [applause] I forgot. Here's your Google tech talk goodie bag. Crockford: This is what makes it all worthwhile, right here. [laughter] So, thank you, everybody. I'm Doug Crockford from the Yahoo. And I'm here today to talk about the good parts. Now when I first started talking about JavaScript, there were a lot of people who just could not accept the fact that JavaScript has good parts. But, in fact, it does. But it's not well understood. Even now. JavaScript has become probably the most important programming language in the world. There's more JavaScript processors on more computers than anything else by a very large factor. But despite that, JavaScript is not held in very good esteem, even within its own programming community. For example, the C# community loves Anders. And the Java community loves Gosling. And the PHP community loves Rasmus. But in the JavaScript community, there is no love. And there should be. And I think it indicates a lack of understanding. That's why JavaScript is still the world's most misunderstood programming language. It's the only language that I'm aware of that people feel that they don't need to learn it before they start using it. [laughter] It kinda looks familiar and yeah, yeah, yeah, yeah. I've seen this before. I know how this works. In fact, it works in a really radically different way. It just looks very similar. And then when people misuse it as inevitably they do because they don't know how it works, they get angry at it, and misunderstand it. Which is a shame because there's actually good stuff in this language. And because it's everywhere, JavaScript is now becoming the virtual machine for the world, which is a really odd mission for this little misunderstood language. You know, you're doing it here at Google with the GUID. And there are lots of other examples of the same kinda crazy thing. You know, it amazes me the lengths that people will go to to avoid having to learn JavaScript. But it's learnable and you can actually write good programs in it. And like everything else, knowing what you're doing, you know, makes a difference. And so I'm here to enlighten the world about JavaScript. JavaScript is a language of many contrasts. It contains some of the best ideas ever put into a programming language. And it contains some of the worst ideas ever put into a programming language. And a lot in between. There's no other language which has this amazing range of the ridiculous and the sublime. Um, if you look at the community of people who use JavaScript, it has the broadest range of programmer skills of any programming language. We've got people at the very high-end doing computer science in this language, which it does really well 'cause it's basically a scheme with C syntax. And we've got cut-n-pasters who don't even know that they're programming, who are putting stuff together and making it happen. If you gave those kids Java compilers, they would never get "Hello World" running, but they can work with JavaScript. So the language has amazing expressive power and it supports everybody in between. I contend there is no other programming language that can support this really broad audience of users. And I'll offer that as further evidence that this language is getting something right. Which again, may be surprising to the people who think this language didn't get anything right. One of the reasons people think that is that they have a lot of complaints about it. And I think these complaints are all valid and I'd like to go through them one at a time. The first one is that JavaScript is not a language I know. If you're programming in any environment-- the desktop or embedded systems or the server-- generally, you get to pick what language you're going to use. But if you're writing in the browser or if you're writing in one of the applications that has embedded JavaScript in it, you don't get a choice. You have to use JavaScript. And a lot of people get resentful about that. You know, "Why should I have to learn this stupid language? "I already know lots of other good languages. Why can't I use one of those?" You can't. Um, and so they... try to write without learning the language, which I think is really a bad thing to do. My advice is man up and learn the language. If you need to be writing in JavaScript, there's nothing like knowing what you're doing. Second complaint. The browser programming experience is awful, which is absolutely true. But that's not JavaScript's fault. I contend it's the DOM's fault. The DOM is one of the worst APIs ever imagined and that's what you have to use when you're using the browser. Fortunately, there are a lot of Ajax libraries available now which all do an amazing job at correcting the DOM model and turning it into something that you can actually write good applications in. So, uh, there is a solution to that. I'm hoping eventually we can push that solution back into the browser. But for now, the Ajax libraries work really well. YEY, I'll mention that one. Comes out of Yahoo. It's actually very, very good. I think maybe the best of them. There are lots of others that are also very good. There's a complaint that it's not fast enough. And in the browser, that's mainly because of the DOM again. If you look at the fraction of time that your program spends running, a tiny fraction of that is actually running in the JavaScript interpreter. Most of the rest of it is wasting time in the DOM interface. So if you could somehow make your programs go infinitely fast, most web applications are gonna look about the same. There are other applications for which having a faster language would actually be a benefit. And so I'm happy to see that mainly, I think, because of leadership from Google, we're now starting to see higher performance JavaScript entrants, which I think is really, really cool and very much to be encouraged. Although, practically, I don't think it's gonna make much difference to web applications for a long time. Then finally, there's a complaint that the language is just a big pile of mistakes. And I contend, no, it's not just a big pile of mistakes. [laughter] That hidden under a huge steaming pile of good intentions and blunders, there is an elegant, expressive programming language because JavaScript has good parts. And if you can recognize those parts and use those parts exclusively and avoid the bad parts, you can actually write good programs in this language. And I'll offer again, as evidence of that, that JavaScript is succeeding very well in an environment where Java was a total failure. I don't know if anyone here remember Java applets. How they're gonna change the world? Didn't happen. Crap. Java turned out to be an okay language and found a niche in the server where it's doing pretty well. But it was absolutely awful as a client programming language. JavaScript is doing really, really well there. The influences on JavaScript were Self, from which it borrows prototypal inheritance of dynamic objects. Dynamic objects are a really clever thing and they worked really well in this language. From Scheme, it gets lambda, which is maybe the best idea in the history of programming languages and loose typing, which is pretty controversial. The style of most languages today calls for strict typing. The theory being that strict typing allows for the compiler to check a large class of errors at compilation time avoiding-- Catching any error early reduces the cost of the errors. So that's a good thing. And JavaScript doesn't have that. So in JavaScript, any variable or any parameter can contain a value of any type. And that's really frightening to someone who's coming from a strongly-typed tradition. Like, "How can I have any confidence that anything's gonna work right?" It turns out that strong-typing doesn't absolve you of the need to test. You still have to test everything, 'cause there's an even larger class of mistakes that type checking doesn't find for you. And I found in my own practice that the amount of testing that I have to do, writing in Java or writing in JavaScript, is about the same. That those type errors get found really quickly anyway, so they're not really a problem. The areas that are a problem, the ones that keep me up at night, um, type safety wouldn't have helped me there. The benefit of having loose typing is you don't have to mess with the type system. And so that turns out to be liberating. Your programs tend to be a lot smaller and a lot simpler. So which one do you like? Well, it doesn't matter. If you're working in JavaScript, it's gonna be loosely typed and that's just the way it works. From Java we get syntax, which is a source of a lot of problems because it's basically the C family of syntax, which we've all learned to deal with. We've gotten so good at it that we don't even recognize anymore how defective it is. But because JavaScript is used by beginners, those problems are intensified. And then finally, from Perle, JavaScript gets a really horrendous regular expression notation. So before we get to the good parts, let me tantalize you with some of the bad parts. The worst part by far, global variables. JavaScript doesn't have a linker. So the way compilation units get bound together is they all get tossed in a common global namespace where all the variable names can collide and interfere with each other. It has terrible reliability problems. It has even worse security problems. You've all heard of cross-site scripting attacks. Those attacks are fundamentally enabled by JavaScript's use of global variables. JavaScript uses + to both add and concatenate. It got that little bit of overloading from Java. In Java, it wasn't too bad because it's strongly typed and so you could predict which one it's going to do. In JavaScript you can't. So this is a very common source of errors. Semicolon insertion was something intended to make the C syntax easier for beginners. C syntax, the rules for where a semicolon goes are kind of complicated. You really have to understand the syntax of the whole language in order to understand where to put them. So to make it easier for them, JavaScript says, "We'll put them in for you so you don't have to use them." The way it did that was when the compiler gets an error, it backs up, looks around for a line feed, turns it into a semicolon, and then tries again. That should freak you out. [laughter] It sometimes puts them in the wrong place. Sometimes doesn't put them in places where you'd expect. My advice? Figure out where the semicolons go. Put 'em in the right place. You'll be much better off. JavaScript has a typeof operator which allows you to determine if the typeof a value is a string or a number or something like that, which is really good. If you ask it what the typeof an object is, it says it's an object. Great. If you ask what the typeof an array is, it says it's an object, which isn't very helpful. If you ask what the typeof null is, it says it's an object, which is wrong. It has a with statement, which was well-intentioned but doesn't work right. I highly recommend you avoid it. Simply by being in the language, it causes programs to be a lot slower than necessary whether you use it or not. And similarly, eval is the most mis-- most misused feature in the language. If you ever find yourself needing to use eval, you're probably thinking about things in a really wrong way. So step away from the computer, read my book, and then take another run at it. [laughter] JavaScript has phony arrays. In most languages, you've got an array, which is a linear sequence of memory, which is divided into regularly spaced buckets, so you can do address computation and very quickly get to an element. JavaScript doesn't have anything like that. In JavaScript, arrays are essentially hash tables, in which the keys are turned into strings and then hashed to locate the buckets. This has a terrible performance penalty. But it has an advantage in that it makes the programming model quite a bit easier, 'cause you don't ever have to dimension an array. Dimensions don't exist in this language. It has a equality operator that does type coercion, which turns out to be problematic. I'll show you an example in a moment. And it has too many bottom values, which is a problem because beginners tend to get confused by having all these things which almost mean the same thing but are slightly different in their meaning. So these are some of the consequences of type coercion on the quality operator. There are rules that govern this. This isn't random behavior. But it's certainly surprising behavior. And the rules are not memorable, so this all looks very mysterious. Fortunately, the language has a triple equal operator, which does not do type coercion, so it would answer false to all these cases, which is the right thing. So I highly recommend-- Always use a triple equal operator. Never use the double equal operator. Just don't use it. So one of the nice things about the dynamic objects in this language-- If you ask an object for a property that it doesn't have, you don't get an error, it doesn't throw. It just returns to the undefined value, which is really nice. So you can, you know-- Reflection is just automatic on things like that. So if you then ask if the thing is undefined, then you can do something about it. But because a lot of beginners don't understand the difference between null and undefined, they use null and they use the wrong comparison operator, which often works. It's the case of two errors that cancel each other out. That's not a good way to write programs. So the right way to write this program would be to use the proper equality operator on the proper value and now it'll work for all cases. Here's another case where good features interact badly in this language and I'll give you an example. Objects can inherit from other objects, which is good. One of the interesting things about this language is you don't have classes inheriting from classes. Objects inherit directly from other objects, which is really powerful, it turns out. Objects can be members-- Functions can be members of objects, which is good. That's how methods are created in this language. And we have a for..in statement that mixes inherited functions with the desired data members, which is not useful at all and is a common source of errors. So how did that happen? There was a design question in the making of the language. Should the for...in statement, which iterates through all of the members of an object, do a shallow skim of the object's own properties, or should it do a deep dredge going through its inheritance chain? The decision was to do the deep dredge. And I think the thinking was that if we do the shallow one and what people really want is the deep one, we're screwed. They just can't get at that stuff. Whereas if we do the deep one and what they wanted was the shallow one, they can do the filtering themselves. Except that they didn't tell anybody that that's why they did it and that's how it works. And so as a consequence, there's a lotta confusion about how to use for...in and how to attach methods to prototypes. I think a better decision would have been to not release the language until they had enough experience with the language to know what the right answer was. But to put it into historical context, at Netscape, getting it right was not an option. Which is why there's no longer Netscape. Um, yes? man: Isn't the real issue that people are using objects as hash tables and they really aren't hash tables because when you said they were, like, two strings who get things you don't expect? Crockford: Um, no, but we can get to that in the Q and A. Um, so these are things which are wrong with JavaScript, which are really wrong going all the way back to B actually. But I'll talk about them here 'cause we're talking about JavaScript. We have the option of using blockless statements, which is a bad practice. It creates code which is more likely to get damaged under maintenance. So I recommend always putting the curly braces in. It allows for expression statements in which it can just have the name of a variable or a simple expression and do nothing. I think the reason for that was it made the specification of the syntax a tiny bit easier. They were able to save a production or two. But as we're gonna see, it just messes things up. The most often reported error in the language is that 0.1 + 0.2 !== 0.3. And this is not really a problem with JavaScript. It's a problem with IEEE floating point. That floating point is the only number type in the language. Having just one number type in the language turns out to be really nice, particularly for a language that beginners use, because there's a whole lot of compatibility problems that just go away. Everything is the same type. But unfortunately, they picked the wrong type. That you tend to do a lot of computations involving money in this language and the sums come out wrong. And generally when you're adding people's money, people have an expectation that the results gotta be right. And it's hard to do in this language. Unnecessarily hard. It has the increment and decrement operators, which are very convenient but have been implicated in buffer overruns and other security hazards. I found in my own practice that when I use them, I would tend to write code which was too tricky. And code which is too tricky is too often wrong. So in my own practice, I don't use them anymore at all, ever. Just part of my discipline. Finally, it has the switch statement. The switch statement was modeled after the FORTRAN computed goto. It has the property that one case can fall through into the next case. I'm gonna tell you later about a program I wrote called JSLint which is a quality-- code quality tool for JavaScript. One day someone wrote to me and said, "You know, the language has switch statements "and sometimes you can have one case fall through "into another case and it's really difficult to see that "when reading the code, you know? "So could you have JSLint generate a warning anytime that happened?" And I thought about it deeply and I wrote back to him and I said, "Well, there are cases "where it's actually beneficial to have that falling through." And you could have a code indicating, you know, whether you intended that or not but, you know, that doesn't really work. You know, so on balance, I think maybe it's better just to leave it alone. That it's actually a good thing to have in the language. Next day, the same guy sent me a bug report that I had something that JSLint was misclassifying. So I threw it in the debugger and it turned out I had a switch statement that was falling through. [laughter] So in that moment, I achieved enlightenment. There are these moments in your programming career where you actually learn something. Learning turns out to be really hard. And in this case, I actually learned my lesson. And so I now never intentionally fall through in a switch statement. And because of that I can now much more easily detect when I accidentally fall through in a switch statement. So as a consequence, I think my use of that statement has improved significantly. So you've been waiting for the good parts. Here they are. It's a short list but it's a good list. At the top of the list is Lambda. This came out of Scheme, which came out of Carl Hewitt's work on the Actor model. I think this is the best thing ever to go into a programming language. It's powerful, it's safe, it's smart, it's good, it's flexible. Great stuff. JavaScript has dynamic objects, which means you can take any object and at any time, you can add a new property to it or remove a property from it. You don't have to go to some class and make another derived class in order to have an object which is slightly different than the one you've got. That turns out to be amazingly powerful. Makes this language especially easy to use. It's got the loose typing in it, which some people look at as a severe disadvantage. I think it's actually an advantage. This language is better off, I think, for having loose typing. And it has object literals. Object literals are a very nice notation for describing objects. JavaScript's object literals were the inspiration for the JSON data interchange format. Um, there-- Inheritance is object-oriented code reuse. And there are two schools of thought for how to do that. There's the classical school, which is represented by almost all present-day languages. And there's the prototypal school, which is represented pretty much just by JavaScript. There are no other languages in broad use which have this property. Turns out the prototypal inheritance is amazingly powerful but it's not well understood. It's so powerful that you can program as though it is classical and it mostly works. You can't do the opposite. You can't go to a classical language and program as though it's prototypal. So in prototypal inheritance, it's class-free. There are no classes. Objects inherit directly from other objects. And in this language, an object contains a hidden link to another object from which it inherits stuff in a process called delegation. Sometimes called differential inheritance. So each object contains only what makes it different from the object it inherits from, and that allows for objects to be much smaller. For a long time, the language was ambivalent about its prototypal nature, so never included an operator for actually making new objects which inherit from other objects. We're correcting that oversight in the next edition of the language with object.create, which will make a new object which inherits from an old one. Um, it's not in the current browsers, but it's easily implemented. Until it becomes standard equipment, you can realize it in this way. What JavaScript has instead of this operator currently is a weird trio of constructor functions, prototype members, and a new operator, which were intended to provide a friendly object-- or friendly classical-like notation for dealing with prototypes. But it didn't work. The Java community smelled this immediately and said, "That's alien. That's clearly not something we like." And so what it really did was confuse what the language was actually doing. Uh, so in-- As part of that sugar for trying to look classical, JavaScript has a new operator, which is absolutely required when you're calling a constructor function. If you call a constructor function without the new operator, instead of creating a new object and initializing it, your constructor will clobber the global object, which is a very, very bad thing. There is no compile-time warning and there's no run-time warning for this. So for this reason, I don't use "new" anymore. I think it's just too dangerous. So it's time to look at some code. Here I'm gonna make a simple little function called digit_name, which I'll pass it a number and it will return a string which is the name of the digit. So I've got an array of strings, which I create using an array literal. Very nice. And then the function returns looking up the argument in the array. So everybody understand how this works? All right. Problem with this is names is a global variable. So if there's anything else in my application called names, either it's going to fail or my program's gonna fail or we're both gonna fail, which is really bad. Particularly as pages become really dynamic, I may be linking with libraries I've never seen, will never get a chance to test with. I may be having to run with ads which I will never see, which could interfere with my program. So I want to--I have really good reasons to try to avoid the global variables. And the language gives us a couple of options for doing that. One approach would be I could define the array of names as a private variable of the function. And that works just fine. So we have function scope in this language. We don't have block scope, so you need to understand the difference and do it right. But having that, this will work. So names is no longer a global variable, so I avoid that hazard. The problem with this is that every time this function gets called, we're going to reinitialize the names array. Now in theory, an optimizing compiler could detect this case and factor that out. But today, nobody does that. So I might want to write this function in a different way to avoid that. So one way I could do that would be to put it in a closure. So here I've got a function which is going to return another function and the outer function gets executed immediately. Okay? The inner function has access to the properties of the outer function or to the variables of the outer function. It will continue to enjoy access to them even after the outer function has returned. So this allows me to have-- So when it returns, the function goes into digit_name and that function will have names bound to the original array and will continue to have it for as long as it lives. This is an amazingly powerful thing that this language does very, very nicely. And we can generalize this into a constructor pattern. So if you think of an application or any kind of singleton, we don't have to make a class in this language to make a singleton. We can just make it. And the proper-- The methods that that singleton has, can enjoy private shared access to stuff. We don't have to put it in global variables. So I can-- Again, I've got a function which I'll execute immediately and return an object literal which contains some methods which will do useful stuff. And those methods will have access to the private material that the outer function provides for them. We can take this and turn it into a constructor, which is a very nice way, an alternate way, in this language for making objects. So here's the recipe. Step one, you make an object. And there are four ways we can make an object. We can use an object literal. We could use "new." I don't do that but you might. We could use object.create to beget something from an existing object. Or we could call another of these power constructors, which gives us another inheritance model. Step two, we define some variables and functions. These will become the private members of the object that we're making. Step three, we augment the object with privileged methods. Privileged methods have unique access to the stuff defining step two. Then step four, we return the object. So pretty simple recipe. Let me turn the recipe into a template. So step one, I'm gonna make a new object. I'm gonna put it in a variable called "that." "That" because it's reminiscent of "this." And I can't call it "this" because "this" is a reserved word. Step two, I'll define a variable that will be secret, be private, shared by these guys. Step three, I'll create a privileged method, which is a function which will have access to the state of the outer function. And step four, I return that, and that's it. Really easy way to make objects which can hide their stuff and be private. So the reason this works is because we have closure in this language, which means that a function object contains the function itself, which has a name and parameters and a body and it has a reference to the environment in which it was created or the context. You know, which-- In this case is the stuff that was in the outer function. This is a very good thing. This is one of the best parts of this language. Now concerning style, if you get any two programmers together, they could argue all day about matters of style. Like should the curly brace be on the left or on the right? And they may get really emotional about which way it goes. We feel very strongly about this stuff even though we don't know why. You know, we can agree that whichever we do, we should be consistent. But it's hard to find agreement on should it be on the left or the right. It's sort of like, "What side of the road should we drive on?" There's not a compelling reason for why we should drive on the left or right. As long as we all drive on the same side. If we don't, then bad things will happen. And we have a similar thing here. So if you look at why people get emotional about that stuff, where did the idea of leftness or rightness come from? You know, you could trace it down to where they went to school or what they learned on their first job or are deeply impressed somebody early in their career. They may give you a lot of reasons for why the left side or right side is better than the other. But they don't fundamentally know. They just get really emotional about it. Well, it turns out having them on the right side is the right way and the left side is the wrong way in JavaScript. I can't testify for any other language. But it is absolutely true for this language. And I'll show you an example why. So here we have a return statement which is returning an object literal. We saw an example of that in the earlier construction pattern. The one on the right works right. And the one on the left, "silent error." It doesn't return an object. It returns nothing. It returns undefined, which is deeply surprising and wrong. You don't get a compile time error. You don't get a runtime error. You don't get nothing in the log. This is really bad. So how does this happen? Because the two statements look like they should be equivalent. So let's zoom in on a little bit. Look at what's going on. All right, you remember I told you about semicolon insertion? How we'll sometimes put semicolons where they shouldn't go? This is one of those times, so it puts a semicolon in there. So a return statement with no value after it and no expression after it, will return undefined in most contexts. Occasionally, it'll return these. So but there's a lot of other junk here. That should cause some sort of syntax error or something. Give us some sort of warning. Well, no, because it turns out that curly brace can mean "start an object literal", or it could mean a block. Now it turns out, in this language, we don't have block scope. So having an empty block is not useful. We have one. The syntax prefers a block to a literal in this notation, so that's what we get. Okay, so "ok" doesn't look like a statement. Well, actually it does. It looks like a statement label. Well, "false" doesn't look like any kind of a statement. But, remember, we have those useless expression statements that we inherited from C. So we'll evaluate "false" and go, "Yep, that's false.", and ignore it. But it doesn't have a semicolon after it. Well, that's not a problem, because semicolon insertion comes in, repairs that one. Now we've got an extra semicolon at the bottom there. That should trigger an error. No, 'cause from C we also get the empty statement, which allows you to have as many semicolons as you want. So all these things tend to work together to mask errors. Then, finally, we've got some unreachable code here. But JavaScript doesn't care. So there's nothing in the language, in the grammar, that says there's any problem with unreachable code. So here's a case where bad style produces a very bad result. You've got code which you think means that which means that. That's one of the worst things a language can do to you. Now you might be looking at this and you might be wondering, "How did this ever become a standard?" And you might be wondering, "Why am I betting my career on this piece of crap?" [laughter] Um, getting back to the question about standards, this shouldn't have become a standard. There was nobody paying attention and this stuff went through and JavaScript became the world's biggest programming language completely independent of its merits. Given the process by which all of that happened, we deserve a language which is far, far worse than JavaScript. In fact, given its amazing success despite some of these obvious shortcomings, I think we got lucky. There's actually enough goodness, smartness, built into the language that if you can just avoid the bad parts, the good parts are really good and are worthwhile. So I call that "working with the grain." I spent a lot of time struggling with this language trying to figure out how to make it work right, how to make it do good things. 'Cause all the examples that were published by Netscape at the time and that you could see coming out of Dreamweaver, all told you to do really awful stuff. And it took a long time to figure out what this was about. I remember one day I had an epiphany. "Wait, this is scheme." You know, I-- There was no documentation which said how functions worked and the properties of it. It wasn't accidental. Brendan Eich, the designer of the language, always intended to implement a scheme language. His bosses at Netscape wouldn't let him do a scheme language because it was too weird looking. They told him, "Make it more like Java or Visual Basic or something." So he did this to it. So it's not accidental that the good stuff is in the language. He put it there intentionally. So he very quickly put together a prototype, uh, uh, in an amazingly short time and presented it to management and it seemed to work. And they said, "It seems to work." He said, "Yeah." So they shipped it. [laughter] Then Microsoft observed it and decided to knock it off, and they reverse engineered it to amazing fidelity. They found all the errors that were in that first implementation and copied them exactly. [laughter] And when it went to standardization, all that stuff got locked into the standard. So this bit I showed you before, this amazingly silly bit of silliness, that's not due to errors and implementations. It's required behavior by the standard. In fact, all the browsers implement it exactly that way. So when JavaScript was first introduced late in 1995, it was intentionally mispositioned by Sun and Netscape. They decided they needed to join together against Microsoft. And there was some confusion about why they needed two languages. 'Cause it was clearly that Java was going to be the language that was going to rule in the future. Netscape didn't want to give up on this language, which was called JavaScript at the time. And their alliance almost broke down until Marc Andreessen, perhaps as a joke, suggested that they call it JavaScript and that way Sun wouldn't have to hate it. [man speaking indistinctly] Crockford: I'm sorry? man: It was LiveScript. Crockford: It was LiveScript. Um... So, um, I looked at the first version of the language and like all of you, I said, "Well, this is incompetent crap. I'm not gonna waste any time on this." I had an occasion several years later to take another look. And between that time and the next, some goodness had been added to the language that was missing from the first release. My company was approached by Turner Broadcasting to do a website for children based on Cartoon Network. And we had a chat system that we had that they wanted to adapt to this online children's community. So I went down to Atlanta and learned about the requirements and it was pretty clear our chat system wasn't going to be good enough to do this. And I didn't wanna give the money back because this was, like, the biggest contract in the history of the company, and I really wanted to do this. So I don't know where it came from, but I got this really silly idea. Maybe we could do it in the web browser just as it is? So I wrote up a little prototype and it ran on IE 4, I think, at the time and on Netscape 4. And I sent it to Atlanta and they liked it. You could drag and drop little cartoon guys. They'd never seen anything like that in a browser before. And they liked that it wasn't a big installation. It was just a little thing that ran in their browsers, so it was something they could ask kids to do. So that was really good. So I went to my team. And my team, I had some of the best Java developers in the world. We'd been together for a long time. We had a lot of experience at doing this stuff. And I said, "Okay, this is how we're going to do it. We're gonna write the client in the browser in JavaScript." And they all said, and you may remember, "That's great. What's plan B? [laughter] "In fact, we should start plan B right now because there's no way this is going to work." And I said, "No, we're not gonna do plan B. "We're going to do plan A, and it is going to work. So who wants to do the JavaScript?" And everybody took a step backward. So it was, like, I have to do this or I'm gonna have to give the money back. And I really didn't wanna give the money back. So I had to do JavaScript. And like everybody else, I started doing it without learning it and was hating it the whole time. [mild growl] And it wasn't until I had the scheme epiphany, which came late, that I understood what it was about. And it was like, "Oh, okay. This isn't so bad." There's actually goodness in it and discovering the goodness-- It's like, "There's JSON in it!" JSON came about it from my experience using the language and recognizing, "Hey, this little bit of a language could be used for doing data interchange." And it was great. It was already there. It was free. And it was well done. So JSON, just as a consequence of my recognizing it, has become a world standard. The JSON story-- In 2001, Chip Morningstar and I were at State Software and we had an early AJAX platform. Really amazing stuff. I think it's still better than what's out there today. And we used JSON for the data exchange. And we went to potential customers and we explained how it worked. And they said, "Well, where's the XML?" We said, "Oh, we don't need XML. We're doing this. It's really so much easier and faster." They'd go, "Oh, we just committed to XML. I'm sorry. We can't use it." Or they'd say, "It's not a standard." I'd say, "Well, yeah, it's a standard. It's in JavaScript." "It's not a standard. We can't use it." So I declared it's a standard. So I bought json.org and put it up. One-pager that described it because it's really simple and it's all the description it needed. Few years later, I also wrote an RFC that described it a little bit more formally. And it's become a world standard. Basically, I am a standards body. [laughter] It became a standard just on my say-so. So anyway, getting back to the electric community story. So we-- That JavaScript program, we finished, we shipped it, we got paid. All that stuff is great. Unfortunately, while I was making the money, the other half of the company was spending the money. So by the time it all got done, the board fired the CEO and the COO and made me CEO again and I had about two week's cash. Anyway, when you're going through a bankruptcy, you get a lotta spare time. [laughter] And so I remembered a paper that Vaughan Pratt had written years ago at the first POPL conference about top-down operator precedents. Which was this amazingly clever, elegant, lightweight way of writing parsers. And he used it for putting an ALGOL-like syntax onto Lisp. But it turned out the Lisp community has never wanted syntax. But the JavaScript community likes syntax. And so it occurred to me that I could write a JavaScript parser in the language, and I did. And it turned out really well. And then I had this JavaScript interpreter-- or JavaScript parser, and what do I do with it? So I turned it into a code quality tool for JavaScript called JSLint. And so what JSLint does is it parses your program and analyzes it for the sorts of weaknesses that I've been showing you. Identifies the bad parts. And if you can get it to stop complaining about your program, then your program probably just contains good parts and it's more likely to be a good program. So it imposes a programming discipline that makes me much more confident in being in this very dynamic, very loosely typed environment. The sort of confidence that strict typing gives you, JSLint gives me in this silly little language. And it's free. If you're writing in JavaScript, you need to be using JSLint. So go on the web and get it. If you're evaluating other people's JavaScript, it's good at that too. So, say if you're comparing AJAX libraries, you don't know which one to use. Run it through JSLint. See which one is coded well. It'll tell you very clearly. One bit of warning. JSLint will hurt your feelings. [laughter] It'll hurt them really bad. It stings. From time to time, people write to me and say, "Hey, here's another thing you could test." And if it makes sense, I'll put it in and then I'll run all of my old programs against it. Then you realize, "Well, I really suck." You know, even though I wrote it, even though I know what all the rules are, it still hurts when I run into this stuff. And so I can imagine your pain when you go through this stuff. I do feel it. Despite that, I recommend do everything it says, because it's right. And even though you've been programming and you've got a good career and you really know what you're doing, it's smarter about JavaScript than you are. It's certainly smarter than I am. I highly recommend you use JSLint. One of the things that makes it hurt is that unlearning is really hard. I get letters from people all the time saying, "JSLint said my shit stinks. What's up with that?" And they always use the words "perfectly fine." "I did this thing and it was perfectly fine." Well, I think "perfectly fine" is double equal to "faulty." [laughter] And there arguing with me. "Why should I have to fix that?" I don't care if you fix it. It's not, you know-- Nothing to do with me. You're not even paying me for this. I'm just putting it out there free. If you want your programs to be good, make 'em good. But, you know, we get really invested in this stuff. And ultimately it's because unlearning this stuff-- When you learn something wrong it's really hard to get it right. In JavaScript, if you're a professional programmer, you're coming to the language with baggage from other languages. And because it looks like Java but works completely different than Java, it's really easy to get stuff wrong unless you're paying attention to what you're doing. Or if you're a beginner, you probably started by reading view-source on crap that ultimately traces all the way back to Dreamweaver. And it's awful and that's the way people learn. And once that stuff gets in your head, it's really hard to get it out, but you need to do it. Josh Billings said, "It's not ignorance "does so much damage; it's knowin' so derned much that ain't so." And ain't that the truth? So maybe the best part about this language is its stability. There have been no new design errors since 1999. [laughter] And this is a consequence of-- That's the last time the language spec was revised was in 1999. But I think it's a good idea to, every ten years or so, revisit the specifications. So we're about to lose this best part. We're about to come out with a new edition which is codenamed ES3.1, which will probably be labeled Fourth Edition. There's a weird story you might ask me about later for why it's called and not JavaScript. This new edition will contain a lot of corrections. Both corrections to the specification and some corrections to the language. It turns out there are cases where, um, all the browser makers did something different than the standard and they all got it right. So we're recognizing that and making the standard better. There are also places where we saw three out of four of the browser makers were doing one thing and Microsoft was doing another. We're fixing that now too. The next version of JScript coming out of Microsoft will be in much closer alliance to the common language than everybody else. So one of the key benefits from this language is that cross-browser compatibility will be significantly improved. Now it turns out JavaScript is already, I think, one of the best languages in the world in terms of compatibility with multiple implementations. You know, two JavaScript engines are much more likely to be compatible at a really deep level than, say, two C engines. JavaScript gets knocked pretty hard about cross-browser compatibility. But most of those problems are due to the DOM. The language itself tends to be pretty good. It's gonna get even better. We're providing support for object hardening. So objects right now are maybe too dynamic, where everything in them is completely malleable all the time. So we can now make objects immutable, where you can lock down individual properties or lock the whole object down. This will be particularly good as we start looking someday towards secure mashups, where you can have a hardened object which you can give to other code and know that it cannot be compromised. We'll also have a new strict mode for reliability. So there are a lot of things in the language which are just intolerable. But the biggest problem with the bad parts in this language isn't that they are useless. They actually are occasionally useful. And so the web has found uses for all of the really bad parts of the language. So we were very greatly constrained in what we could take out. And we've tried to be respectful for existing code and tried to minimize the breakage that the new language will cause. But there's some stuff in the language which really has to be fixed. So we now have an opt-in mode. You can say "strict mode" and put it in the top of your program or in the top of your function and that says, "I don't want the crappy behavior. I want the rational behavior." I recommend you not put the strict mode tag into your program unless you understand what it does and what it means and that's the language you want to be writing in. But I recommend that's the language that you want to be writing in. So right now we're waiting on implementations. The specification's just about done. Microsoft and Mozilla both committed to public testing. If the testing goes well, then the standards should go to the ECMA general assembly in December and I'm hoping that it will pass. And then we'll probably see it up here in web browsers even before that. If you could hold it to the end. We're almost there. Something that's not coming soon is a competing project called ES4. That project has been cancelled. There were some good ideas in that project though and they've been resurrected in a follow-on to 3.1 called Harmony. So far, the project doesn't have any defined goals or rules, so it's a little vague as to what it's gonna turn out to be. We'll keep an eye on that. There's been some real interesting work lately in secure subsets. JavaScript is not a secure programming language but it's not far off from one. If you correct--get rid of the global object and make a few other changes-- hold much closer to its scheme nature, there's the kernel of a secure language in there. We've seen some experiments like FBJS out of Facebook, Caja & Cajita from the Google, and ADsafe, which is my own work. ADsafe is intended to make advertising safe. Currently it's not, and we can talk about that another time. These subsets will be informing the design of a new language which will ultimately replace JavaScript. And there's some exploration going on now at ECMA for such a language. So to review the good parts, this is maybe the best part of all. Your JavaScript application has the potential to reach an audience of billions. There is no other programming platform that has anywhere near that kind of reach. And, you know, just that, I think, should be enough to encourage you to wanna be on this platform. If you avoid the bad parts, JavaScript works really well. There's even brilliance in this language. There should be love in the JavaScript community for this language and its designer, 'cause there is goodness here. And it is possible to write good programs in JavaScript. There are a lotta people who thought it's not possible to write good programs, so you shouldn't even try. My message is it is possible and it is necessary to write good programs. If you don't wanna write good programs, I recommend you find another line of work. Um, then finally, um, here's the commercial plug. I wrote this cranky little pamphlet called "JavaScript: The Good Parts." So if you wanna know more about this silly language, that's where to go. So that's it. That's all I got for you today. Thank you. [applause] So how do we do questions here? Is there a mic or do I repeat or what? [man speaking indistinctly] Crockford: Okay, yes? man: So strict mode in 3.1, does that actually change behavior or does it just pick things out? Crockford: Strict mode, does it change behavior or does it take things out? It actually changes some behavior. So one of-- It does take some things out. Like, you can't have a "with" statement in strict mode. So it does take some features out of the language. It changes the way some features work. Like, it greatly constrains how eval works and reduces its ability to do harm to the state. It also changes some air behavior. For example, currently in the language, if you do an assignment to a read-only property of an object, you get a silent failure. Which is a bad thing. In strict mode, you will now get an exception, which is a better thing. Any other questions? man: I've heard you and some other people I know talk about ideas for projects to fix the DOM problem. Can you give us a update on what's going on there? Crockford: Question is what are we doing about the DOM problem? One bit of difficulty about that is there are two independent standards bodies that control two parts of this system. ECMA controls the programming language and W3C controls the API. And these two organizations, as far as I can tell, do not cooperate with each other. They don't talk, they don't share plans. That's a problem. And so there's much in the DOM-- Fixing the language will not solve any of our security problems if the DOM is left the way it is because it is also hopelessly insecure. So I'm hoping that we can put ECMA and W3C together and do a more collaborative approach to revising the DOM. I see work going on on HTML 5 and the web API stuff and it's really alarming to me. I think they're going off in very, very bad direction. I think it's way too complicated. I don't think it's addressing our real problems. It just seems more like a standard maker's holiday to me. So I'm hoping that we can do a reset there, start over with a better set of goals that we can go into the future together. I'm optimistic about it because of what I've seen in the AJAX libraries. You know, the DOM model is just really awful. There was originally the Netscape model, which was even worse. Microsoft improved it. Microsoft gets beaten up a lot for making the DOM so bad. I think the thing they did wrong was they stopped too soon. But it is bad. But the AJAX libraries are all very thin. Just, you know, a little bit of code, you know, generally on the order of 20 to 40k, which makes it so much better, you know? So eventually I'd like to take a look at the lessons that we got from the AJAX libraries, and then refactor the DOM based on that, push it down, and that becomes the new API. Yeah? man: What about Lambdasoft? Lambda is good. I like Lambda. You had lots of praise for it. But Lambda's more than closures. How do you spell Lambda in JavaScript? Crockford: How do you spell Lambda in JavaScript function? So you don't get everything that you get in scheme. You know, so we don't have continuations. We don't have tail recursion optimization. There's a lot of stuff that's missing. But the basic notion of helixical scoping is there and functions as first-class values. Yes? man: You mentioned the worst mistake in JavaScript was the use of global variables for linkage. What's your preferred way of solving that problem? Crockford: So I said the worst problem in JavaScript was its use of global variables for linkage. How would I solve that? I'd like to have some... discovery pattern in which each of the compilation units is initially completely isolated, but is given a capability which allows it to introduce itself to some other capability manager. So they can make introductions to each other and form a network. Uh, uh, yeah? man: You said that there is no issues with using objects as though they were hash tables. Remind me what key you would use [indistinct]. Crockford: Okay, so Waldemar is getting after me about-- JavaScript objects are not strictly hash tables, or are defective hash tables, I think is maybe more correct. In that there are some names which will cause collisions. And, in fact, some of the stuff we came up with in 3.1 is a little odd in the way it's put together and that was in order to not worsen that problem. So, yeah, it's not perfect. Like so much in this language, it's not perfect. Yes? man: You were saying that you think that web apps and HTML 5 is going in the wrong direction. What things do you think that we're doing wrong? Is it just that we're not solving the problems, or is it are we actually adding to them? Crockford: What do I think is wrong with HTML 5? man: And the web apps. Crockford: And the web apps? I think it's doing too much. You can look at any individual thing and say, "Oh, that looks nice." But there are way too many of those things. I would like to see a more disciplined approach. I'd like to see a more minimalist approach. You know, so if you look at the two proposals that were competing for the fourth edition, ES3.1 and ES4. I preferred ES3.1. It was less ambitious but it was less likely to cause problems. And it was moving more toward minimalism. Which I think is something which is way underrated, Particularly in standards. My view of minimalism, particularly after the JSON standard, is that the less we have to agree on in order to work together, the better. And so I would like to look at a way of re-engineering HTML and all the stuff that goes around it to be much smaller and work better. And, you know, I see HTML 5 and the web apps going in the other direction, which is just the emperor's old clothes approach, where you just keep piling more stuff and more stuff and more stuff. It just gets too big. It's easy to make things bigger. It's harder to make things better. Okay. Yeah? man: How did it come about that JSON and, uh, ECMAscript have the same syntax, but almost--but not quite? Crockford: Yeah, so how'd it come about that JSON and JavaScript have almost the same syntax? I think it's just in the two line-ending characters. Yeah? Yeah. It's because I missed that line in the standard when I was putting it together. When I specified what the whitespace characters were, carriage return, line feed, tab, and space. And I missed that-- What-- PS and? man: And LS? Crockford: And LS. Were also recognized as whitespace. We tried to fix that in the ECMAscript standard and we couldn't. So we're stuck with that little bit of difference. As far as I can tell, nobody's ever used PS and NLS in this context, so... [man speaking indistinctly] Crockford: Yeah, but I've never seen anybody use them. So it hasn't been a problem yet. There's a potential security hazard in that the two systems view it differently. Particularly when-- But we never identified an exploit that came from that. And now that there's an explicit JSON parser built in to JavaScript--that's one of the new good parts, by the way. That problem goes away completely. Yes? man: So the first time I was using JSON, the first problem I ran into, like, first object I tried to parse with the JSON parser, it wouldn't parse and it was because I didn't put quotes around my property names. Is there a reason for why that is not allowed? Crockford: Yeah, so why does JSON require quotes around the property names? There are three reasons. One of the reasons is that I wanted to align it with Python. In Python, the quotes are required. Another reason was it makes the grammar of the standard much easier to specify and I like simplicity. But the real reason, the true reason, is that JavaScript has a-- okay, I'll say it-- a stupid reserved word policy. And there are certain words that you cannot use in the key position of an object literal. Many of those names are not even used in the language. They're reserved unnecessarily and there's just no reason for it. And at the time that I put JSON together, it wasn't like I was riding on JavaScript's coattails, because nobody was using JavaScript at that time and everybody hated JavaScript. So it wasn't like I was basking in JavaScript's glow. So in order to not have quotes but still use it in JavaScript, I was going to have to have an appendix of the JSON spec, which was gonna be at least as big as all the rest of the spec describing how the reserve words worked. Basically what it said, "This is something that's really stupid in JavaScript." You know, need to point it out. And at that point, I didn't wanna make JavaScript look stupider. So I said, "Okay, we'll just quote the keys and then we don't have to tell anybody about this shameful thing." One bit of good news. We fixed that in the next language. Reserved words are now allowed in key position and also in dot position in the language. So that's better. But that took a long time. Uh, one more question? Yeah? All right, one more. Yes? man: Are there any prospects for adding concurrency to the language? Crockford: Are there any prospects for adding concurrency to the language? It depends on what you mean by "concurrency." Brendan Eich is pretty adamant and I completely agree with him. We should not put threads in this language. I would like to see some sort of messaging model. I don't know that it belongs in this language. More likely, it belongs in some layer beside the language. We would definitely benefit from that. man: There is--Firefox 3.1 is gonna have support for APIs that allow you to create separate threads that can send messages to each other. Crockford: Yeah, I like that model a lot. Okay, that's all I got for you today. Thanks. [applause] Souders: That was an amazing talk, Doug. Thank you very much.
A2 初級 美國腔 JavaScript。好的部分 (JavaScript: The Good Parts) 105 11 朱聪聪 發佈於 2021 年 01 月 14 日 更多分享 分享 收藏 回報 影片單字