Javascript 编程语言概论

原文出处 http://javascript.crockford.com/survey.html

综述

这篇文章为专业程序员介绍 JavaScript Programming Language 。它是一个微型语言,如果你熟悉其它语言的话,很容易理解。

JavaScript 并不是Java。它们是两种不同的语言。JavaScript 也不是 Java 的一个子集。更不是解释性的Java。(Java 是解释性的 Java!) JavaScript 和 Java 一样拥有 C语言族语法特性,但是在更深的层次它更类似于 Scheme Self。它是一个微型语言,但是它同时是功能非常强大的表达式语言。你应该重视它。你将会发现它并不是一个语言玩具,它是一个拥有着不同属性的完整语言。

JavaScript 是一个常用的语言,不需要花费太多的时间进行学习。它比 Java 更适合用于客户端编程等场景。依我个人的经验,我发现使用 JavaScript 使我 Java 语言方面的能以也得到提高,因为它为我引入了一些列非常有用的动态技术。

最初,介绍 JavaScript 的时候,我误解为它不值得我的关注。很久之后,我使用另外一种眼光看待它的时候发现藏在浏览器之下的是一个非常完美的编程语言。我最初的态度是建立在 Sun 和 Netscape 对 JavaScript 最初定位的基础上的。为了不至于和 Java 定位发生冲突,他们误传 JavaScript 的定位。在假货和业余市场,不少低劣的 JavaScript 书籍中传经常出现他们的误传。

历史

JavaScript 由 Netscape 公司的 Brendan Eich 作为一种页面脚本语言为 Navigator 2 创造。它是一个典型的表达式动态语言。因为它和 web 浏览器的联系,很快受到广泛的欢迎。没有经历一个在实际使用修改和完善的审查阶段。因此,这个语言是强大的但是同时又是有缺陷的。

这篇文章描述 ECMAScript 第三版(aka JavaScript 1.5)。 Microsoft 和 Netscape 在不断的修订版本,但是并没有修改该语言的缺陷。那些新语言并不是 JavaScript 也超出了本文的范围。

数据类型


JavaScript 拥有一个很少的数据类型集合。它有三个基本类型 boolean, number 和 string 和一些特殊值 null 和 undefined。其它所有都是 object 的变种。

Boolean 有两个值:true 和 false。

Number 是64位浮点数,类似与 Java 的 double 和 Double。没有整形类型。两个整数的除法结果是一个有小数的结果。Number也同样拥有特殊的值 NaN(不是一个 number) 和 Infinity。

String是一个拥有零个或多个的 unicode 字符串。没有单独的字符类型。一个字符用长度为一个的字符创代表。文字字符串使用 ‘ 或 “ 字符括起来。括号的使用可以随意选择,但是必须匹配。

    'This is a string.'

    "Isn't this a string? Yes!"

    'A' // 字符A

    “”//空字符串

和 Java 类似,保留字使用 / 字符。String 是不可变得。String 有一个 length 成员,用于确定字符串的字符个数。

    var s = "Hello World!";
    s.length == 12

可以给原始类型添加方法。因此,你可以添加一个 int() 方法给所有的 number 类型数据,这时 Math.PI.int() 的结果是 3。

对 Object 的实现可以提供其它类型,例如 日期 和 正则表达式,但是那些也都是object。其它任意类型都是 object。

对象

JavaScript有非常方便使用 hashtable 的方式。

    var myHashtable = {};

这个表达式创建了一个新的 hashtable 并且将一个局部变量赋值给它。JavaScript是弱类型的,因此在声明的时候不必要使用类型名。我们使用下标添加,替代,或重新获取 hashtable 里面的元素。

    myHashtable["name"] = "Carl Hollywood";

你也可以使用点号,这样更方便。

    myHashtable.city = "Anytown";

当下标是一个字符串常量,并且是合法的修饰符的时候,可以使用点号。因为对该语言的定义存在错误,保留字不能和点号结合使用,但是可以用在下标中。

你会发现 JavaScript 的 hashtable 的符号非常类似于 Java  的对象和数组的符号。JavaScript 更进了一步:对象和数组是同一回事,我可以这样写

    var myHashtable = new Object();

结果是完全一样的。

for 表达式内置了列举元素的能力。

  for (var n in myHashtable) {
document.writeln("<p>" + n + ": " + myHashtable[n] + "</p>");
}

结果是

<p>name: Carl Hollywood</p>
<p>city: Anytown</p>

一个对象是一个 name/value 对的引用容器。name 是字符串(或者其它元素,它们会转化为字符串)。value 可以使任意的数据类型,包括其它对象。Object 通常类似于hash-table实现,但是没有 hash-table 的特性(例如 hash 函数和 rehash 函数)。

对象可以很容易的嵌套在其它对象里面,并且通过表达式可以获取内部的对象。
   
    this.div = document.body.children[document.body.children.length-1];

 使用对象的文字符号,一个对象可以描述为在大括号里由逗号隔开的 name/value 对。name 在冒号之前,可以是标示符或字符串。因为对语言的定义存在错误,保留在不能作为表示符使用,但是可以以字符串的形式使用ton。value 可以是文字或任意类型的表达式。

       var myObject = {name: "Jack B. Nimble", 'goto': 'Jail', grade: 'A', level: 3};

 
return {
        event: event,
   
op: event.type,
        to: event.srcElement,
        x: event.clientX + document.body.scrollLeft,
        y: event.clientY + document.body.scrollTop};
    
    emptyObject = {};

JavaScript 的对象文字表达是 JSON 数据交换格式的基础。

新的成员可以在任何时间添加到任何对象中去。

    myObject.nickname = 'Jackie the Bee';

数组和函数也是对象的一个实现。

数组

在 javascript 里数组也是一个 hashtable 对象。这使他们非常适合稀疏矩阵的应用。当你构造一个数组,你不必声明它的空间。和 java 的 vector 类似, 数组会自动增长。值是通过键(key)而不是偏移量来获取的。这使 javascript 的数组使用起来非常方便,但是不适合数字分析的应用。

数组和对象最大的区别是长度属性(length property)。数组的长度总是比数组中最大的下表值大1。有两种方法都早一个新的数组:
 
    var myArray = [];
    var myArray = new Array();

数组是没有类型的。它可以容纳数字,字符串,布尔型,对象,函数和数组。你可以混合字符串还有数字和对象在同一个数组里面。你可以把数组作为一个一般的嵌套序列使用,就像 s-expressions。数组的一个元素下标识0。

当一个新的元素添加到数组里面去的时候,如果它的下标是正数并且比当前长度大,数组长度就会改变为下标加1。这是特性使遍历数组中每一个元素非常方便。

数组也有一个文字表达方式(literal notation),类似于对象的表达方式。

    myList = ['lats', 'peas', 'beans', 'barley' ];
 
    emptyArray = [];

    month_lengths = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];

    slide = [
        {url: 'slide0001.html', title: 'Looking Ahead' },
        {url: 'slide0008.html', title: 'Forecast' },
        {url: 'slide0021.html, title: 'Summary' }
    ]

    一个新的元素可以通过赋值赋给数组。

    a[i + j] = f(a[i], a[j]);

函数

JavaScript的函数和 C 语言的函数非常像,除了使用 function  定义而不是使用类型。当调用一个函数的时候,不必使用固定的参数个数。过长的参数会被忽略,而不足的默认为 undefined 。 这使得处理可选参数的函数非常方便。

函数可以获取一个参数数组,通过它可以访问到所有实际调用时传入的参数。这使得获取变长参数非常容易。比如:

   
function sum() { // 处理任意长度的参数,并且返回总和
       
var total = 0;
       
for (var i = 0; i < arguments.length; ++i) {
           
total += arguments[i];
       
}
       
return total;
   
}

JavaScript 支持内部函数,作用和 Java 的内部类很像,但是要简单很多。JavaScript 也支持匿名函数,作用类似于 lambda 表达式。
函数拥有自己的词汇空间。

函数时 JavaScript 首先支持的类,应此它们可以被保存或者作为参数传递。

定义

有三种定义函数的方式:函数表达式,函数操作符,和函数构造器。

函数表达式
函数表达式可以在当前的作用域创建一个拥有函数名的函数。

    function name( argumentlist ) block

函数可以嵌套。见作用域。一个参数列表(argumentlist)可以使零个或多个使用逗号隔开的参数名称。代码块(block)可以是零个或多个使用 {} 括起来的表达式。

函数表达式是函数操作符的一个简要形式:

    var name = function name( argumentlist ) block;

函数操作符
函数操作符是一个前缀操作符,它可以创建一个函数对象。看上去和函数表达式很相似。

    function name( argumentlist) bock

函数名(name)是可选的。如果给出,那么在函数内部可以通过它递归调用。也可以通过它访问函数的内部元素(IE 除外)。如果函数名省略,它将是一个匿名函数。

函数操作符通常用于为原型(prototype)赋值函数。

函数操作符也可以在适时使用,这使得像编写回调函数非常方便。

函数构造器
函数构造器使用包含参数了函数体的字符串创建函数对象。

    new Function( string . . . )

不要使用这种形式。语言的引用转换使得构造一个正确的函数体非常困难。而且,使用字符串的形式使得早期的错误检查失去作用。这种使用非常慢,因为每处使用到的地方都需要调用编译器。同时,这也是非常耗存储资源的,因为每一个函数都有自己的实现。

对象和 this

一个函数是一个对象。它可以包含其它对象做为自己的成员。这使得一个函数可以包含自己的数据表(data table)。 它使得一个对象的行为类似于一个类,拥有构造函数和一系列方法。

一个函数可以是对象的一个成员。当一个函数是一个对象的成员是叫做方法。有一个特殊的变量 this,当一个对象的方法被调用的时候被设值。

比如说,在 foo.bar() 这个表达式里,this 变量就做为一个额外的参数设置给 bar,值为 foo 。这个函数 bar 就可以引用 this 获取感兴趣的的数据。

在一个复杂的表达式里,比如说 do.re.mi.fa(),这个变量就被设为 do.re.mi ,而不是 do。在简单的函数调用里面 this 被设置为全局对象(窗口),这不是特别有用。正确的行为应该被保存 this 的值,尤其是当内部函数调用时。

构造函数

用于初始化一个对象的函数叫做构造函数。调用构造函数的顺序和调用普通函数的顺序有一点不同。构造函数使用 new 前缀调用:
   
    new Constructor(parameters...)

按惯例,构造函数的首字母大写。

new 前缀改变了this 的意思。this 指向的是一个新的对象,而不是像通常那样。构造函数的函数体用于初始化对象成员。构造函数会返回一个新的对象,除非明确使用return 语句。

构造的对象将拥有一个隐含的 prototype 连接属性,包含了指向构造函数 prototype 成员的引用。

原形(Prototype)

对象包含一个隐含的连接属性。这个连接指向对象构造函数的原形成员。

当对象的元素通过点号或下标获取的时候,如果元素没有在对象找到,此时就会检查该连接。如果在连接对象中仍然没有找到,并且该连接对象自身也有连接对象,那么会继续递归搜索这个连接对象。如果在整个连接链都没有找到,将会返回 undefined。

这种使用原形链的方式提供了一种继承的方式。

可以通过复制给一个原形添加成员。这里我们定义了一个新的类 Demo,它从它的祖先 Ancesotr继承,并且添加了一个它自身的函数 foo。

    function Demo(){}
    Demo.prototype = new Ancestor();
    Demo.prototype.foo = function(){};

变量

有名变量通过 var 表达式声明。当使用在函数里面,var 定义的变量的作用域为函数作用域。这些变量不能在函数外部访问。在 Javascript 里没有其它的作用域区间粒度。也就是说,没有块区间(block-scope)。

任何在函数中使用,但是没有通过 var 定义的变量都认为是属于外层作用域,很可能是全局作用域。

如果变量没有显示的初始化,默认为 undefined。

变量是没有类型的。一个变量可以引用任何类型的对象,可以是一个字符串或者一个数字或者 null 或 undefined。

函数的每次调用都回创建一组新的变量。这样,函数就允许递归调用。

作用域(Closure)

函数可以定义在其它函数之内。内部函数可以访问外部函数的变量或参数。如果对于内部函数的应用有效(比方说一个回调函数),那么外层函数的变量仍然有效。

返回

JavaScript 没有 void 类型,所以任何函数都必须返回一个值。除了构造函数默认返回的是 this ,其它函数默认的值为undefined。

关键字(Statements)

关键字包括 var, if, switch, for, while, do, break, continue, return, try, throw, 和 with。他们大多数都和其它 类C 语言的作用相似。

var 关键字语序一系列由逗号隔开的变量名和可选的初始化表达式。

    var a,b = window.document.body;

如果 var 关键字出现在函数外部,它将为全局对象添加一个成员。如果它出现在一个函数里面,它将为函数定义一个局部变量。

对于 if, while, do 和逻辑操作符,Javascript 将判断 false, null, undefined, ""(空字符串)和 数字0为 false。其它所有值都将认为是true。

使用在 switch 关键字里的 case  标签可以跟一个表达式,不必是常量,可以使字符串。

for 关键字有两种形式。第一种是普通的 (init; test; inc) 的形式。第二种是对象遍历的形式。

    for ( name in object){
        value = object [ name ];
    }

这个程序块将遍历对象的没有属性名。属性名出现的顺序是不可知的。

关键字可以有一个标签前缀,用于标识关键字,使用冒号隔开。

最好不要使用 with 关键字。

操作符

JavaScript 用于一个相当大的操作符集合。他们大部分和类 C 语言的操作符相似。只有一小部分需要额外注意。

“+" 操作符用于加法操作和串联操作。如果任意一个操作数是字符串,它将执行串联操作。这会引起一些俄问题。比方说,‘$' + 3 + 4 结果是 ‘$34',而不是’$7'。

"+" 也可以是一个前缀操作符,转化字符串操作符为数字。

“!!" 是一个前缀操作符,转化它的操作数为boolean型。

“&&"操作符通常叫做逻辑与。它也可以叫做守卫(guard)。如果第一个操作数为 false, null, undefined, ""(空字符串),或者数字 0, 它将返回第一个操作数。否则,它将返回第二个操作数。这就使空值检查变得很容易。

    var value = p && p.name /* name 的值仅在 p 有值得情况下才会被引用。这样就可以避免错误*/

“||”操作符通常叫做逻辑或。也叫做默认值(default)。如果第一个操作数为 false,null,undefined,“”(空字符串),或者数字 0,它将返回第二个操作数。否则,它将返回第一个操作数。这使得定义默认值非常方便。

    var = v || 10; /* 如果 v 有值使用 v,否则使用 10 */

JavaScript 提供了一些列位移和位处理操作符,但是没有整型变量与之对应。在作用于一个数字操作数(64位的浮点数字)之前,将会把它转化为32位的整型,预算结束将在转化为浮点数。

在JavaScript里,void 是一个前缀操作符,而不是一个类型。它总是返回 undefined。这没有什么太多的作用。我仅仅是为了你不会因为偶尔习惯性的输入 void 而为它的行为感到奇怪,提示了它一下。

“typeof” 操作符会根据操作数的类型返回一个字符串。
红色标示引起错误
Object 'object'
Array 'object'
Function 'function'
String 'string'
Number 'number'
Boolean 'boolean'
null 'object'
undefined 'undefined'

<-- 待续 -->
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值