JavaScript大杂烩1 - 理解JavaScript的类型系统

  随着硬件水平的逐渐提高,浏览器的处理能力越来越强大,本人坚信,客户端会越来越瘦,瘦到只用浏览器就够了,服务端会越来越丰满;虽然很多大型的程序,比如3D软件,客户端仍然会存在,但是未来的主流必将是浏览器,也就是Web程序/网站。

Web前端开发模式:Thinking in "DIV + CSS + JS (JavaScript)"

  任何面向用户的程序,最终都表现为3个部分:界面,逻辑,数据。而经过几十年的编程实践,大家都发现,当把这3个部分以弱耦合的形式结合起来的时候,开发的灵活性和效率最好,而且这种形式的程序应对变化的能力也比较强。这条原则在Web前端开发中就体现为"DIV
+ CSS + JS"的分离与开发。

  对照上面的3个部分,我们很容易找到对应的关系:以DIV为代表的HTML构成网页上面的数据,CSS控制界面的显示效果,JavaScript执行网页的逻辑。这3个部分可以互不干扰,独立进行开发,为Web的程序设计和团队合作带来了无与伦比的灵活性。

  这个系列是以总结JavaScript开发为主,涉及到另外两个方面的内容都是简单的提及一下。

浏览器的兼容性

  JavaScript是运行在浏览器中的,但是由于各家软件公司,像微软,并不按照规定的套路出牌,不去执行相关的标准去实现浏览器的行为,所以JavaScript从诞生那天起,在不同的浏览器中就充满着兼容性问题。不过还好,渐渐的大家都服从相同的ECMAScript标准了,兼容性的问题得到了一定的缓解,不过在很多时候还是值得我们去注意。
  从某种意义上说,各种JavaScript类库的出现一方面是为了重用更多的功能,另一方面也是为了更好的屏蔽浏览器的兼容性问题,本质上其实都还是重用,这是计算机技术向前发展的动力。
  所以很多时候,我们进行Web开发的时候,选择合适的类库不仅能快速开发出我们想要的功能,还能够最大程度的减少浏览器的兼容性问题。

JavaScript的组成部分

  简单的来说,JavaScript就是这样的:

JavaScript = ECMAScript (语言标准) +
DOM (Document Object Model,文档内容的建模对象) +
BOM (Browser Object Model,浏览器的建模对象)

ECMAScript规范:
这个不用多说,就是语法规范,这个是JavaScript编程的基石。

DOM: 这个是JavaScript的重点,我们学了那么多,就是为了要为HTML提供逻辑功能,从HTML元素抽象出来的DOM自然是重中之重。

BOM: JavaScript是运行在浏览器中的,与浏览器打交道是必须的,但是通常不会很频繁。

基本类型

  从语言的类型来说,JavaScript是一门脚本语言,是动态语言,特点就是不需要编译,直接解释执行。
  动态语言也有基本的类型系统,而且通常比较简单,这一点在JavaScript中体现最为明显。
  通常来说,JavaScript定义了如下6种基本类型:
1.
number
  这是一切数字类数据的类型,包括浮点数(如0.1),整数(如10),还有像NaN这样的特殊值。

  NaN代表非法的数字,这个值通常是在将一个类型转换成数字失败以后返回的数值。

  此外,与别的编程语言一样,也可以使用十六进制或八进制表示数字,比如0xFF, 012等。
2. string

  
这个类的重要性就不需重复了,不过需要注意,在JavaScript中,既可以用双引号""定义字符串,也可以用单引号‘‘定义字符串。但是考虑到HTML中的属性大多用双引号定义属性,所以在JavaScript中习惯上只用单引号定义字符串。
3.
boolean
  这个类型很简单,只有true和false两个值。
4.
object
  这个类型是JavaScript的基石,因为JavaScript是面向对象的语言,object就是整个类型系统的根,其他的所有类型都是对象,并且都是直接或者间接的从object继承而来。
  object类型有一个特殊的值null,代表对象的值是空值。
5.
function
  这个类型时JavaScript的第一等成员,它构成了JavaScript编程的主旋律,function类型作为一种基元类型,可以使用在任何数据类型可以出现的场合,比如变量,参数,返回值等等。不用怀疑,function是从object继承来的。
6.
undefined
  这个类型比较特别,它只有一个值,就是undefined。它代表已经声明,但还没有赋值的数据。任何的数据类型,只要声明了,没赋值,那么这个变量的类型就是undefined,值就是undefined。

  动态语言的变量不要求像静态语言那样,严格的定义类型,然后使用;在JavaScript中,一切类型都由var来定义,不需要指定类型。没有指定类型,就决定了定义的变量的类型取决于赋值的数据的类型。下面例子给出了常见的用法:

var age = 10; // number
var name = ‘Frank‘; // string
var married = false; // boolean
var obj = new object(); // object
var fun = function() { alert(‘Hi‘);}; // function
var extend; // undefined

  这些类型定义很简单,使用起来也与别的语言没什么区别,但是有几点还是需要注意的:

1.
空串,NaN,null,undefined的辨析
  空串很简单,其类型string类型,值为‘‘。
  NaN也很简单,其类型为number类型,值为NaN。只不过NaN与任何值都不相等,即使是与NaN自身也不相等,判断一个值是否是NaN的唯一方式就是使用全局的isNaN()方法。
  null也很简单的,其类型为object类型,值为null。
  undefined最简单,其类型为undefined类型,值为undefined。
  这些相似的东西很多时候是相似的,比如在if语句的条件表达式中,不过只要我们记住了它们的类型,那么在下面的全等运算符(===)面前,它们是无所遁形的
2.
类型之间的转换
  类型转换的方式主要有下面几种:
  1).
使用全局方法:String(),Number(),parseInt(),parseDouble()等等。
  2).
使用对象的方法:比如所有对象转成string类型都可以使用object内置的toString()方法。
  3). 使用运算符:
比如所有对象转成string类型的间接方式: var s = ‘‘ + obj;其本质上与第二个方法是一样的。
  4). 使用new操作:
比如new String(),new
Number()等等。
  从上面我们看到了两种类型,以字符串类型为例,一种是string类型,一种是String类型,因为JavaScript是区分大小写的,这两种不是同一种类型。如何理解这种现象呢?有C#背景的同学可能比较熟悉值类型与引用类型的区别,实际上在JavaScript中也存在类似情况,string作为基本的类型,算是一种与值类型相当的类型,而String是作为string的包装类型存在,是完整的与引用类型相当的类型。
  所以使用new
String()的方式得到的字符串会与普通的使用‘‘定义的字符串会有那么一点不同,比如在命令行(浏览器的调试工具)中本别输入:

String(10) 输出的结果是"10"
new String(10) 输出的结果是String {0: "1", 1: "0", length: 2}

  通常我们不会使用第四种转换方式去强行构造一个字符串对象。

  此外需要注意Number()与parseInt()处理的过程是不一样的,Number(‘10a‘)会返回NaN,而parseInt(‘10a‘)会返回10。
3.
其它类型到boolean类型的转换
  boolean类型是比较特殊的,因为很多的语句(比如if,while等等)都要使用boolean值。其他类型转换成boolean类型的显式方式是Boolean()方法。但是我们还是要了解一下,哪些值会转成true,哪些值会转成false。
  除了‘‘,null,undefined,0,NaN这几个值会转成false以外,其它的所有值都会转成true。

基本运算
  看完基本类型,我们再看看基本的运算,这个和其他语言没什么区别,基本的数学运算(+,-,*,/,+=,-=,*=,/=),取模(%,%=),赋值(=),判等(<,>,==,!=),取反(-),自增自减(++,--),唯一的三元条件运算符(?:)等等都是一样的。
  但是,在JavaScript中,有几个运算符与别的语言是有些区别:
1.
全等(===),不全等(!===)
  全等代表着类型和值都相等,不全等代表着类型或值不相等,细细辨别下面这些语句的不同:

alert(null == undefined); // true
alert(null === undefined); // false

  结论是我们需要判等的时候,尽量使用全等运算===,而不是普通的相等运算==。

2.
逻辑运算符(&&,||,!)
  这些运算符的第一层用法就是判断一组boolean类型的逻辑运算结果,当然其他的类型的值可以先转成boolean后参与运算。
  这个运算符的第二层用法就是像下面这种常见的写法:

var Common = Common || {};

  这种用法是确保Common被初始化了,然后可以作为一种namespace使用,这个在后面对象的总结中还会提及到。

  结合起来,其实可以简单总结为:

||是这样运算的:从第一个操作数开始,遇到有意义的操作数就返回,否则返回最后一个表达式(不一定是boolean值);
&&是这样运算的:从第一个操作数开始,遇到无意义的操作数返回,否则返回最后一个表达式(注意同上);
!是这样运算的:对表达式的值取非(注意不是对表达式)。

  无意义的值指的就是‘‘,null,undefined,0,NaN这几个与false等价的值。

3. 位运算符(&,|,^,
>>,<<,>>>)
  这几个运算符中前4个没什么可说的,关键就是最后这个个无符号右移位操作:

expression1 >>> expression2

  >>> 运算符将 expression1 的位右移
expression2
中指定的位数,用零填充右移后左边空出的位,这是它与>>最大的不同(>>会保持符号,如果第一位是1的话,右移还是用1填充左边),
右移的位被丢弃。

4. undefined参与运算
  这是一个特殊的类型,导致参与运算的结果也比较特别,品味下面的例子:

undefined + 1; // 结果为NaN
undefined + ‘‘; // 结果为‘undefined‘

  所以一旦程序中出现undefined的话,往往会出现一些奇怪的问题,所以程序中要特别注意出现undefined的情况。

  此外,JavaScript的基本语句与别的C系语言也相同,比如if,switch,return,for,while,break,continue,包括注释(//,/*...*/)等等,这里就不多说了。

自动垃圾回收机制
  JavaScript是使用自动垃圾回收机制的,这个有C#或者Java这些语言背景的同学还是比较清楚的。原理也是差不多,没有再被有效引用的变量会自动被当做垃圾回收掉。如何辨别一个变量是不是垃圾有很多方法,常用的是标记清楚和引用计数两种方法,“标记清除”是目前主流的垃圾回收算法,这种算法的思想是给当前不使用的值加上标记,然后再回收其内存。“引用计数”算法的思想是跟踪记录所有值被引用的次数。JavaScript引擎不再使用“引用计数”这种算法;但在较低版本的IE(较高版本中据说已修复,不过我不用IE久矣)中访问非原生JavaScript对象(如DOM元素),还是使用这种垃圾收集的。
  当代码中存在循环引用现象时,“引用计数”算法就会导致内存泄露问题。比如:

var a = {name:‘a‘};
var b = {name:‘b‘};
a.bname = b
b.aname = a;

  这种和数据库死锁差不多的的情况还好,至少说程序员不会有意为之。但是下面这种情况在IE中却是普遍存在的:

$(document).ready(function() {
var div = document.getElementById("mydiv");
div.onclick = function(){
console.log("div");
};
});

  这个是网上某位仁兄给出的例子,据说当指定的单击事件处理程序时,创建了一个在其封闭的环境中包含div变量的闭包环境。而div也包含一个指向闭包的引用(onclick属性自身),这就导致了内存都不能得到释放。当然解决方法很简单:


$(document).ready(function() {
var div = document.getElementById("mydiv");
div.onclick = divonclicked;
});

function divonclicked() {
console.log("div");
};

  此时因为divonclicked函数不在包含div的引用,所以没有形成循环,内存可以得到释放。

  可能很多人都知道将一个对象置为null,那么它的内存就会回收。这是因为变量的指向了一个null,那么它原来指向的那块内存空间就会因为没有被指向,或者说没有被引用,而被垃圾回收掉,这种做法在JavaScript中仍然适用。
  上面的例子姑且不管现在存不存在,总的来说,为了避免这些内存泄露的情况,方法就是少用IE,然后是多注意闭包中引用HTML对象的情况,在大部分情况下自动垃圾回收是没有太大问题的。

Client端JavaScript与Server端JavaScript
  JavaScript发展至今,已经不再仅仅满足于活动在浏览器端了,它把触角已经伸向了后面的服务器端,这对程序猿来说应该是好事,因为只要学好JavaScript,就可以前后通吃了。不过大家还是要注意,后端的JavaScript完全可以称之为全新的编程语言,不能再以老的对待浏览器中的JavaScript的眼光去看待它了。
  浏览器端的JavaScript由于运行在浏览器的这个沙箱中,所以它不可能有多么大的权限。它的主要职责就是操作浏览器中的对象,完成相应的逻辑功能。即使存在各种类库,但是本质上还是没有脱离浏览器的限制。
  但是服务器端的JavaScript中,例如在NodeJs环境中,JavaScript是作为一门独立的语言存在的,它与C#等语言一样,拥有各种丰富的各种类库,去完成丰富的功能,比如读取文件,开启线程等等,这些特性与浏览器端的JavaScript已经完全不可同日而语了。

  这个系列的重点是在Client端的JavaScript,这里的基础知识对Server端的JavaScript完全是适用的。

时间: 2024-10-22 18:55:23

JavaScript大杂烩1 - 理解JavaScript的类型系统的相关文章

JavaScript大杂烩6 - 理解JavaScript中的this

在JavaScript开发中,this是很常用的一个关键字,但同时也是一个很容易引入bug的一个关键字,在这里我们就专门总结一下页面中可能出现的this关键字(包括几种在其他页面文件中出现的this). JavaScript中的this关键字通常只使用在函数中,它指向当前函数的调用者,这是this关键字的本质,所有的使用方式都是围绕这个展开的,让我们来看一下在各种性质的函数中this的用法.1. 在对象的函数中使用this var person = { name: 'Frank', say: f

JavaScript大杂烩4 - 理解JavaScript对象的继承机制

面向对象之继承 JavaScript是单根的面向对象语言,它只有单一的根Object,所有的其他对象都是直接或者间接的从Object对象继承(没有指定父类的对象,都被认为是从Object继承的). 在前面我们讨论了面向对象的封装性,在最后的地方也谈到了JavaScript的继承是通过原型和原型链实现的,下面我们就详细的展开这个问题:JavaScript到底是如何实现继承的? 继承的本质 继承的本质是重用,从语法上来讲,继承就是"D是B"的描述,其中B是基类,描述共性,D是子类,描述特性

JavaScript大杂烩2 - 理解JavaScript的函数

JavaScript中的字面量 书接上回,我们已经知道在JavaScript中存在轻量级的string,number,boolean与重量级的String,Number,Boolean,而且也知道了之间的区别.这里补充一点,直接使用字面量定义的变量都是属于前一种类型,例如: var name = 'Frank'; 此外大多数的内置操作返回的也都是前一种类型,这是必须的. function是第一等公民 与别的语言不同,在JavaScript中,函数是作为数据类型存在的,所以函数具有数据的静态行为.

JavaScript大杂烩9 - 理解BOM

毫无疑问,我们学习JavaScript是为了完成特定的功能.在最初的JavaScript类型系统中,我们已经分析过JavaScript在页面开发中充当着添加逻辑的角色,而且我们知道JavaScript不仅仅包含基本的语法规范.下面我们就重点看一下JavaScript在页面中干的那些事.总的来说,JavaScript在页面端就干两件事:操作DOM与操作BOM (当然了向Server获取数据也是它的工作,不过获取到数据后还是回来干这两件事,大家对JavaScript最直接的印象应该就是各种光怪陆离的

JavaScript大杂烩12 - 理解Ajax

AJAX缘由 再次谈起这个话题,我深深的记得就在前几年,AJAX被炒的如火如荼,就好像不懂AJAX,就不会Web开发一样.要理解AJAX为什么会出现,就要先了解Web开发面临的问题. 我们先来回忆一下Web页面的申请过程,这个咱们在第一篇中就介绍过了:Web页面开发就是在无连接和无状态的HTTP协议上管理页面的状态.每次申请页面的时候,服务器都会返回完整的HTML文本(当然还有其他的文本文件),浏览器就负责解析这个文本并在浏览器中显示. 在这个过程中,不管当前页面的内容是不是都变化了,服务器都会

JavaScript大杂烩7 - 理解内置集合

JavaScript内置了很多对象,简单的类型如String,Number,Boolean (相应的"值类型"拥有相同的方法),复杂一点的如Function,Object,Array,它们支撑起来JavaScript编程的基石.由于Number与Boolean很简单,这里就不多说了,下面着重介绍其他的内置对象. 万物之源 - Object对象 JavaScript是单根的,唯一的根就是Object对象,这个对象提供了几个还是不错的方法,值得了解一下. 1. hasOwnProperty

JavaScript大杂烩8 - 理解文本解析的"黄金搭档"

文本解析"黄金搭档" - String与RegExp对象 文本解析是任何语言中最常用的功能,JavaScript中也是一样,而正则表达式作为最常用的方式,JavaScript也同样是支持的,下面就来看看字符串对象与正则表达式对象的配合. 字符串的恒定性 在正式开始讨论字符串对象的成员之前,我们需要了解一点,那就是:与C#一样,JavaScript 的字符串是不可变的(immutable),String对象定义的方法都不会改变字符串的内容.像toUpperCase这样的方法,返回的是全新

【JavaScript】深入理解JavaScript之强大的原型和原型链

由于JavaScript是唯一一个被广泛使用的基于原型继承的语言,所以理解两种继承模式的差异是需要一定时间的,今天我们就来了解一下原型和原型链. AD: hasOwnProperty函数: hasOwnProperty是Object.prototype的一个方法,它可是个好东西,他能判断一个对象是否包含自定义属性而不是原型链上的属性,因为hasOwnProperty 是 JavaScript 中唯一一个处理属性但是不查找原型链的函数. // 修改Object.prototype Object.p

深入理解JavaScript系列+ 深入理解javascript之执行上下文

http://www.cnblogs.com/TomXu/archive/2011/12/15/2288411.html http://blog.csdn.net/hi_kevin/article/details/37761919    深入理解javascript之执行上下文(execution context)