`
hideto
  • 浏览: 2679069 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

A(Re)-Introduction to JavaScript

阅读更多
2007-7-17 22:30左右
长夜慢慢,无心睡眠,老婆已眠
笔者打开笔记本,翻开这篇老文,愿与君共享之
A(Re)-Introduction to JavaScript
Simon Willison - http://simonwillison.net/
Notes made in preparation for a three hour tutorial at ETech in San Diego, March 6th 2006


目录
介绍
概览
数字
字符串
其他类型
变量
操作符
控制结构
对象
数组
方法
自定义对象
内部方法
闭包
内存泄漏


介绍
我叫Simon Willison,本文的标题为“A re-introduction to JavaScript”。

为什么要重新介绍JavaScript?因为JavaScript有理由称为世界上最易误解的语言。虽然JavaScript经常被当作玩具,其实在它的简单性
下面隐藏着强大的语言特性。去年我们看到许多高质量的JavaScript程序,这显示出对这门技术的深入了解对任何Web开发人员是一项很重
要的技能。

先看看这门语言的历史非常有用。JavaScript创建于1995年,1996年早期和Netscape 2一起发布,作者Brendan Eich则是Netscape的一名
工程师。最初JavaScript称为LiveScript。出于市场的原因以及当时Sun公司的Java语言的流行才改名换姓。这是JavaScript与Java产生
混淆的源头。

几个月后微软同IE 3一起发布了一个最兼容版本的语言JScript。Netscape把JavaScript提交给一个欧洲标准组织Ecma,这样导致在1997年
出现了第一版的Ecmascript标准,并在1999年发布了经过重大更改的Ecmascript 3 -- 这个版本一直稳定下来,虽然目前第4版也在开发中。

版本的稳定对开发人员来说是好消息,因为这让诸多实现有机会迎头赶上。我这里将主要关注第3版。出于熟悉,我将一直用JavaScript
作为其名称。

不像大多数编程语言,JavaScript没有输入输出的概念。它被设计来作为一门脚本语言在宿主环境里运行,并且依赖于宿主环境来提供与
外界交互的机制。最常见的宿主环境是浏览器,但是JavaScript解释器也可以在Adobe Acrobat,Photoshop,Yahool!的Widget引擎等等
里面找到。

概览
让我们以这门语言的构建块--类型开始。
JavaScript程序处理值,并且这些值都属于某一类型。
JavaScript的类型有:
Number
String
Boolean
Function
Object
以及undefined和null,它们有点奇怪。
以及数组,它是一种特殊的对象。
还有日期和正则表达式,也都是语言内建支持的对象。
从技术上讲,函数也只是一种特殊类型的对象。
所以类型图看起来如下:
Number
String
Boolean
Object
-Function
-Array
-Date
-RegExp
null
undefined
以及一些内建的Error类型。
分享到:
评论
19 楼 hax 2007-07-18  
其他翻译:
字面量、字面值、直接量
18 楼 hax 2007-07-18  
哦,记起来了。台湾人通常把literal译作“常值”。
17 楼 hax 2007-07-18  
Literal: A letter or symbol that represents a particular constant or number, known or unknown, and is not programmer-defined.

通常literal翻成文字量,或者字面值。当然这都不是很易懂。有时候我觉得如果上下文不会造成误解的情况下,可以直接翻成“值”,例如 string literal可以翻译成字符串值。但是如果强调了literal的意思,那就需要找个词。我以前看到过一种比较好的翻译,一时想不起来了。。。
16 楼 hax 2007-07-18  
最好有个wiki版的,有中英文对照,大家可以对着改。
15 楼 hideto 2007-07-18  
string literal怎么翻译比较好?
14 楼 hax 2007-07-18  
引用
Null表示没有值。


原文是 Null means a deliberate no value.

意思是:null表示“无”这个有意义的值。
13 楼 hax 2007-07-18  
引用
这是我们第一次解除JavaScript对象!



错别字,呵呵。难道你用的是谷歌拼音?

建议翻成“这是我们和JS对象的第一次亲密接触”,哇哈哈哈哈。
12 楼 hax 2007-07-18  
如上,所有类型带有s的,我觉得最好翻译出来,因为它不是表示真的实体名,而是表示一些数字对象,一些函数对象这样的意思。
11 楼 hax 2007-07-18  
引用
出于技术的准确性,functions是一种特殊的对象。


从技术上讲,函数也只是一种特殊类型的对象。
10 楼 hideto 2007-07-18  
恩,已经更正。
感谢hax帮忙完善此文档。
9 楼 hax 2007-07-18  
引用
还有Dates和Regular Expressions,它们是免费的对象。


这个翻译令人有点费解。建议改成:

还有日期和正则表达式,也都是语言内建支持的对象。
8 楼 hax 2007-07-18  
host翻译成“宿主”比“主机”好。
7 楼 hax 2007-07-18  
引用

这个版本一直稳定下来,虽然目前第4版也在使用。


这里有错误,第4版还在开发中。
6 楼 hideto 2007-07-18  
内部方法
JavaScript允许在其他方法里声明方法,我们在前面的makePerson()方法里看到了。JavaScript里嵌套方法的一个重要的细节是它们
可以它们的父方法的作用域里的变量:
function betterExampleNeeded() {
  var a = 1;
  function oneMoreThanA() {
    return a + 1;
  }
  return oneMoreThanA();
}

这提供了编写更易维护的代码的便利。如果一个方法依赖于一到两个在其他地方没用的方法,你可以嵌套这些辅助方法到被别处调用的方法
里面。这控制了global scope的方法的数量。

这也减少了使用全局变量的诱惑。在写赋值代码时,我们经常尝试使用全局变量来在多个方法间共享值 -- 这导致我们的代码很难维护。
嵌套方法可以在它们的父方法里分享变量,这样当你不想污染你的global名字空间时可以使用该机制来将方法结合在一起 -- “local
globals”。这项技术应该谨慎使用,但是它确实非常有用。

闭包
闭包让我们看到了JavaScript最强大的一面,但是也很容易让人迷惑。
function makeAdder(a) {
  return function(b) {
    return a + b;
  }
}
x = makeAdder(5);
y = makeAdder(20);
x(6)
?
y(7)
?

makeAdder方法名应该已经泄露了机密:它创建了一个新的“adder”方法,“adder”方法在使用一个参数加以调用时将这个参数加到
该方法被创建时的初始化参数上。

这里发生的事情和内部方法里发生的事情很类似:一个定义在另一个方法里的方法可以访问外部方法的变量。这里唯一的区别是外部方法
已经返回了,这样按常识看起来它的本地变量不再存在。但是它们确实存在 -- 否则adder方法将不能工作。而且,这里有两个
不同的makeAdder的本地变量的拷贝 -- 一个是5而另一个是20.

真正发生的事情如下。当JavaScript执行一个方法是,一个“scope”对象被创建来持有该方法创建的本地变量,它使用传递进来的任何
变量作为方法参数来初始化。这类似于global对象,所有的全局变量和方法位于global对象里,但是有一些不同:首先,每次一个方法
开始执行时一个新的scope对象就被创建;其次,不像全局对象(在浏览器器里使用window来访问),这些scope对象不能直接在你的
JavaScript代码里访问。没有机制来遍历当前scope对象的属性。

所以当makeAdder被调用时,一个scope对象被创建并拥有一个属性:a,该属性是传递给makeAdder方法的参数。然后makeAdder返回一个
新创建的方法。正常情况下,JavaScript的垃圾收集器这时将清除和makeAdder相关的scope对象,但是返回的方法持有对scope对象的引
用。结果是,scope对象将不会被垃圾收集器清除,直到没有对makeAdder返回的方法对象的引用。

scope对象形成一个称为scope chain的链,类似于JavaScript的对象系统使用的prototype链。

闭包就是一个方法和创建该方法的scope对象的联合。

闭包让你保存状态 -- 这样,它通常可以用来替代对象。

内存泄漏
闭包的一个不幸的副作用是它使得在IE里容易产生内存泄露。JavaScript是一个垃圾收集语言 -- 对象在它们创建时分配内存并在没有
对对象的引用时被浏览器回收。宿主环境提供的对象被该环境处理。

浏览器环境需要管理大量表示被呈现的HTML页面的对象 -- DOM对象。这些对象的内存分配和回收由浏览器管理。

区别于JavaScript本身使用的垃圾收集机制,IE使用它自己的垃圾收集方案。这两者的交互可能会导致内存泄露。

任何时候一个JavaScript对象和一个native对象间的循环引用都会导致内存泄露。考虑下面的代码:
function leakMemory() {
  var el = document.getElementById('el');
  var o = {'el': el};
  el.o = o;
}

上面形成的循环引用会产生内存泄露;IE将不会释放el和o占用的内存直到浏览器完全重启。

上面的例子很可能被忽视;内存泄露仅仅在长时间运行的程序里或者由于巨型数据结构或循环而泄露大量内存时才引起真正的关心。

闭包可以很容易产生内存泄露,考虑下面的代码:
function addHandler() {
  var el = document.getElementById('el');
  el.onclick = function() {
    this.style.backgroundColor = 'red';
  }
}

上面的代码创建一个元素,但它被点击时变成红色。这也会导致内存泄漏?为什么?因为对el的引用不经意的被为匿名内部方法创建的
闭包获取了。这就创建了一个JavaScript对象(匿名方法)和一个native对象(el)的循环引用。

有许多这种问题的解决方法,最简单的是:
function addHandler() {
  var el = document.getElementById('el');
  el.onclick = function() {
    this.style.backgroundColor = 'red';
  }
  el = null;
}

这就破坏了循环引用。

令人惊奇的是,破坏闭包产生的循环应用的一种技巧是添加另一个闭包:
function addHandler() {
  var clickHandler = function() {
    this.style.backgroundColor = 'red';
  }
  (function() {
    var el = document.getElementById('id');
    el.onclick = clickHandler;
  })();
}

内部方法会马上执行,并且隐藏了用clickHandler创建的闭包的内容。

另外一个避免闭包的很好的技巧是在window.onunload事件触发时破坏循环引用。许多事件库会为你做这件事。
5 楼 hideto 2007-07-18  
自定义对象
在经典的面向对象编程领域,对象是数据和操作数据的方法的集合。让我们考虑一个person对象,它有一个first和last name域。
有两种方式来显示名字:“first last”或“last, first”。使用我们前面讨论的方法和对象来完成这件事情:
function makePerson(first, last) {
  return {
    first: first,
    last: last
  }
}
function personFullName(person) {
  return person.first + ' ' + person.last;
}
function personFullNameReversed(person) {
  return person.last + ', ' + person.first
}
> s = makePerson("Simon", "Willison");
> personFullName(s)
Simon Willison
> personFullNameReversed(s)
Willison, Simon

这可以工作,但是非常丑陋。你将在global名字空间里得到一打方法。我们真正需要的是添加方法到一个对象。
由于方法也是对象,这很简单:
function makePerson(first, last) {
  return {
    first: first,
    last: last,
    fullName: function() {
      return this.first + ' ' + this.last;
    },
    fullNameReversed: function() {
      return this.last + ', ' + this.first;
    }
  }
}
> s = makePerson("Simon", Willison")
> s.fullName()
Simon Willison
> s.fullNameReversed()
Willison, Simon

这里有些事情我们以前没见过: “this”关键字。在一个方法里,“this”表示当前对象。它实际上的含义是通过你调用该方法的方式
决定的。如果你在该对象上使用.符号,该对象就是“this”。如果你不使用.符号,“this”则表示global对象。这是频繁发生的错误:
> s = makePerson("Simon", "Willison")
> var fullName = s.fullName;
> fullName()
undefined undefined

当我们调用fullName()时,“this”绑定为global对象。由于没有叫first和last的global变量,我们对两者分别得到undefined。

我们可以使用“this”关键字来改进我们的makePerson方法:
function Person(first, last) {
  this.first = first;
  this.last = last;
  this.fullName = function() {
    return this.first + ' ' + this.last;
  }
  this.fullNameReversed = function() {
    return this.last + ', ' + this.first;
  }
}
var s = new Person("Simon", "Willison");

我们引入了另一个关键字:“new”。“new”与“this”关系紧密。它的工作是创建一个新的空对象,然后调用指定的方法,并把“this”
指定为该对象。设计用来通过“new”调用的方法称为构造函数。通常的实践经验是将这些方法首字母大写来提示使用“new”调用它们。

我们的person对象越来越好了,但是仍然有一些丑陋依附在它上面。每次我们创建一个person对象时我们在它里面创建了两个新的方法对
象 -- 如果将这些代码共享出来是否更好呢?
function personFullName() {
  return this.first + ' ' + this.last;
}
function personFullNameReversed() {
  return this.last + ', ' + this.first;
}
function Person(first, last) {
  this.first = first;
  this.last = last;
  this.fullName = personFullName;
  this.fullNameReversed = personFullNameReversed;
}

这样更好:我们仅仅创建方法一次,并且将引用在构造函数里赋值。我们能否比这做的更好呢?答案是yes:
function Person(first, last) {
  this.first = first;
  this.last = last;
}
Person.prototype.fullName = function() {
  return this.first + ' ' + this.last;
}
Person.prototype.fullNameReversed = function() {
  return this.last + ', ' + this.first;
}

Person.prototype是所有的Person实例共享的对象,它组成查询链的一部分:任何时候你尝试访问Persond的一个属性而该属性不存在时,
JavaScript将检查Person.prototye来看看该属性是否在那里存在。结果是,任何赋给Person.prototype的属性对所有实例可见。

这是一个极端强大的工具。JavaScript让你修改在任何时候修改某个东西的prototype,这意味着你可以在运行时添加额外的方法到已经
存在的对象上:
> s = new Person("Simon", "Willison");
> s.firstNameCaps();
TypeError on line 1: s.firstNameCaps is not a function
> Person.prototype.firstNameCaps = function() {
    return this.first.toUpperCase()
  }
> s.firstNameCaps()
SIMON

非常有趣,你也可以添加东西到JavaScript内建的对象的prototype上。让我们添加一个方法到String上来返回倒序的字符串:
> var s = "Simon";
> s.reversed()
TypeError on line 1: s.reversed is not a function
> String.prototype.reversed = function() {
  var r = '';
  for (var i = this.length - 1; i >= 0; i--) {
    r += this[i];
  }
  return r;
}
> s.reversed()
nomiS

我们的新方法甚至对字符串字面量工作!
> "This can now be reversed".reversed()
desrever eb won nac sihT

上面提到,prototye形成部分查询链。该链的根为Object.prototype,它的方法里包括toString() -- 这个方法在你尝试把一个对象以字符串
表示时调用。这对调试我们的Person对象非常有用:
> var s = new Person("Simon", "Willison");
> s
[object Object]
> Person.prototype.toString = function() {
    return '<Person: ' + this.fullName() + '>';
  }
> s
<Person: Simon Willison>

还记得avg.apply()为什么有一个null参数吗?我们现在可以再看看它。
apply()的第一个参数是应该被认为是“this”的对象。例如,这里是“new”的简单实现:
function trivialNew(constructor) {
  var o = {}; // Create an object
  constructor.apply(o, arguments);
  return o;
}

这不是new的精确复制,因为它没有建立prototype链。apply()很难解释 -- 它不常用,但是它很值得了解。

apply()有一个姐妹方法称为call,它让你设置“this”但是使用展开的参数列表而不是一个数组。
function lastNameCaps() {
  return this.last.toUpperCase();
}
var s = new Person("Simon", "Willison");
lastNameCaps.call(s);
// Is the same as:
s.lastNameCaps = lstNameCaps;
s.lastNameCaps();
4 楼 hideto 2007-07-18  
方法
和对象一样,方法是理解JavaScript的核心组件。最基本的方法:
function add(x, y) {
  var total = x + y;
  return total;
}

JavaScript方法可以有0个或多个命名参数。方法体可以包含任意多个参数,并且可以声明自己的本地变量。返回语句可以在任何时候
用来返回一个值从而终结方法。如果没有返回语句或者空返回,JavaScript将返回undefined。

命名参数更像是方法的指导,你可以调用一个方法而不传递它期望的参数,这时这些参数将被设置为undefined。
> add()
NaN // You can't perform addition on undefined

你也可以传递比方法期望更多的参数:
> add(2, 3, 4)
5 // added the first two; 4 was ignored

方法可以在方法体里访问一个额外的参数arguments,它是一个包含所有传递进来的参数值的array-like对象。
让我们重写add方法并使用尽可能多的参数值:
function add() {
  var sum = 0;
  for (var i = 0, j = arguments.length; i < j; i++) {
    sum += arguments[i];
  }
  return sum;
}

>add(2, 3, 4, 5)
14

很方便吧,让我们再创建一个求均值方法:
function avg() {
  var sum = 0;
  for (var i = 0, j = arguments.length; i < j; i++) {
    sum += arguments[i];
  }
  return sum / arguments.length;
}
> avg(2, 3, 4, 5)
3.5

这非常好用,但是引入了一个新的问题。avg()方法采用逗号分割的参数列表 -- 但是如果你想得到一个数组的均值时怎么办?
我们重写该方法:
function avgArray(arr) {
  var sum = 0;
  for (var i = 0, j = arr.length; i < j; i++) {
    sum += arguments[i];
  }
  return sum / arr.length;
}
>avgArray([2, 3, 4, 5])
3.5


但是重用我们刚才已经创建的方法会更好。幸运的是,JavaScript可以让你调用一个方法并使用一个任意的数组作为参数,使用apply()方法:
> avg.apply(null, [2, 3, 4, 5])
3.5

apply()的第二个参数是作为参数的数组,第一个参数我们稍后解释。这强调了方法也是对象。

JavaScript让你创建匿名方法。
var avg = function() {
  var sum = 0;
  for (var i = 0, j = arguments.length; i < j; i++) {
    sum += arguments[i];
  }
  return sum / arguments.length;
}

这在语义上等同于function avg()形式。这种方式非常强大,因为它允许你把一个完整的方法定义放在你通常放置表达式的任何位置。
这允许一些聪明的小技巧。这里是一种“隐藏”一些本地变量的方式 -- 类似C里面的block scope:
> var a = 1;
> var b = 2;
> (function() {
    var b = 3;
    a += b;
  })();
> a
4
> b
2

JavaScript允许你递归调用方法。这对处理树结构非常有用,例如浏览器DOM。
function countChars(elm) {
  if (elm.nodeType == 3) { // TEXT_NODE
    return elm.nodeValue.length;
  }
  var count = 0;
  for (var i = 0, child; child = elm.childNodes[i]; i++) {
  count += countChars(child);
  }
  return count;
}

这导致一个潜在的问题:你怎样递归调用匿名方法?答案为arguments对象,它除了类似与一个参数的列表外还提供一个属性叫callee。
这个属性引用了当前方法,这样就可以用来做递归调用:
var charsInBody = (function(elm) {
  if (elm.nodeType == 3) { // TEXT_NODE
    return elm.nodeValue.length;
  }
  var count = 0;
  for (var i = 0, child; child = elm.childNodes[i]; i++) {
    count += arguments.callee(child);
  }
  return count;
}) (document.body);

既然arguments.callee为当前方法,并且所有的方法都是对象,你可以使用arguments.callee来跨越多个调用保存信息到同一方法。
这里是记录该方法被调用多少次的例子:
function counter() {
  if (!arguments.callee.count) {
    arguments.callee.count = 0;
  }
  return arguments.callee.count++;
}
> counter()
0
> counter()
1
> counter()
2
3 楼 hideto 2007-07-18  
对象
JavaScript对象是简单的键-值对的集合,所以它类似于:
Python里的Dictionary
Perl和Ruby里的Hash
C和C++里的Hash table
Java里的HashMap
PHP里的Associative array
由于JavaScript里除了核心类型外都是对象,任何JavaScript程序自然涉及到大量的hash table查询,还好它很快!
键是一个JavaScript字符串,而值可以是任意JavaScript值 -- 包括对象。这允许你构建任意复杂度的数据结构。
有两种创建对象的基本方式:
var obj = new Object();

var obj = {};

这两者在语义上是相等的,后者称为对象字面量语法,它更为方便。对象字面量语法在早期版本的JavaScript里没有出现,这是你在
许多代码里只看到旧的方式的原因。

一旦创建了对象,对象的属性可以有两种方式来得到:
obj.name = "Simon"
var name = obj.name;

obj["name"] = "Simon";
var name = obj["name"];

它们也是语义相等的。后者的优点是属性名可以以字符串的方式提供,这意味着它可以在运行时计算得到。
后者还可以使用保留字作为属性名:
obj.for = "Simon"; // Syntax error
obj["for"] = "Simon"; // works fine

对象字面量语法可以用于初始化对象:
var obj = {
  name: "Carrot",
  "for": "Max",
  details: {
    color: "orange",
    size: 12
  }
}

属性访问可以链起来:
> obj.details.color
orange
>obj["details"]["size"]
12


数组
JavaScript里的数组是一个特殊类型的对象 -- 它使用数字而不是字符串作为属性名。它们想正常的对象一样使用(始终使用[]语法
访问属性),但是它们有一个称为'length'的魔力属性,它的值始终比当前array最大的索引大1.
旧的创建数组的方式为:
> var a = new Array();
> a[0] = "dog";
> a[1] = "cat";
> a[2] = "hen";
> a.length
3

更方便的方式是使用数组字面量:
> var a = ["dog", "cat", "hen"];
> a.length
3

注意array.length没必要是array中的items的数量,考虑下面的代码:
> var a = ["dog", "cat", "hen"];
> a[100] = "fox";
> a.length
101

记住 -- array的length比最大的索引大1.

如果你查询一个不存在的array索引,你会得到undefined:
> typeof(a[90])
undefined

你可以像下面这样遍历数组:
for (var i = 0; i < a.length; i++) {
  // Do something with a[i]
}

像上面那样每次查询数组的length属性是非常低效的,看看更好的方式:
for (var i = 0, j = a.length; i < j; i++) {
  // Do something with a[i]
}

以及一个更好的习惯用法:
for (var i = 0, item; item = a[i]; i++) {
  // Do something with item
}

这里我们创建了两个变量。for循环中间部分的赋值也被检查是否为“真” -- 如果为“真”,循环继续。由于i是每次自增的,array里的items
将按顺序赋值给item。当值为“假”的item被检查出来时循环结束(例如undefined)。
注意这个技巧只能用于不包含“假”的值的数组(例如对象数组或DOM节点数组)。如果你对可能包含0的数字数组或包含空字符串的字符串数组
进行遍历,还是使用i,j方式吧。

如果你想添加一个item到数组中,最安全的方式是这样:
a[a.length] = item;

因为a.length比最大的索引大1,可以保证这样会在数组的末尾添加数据。

数组自带一些方法:
a.toString(), a.toLocaleString(), a.concat(item, ..), a.join(sep),
a.pop(), a.push(item, ..), a.reverse(), a.shift(), a.slice(start, end),
a.sort(cmpfn), a.splice(start, delcount, [item]..), a.unshift([item]..)
concat返回一个添加了items的新数组
pop删除并返回最后的item
push添加一个或多个items到数组末尾(类似ar[ar.length]用法)
slice返回一个子数组
sort使用可选的比较方法
splice让你通过删除一部分items并用别的items替换来修改一个数组
unshift添加items到数组前端
2 楼 hideto 2007-07-18  
变量
JavaScript里新变量用var关键字声明:
var a;
var name = "simon";

如果你声明一个变量而不给它赋值,则它的值为undefined。

操作符
JavaScript的数学操作符为+,-,*,/和%(取余)。
赋值使用=,复合赋值如+=和-=表示x = x 操作符 y。
x += 5
x = x + 5

你可以使用++和--来自增和自减。它们可以当成前缀或后缀操作符使用。

+操作符也用于字符串串联:
> "hello" + " world"
hello world


如果你用一个字符串和一个数字(或其他值)相加,JavaScript会首先把这个值转换成字符串:
> "3" + 4 + 5
345
> 3 + 4 + "5"
75

用一个空字符串和别的东西相加是类型转换的有用方式。

JavaScript里的比较使用<,>,<=和>=。这对字符串和数字都工作。
相等有一点不直接。如果给两个不同类型的值作比较,双等号操作符会处理类型强制转换:
> "dog == "dog"
true
> 1 == true
true

可以使用三等号操作符来避免类型强制转换:
> 1 === true
false
> true === true
true

还有!=和!==操作符。
JavaScript也有位操作符。

2007-7-18 01:00左右
(困了,明天接着写)

控制结构
JavaScript具有同C家族类似的控制结构语句集。条件语句支持if和else,你可以把它们链在一起使用:
var name = "kittens";
if (name == "puppies") {
  name += "!";
} else if (name == "kittens") {
  name += "!!";
} else {
  name = "!" + name;
}
name == "kittens!!"

JavaScript具有while循环和do-while循环。前者适合基本的循环,后者保证至少循环一次:
while (true) {
  // an infinite loop!
}

do {
  var input = get_input();
} while (inputIsNotValid(input))

JavaScript的for循环同C和Java一样:它让你提供控制信息给循环。
for (var i = 0; i < 5; i++) {
  // Will execute 5 times
}

&&和||操作符使用短路逻辑,这表示它们将依赖于第一个操作符来判断是否执行第二个操作符。
这对null对象很有用,可以在访问它们的属性之前检查它们是否为null:
var name  o && o.getName();

或者设置默认值:
var name = otherName || "default";

JavaScript有一个三元操作符来在一行里写条件语句:
var allowed = (age > 18) ? "yes" : "no";

switch语句基于数字或字符串用于多个分支:
switch(action) {
  case 'draw':
    drawit();
    break;
  case 'eat':
    eatit();
    break;
  default:
    donothing();
}

如果你不加上break语句,将继续执行下一级。你很少希望这样做 -- 如果你确实想这样的话,加上一行fallthrough的注释很值得:
switch(a) {
  case 1: // fallthrough
  case 2:
    eatiti();
    break;
  default:
    donothing();
}

default语句是可选的。你可以在switch和case语句处使用表达式:
switch(1 + 3) {
  case 2 + 2:
    yay();
    break;
  default:
    neverhappens();
}
1 楼 hideto 2007-07-18  
数字
根据规范,JavaScript里的数字为“双精度64位格式IEEE754值”。这就有了一些有趣的推论。
JavaScript里没有integer,所以如果你习惯于C或Java里的数学的话,你就必须对算术小心点。
看看下面的内容:
0.1 + 0.2 = 0.30000000000000004

支持标准的数字操作符,包括加,减,乘,取模(或取余)等等。还有一个我前面忘了提到的内建的对象叫Math,它用于处理更高级的数学
方法和常量。
Math.sin(3.5)
d = Math.PI * r * r;

你可以使用内建的parseInt()方法把一个sring转换为一个number:
> parseInt("123")
123
> parseInt("010")
8

上面根据第一个字符0来把参数当作一个八进制数,你可以始终提供第二个可选的进制参数来避免这种情况:
> parseInt("123", 10)
123
> parseInt("010", 10)
10

如果你想把一个二进制数转换成一个整数,只需修改第二个参数即可:
> parseInt("11", 2)
3

JavaScript还有一个特殊的值称为Not-a-Number,它在例如当你把一个非数字的字符串转换成一个数字时出现。
> parseInt("hello", 10)
NaN

NaN是有毒的 -- 如果你把它当作任何数学操作的输入时结果也会是NaN:
> NaN + 5
NaN

你可以使用内建的isNaN方法来检测:
> isNaN(NaN)
true

JavaScript还有一个无穷大和无穷小的特殊值:
> 1 / 0
Infinity
> -1 / 0
-Infinity


字符串
JavaScript里的字符串是字符序列。更准确的说,它是unicode字符序列,每个字符由16位数字表示。这对国际化来说是好消息。
如果你想表示一个单独的字符,你只需使用length为1的字符串。
访问length属性来得到字符串的长度:
> "hello".length
5

这是我们和JavaScript对象的第一次亲密接触!我提到过字符串也是对象吧?它们也有方法:
> "hello".charAt(0)
h
> "hello, world".replace("hello", "goodbye")
goodbye, world
>"hello".toUpperCase()
HELLO


其他类型
null表示“无”这个有意义的值。undefined表示一个变量还没有赋值。我们在后面会讲到变量。
JavaScript中可以声明一个没有赋值的变量。如果你这样做,变量的值则为"undefined"。

JavaScript有一个boolean类型,它为true或false(两者都是关键字)。
JavaScript中其他的任何东西要么是“真”要么是“假”,这决定了它们在boolean context中怎样使用。
值为“真”或“假”的规则为:
0,"",NaN,null和undefined为“假”,其他都为真。

支持的Boolean操作符有&&,||和!。你可以将任何值转换成boolean值:
> !!""
false
> !!234
true

相关推荐

    Data Visualization with Python and JavaScript.azw3

    If you’re ready to create your own web-based data visualizations—and know either Python or JavaScript— this is the book for you. Learn how to manipulate data with Python Understand the ...

    Java in a Nutshell, 7th Edition

    The book’s first section provides a fast-paced, no-fluff introduction to the Java programming language and the core runtime aspects of the Java platform. The second section is a reference to core ...

    JavaScript for kids

    JavaScript for Kids is a lighthearted introduction that teaches programming essentials through patient, step-by-step examples paired with funny illustrations. You’ll begin with the basics, like ...

    django-master-class

    ### Django Master Class: Key Takeaways and Detailed Knowledge Points ... Whether you're a beginner or an experienced developer, these concepts will help you leverage Django's full potential.

    Building Web Components with TypeScript and Angular 4

    To present these topics, the first chapters of the book provide a thorough introduction to the TypeScript language, from its new data types to its support for the document object model (DOM)....

    UE(官方下载)

    This is a convenient feature when you're manually comparing files, when you want to copy/paste between multiple files, or when you simply want to divide up your edit space. Tabbed Child Windows ...

    Java SE 8 for the Really Impatient

    A concise introduction to JavaFX, which is positioned to replace Swing GUIs, and to the Nashorn Javascript engine A thorough discussion of many small library changes that make Java programming more ...

    Serverless Applications with Node.js

    And thanks to JavaScript support in AWS Lambda and powerful new serverless API tools like the Claudia.js library, you can build and deploy serverless apps end to end without learning a new language. ...

Global site tag (gtag.js) - Google Analytics