JavaScript内核之基本概念_基础知识

本章主要讲述JavaScript中的数据类型(基本类型与引用类型),变量(包括变量的作用域),操作符(主要是一些较为常见,但是不容易从字面上理解的操作符)。由于JavaScript中的“一切皆对象”,在掌握了这些基本的概念之后,读者就可以较为轻松的理解诸如作用域,调用对象,闭包,currying等等较难理解的概念了。

数据类型

有程序设计经验的读者肯定知道,在C或者Java这样的语言中,数据是有类型的,比如用以表示用户名的属性是字符串,而一个雇员的年龄则是一个数字,表示UI上的一个开关按钮的数据模型则为布尔值等等,对数字可能还可以细分为浮点数,整型数,整型数又可能分为长整型和短整型,总而言之,它们都表示语言中的数据的值的类型。

JavaScript中的数据类型分为两种:基本数据类型和对象类型,其中对象类型包含对象,数组,以及函数(事实上,函数,数组等也都是对象,这个在后边的章节详述)。

1.1.1 基本数据类型

在JavaScript中,包含三种基本的数据类型,字符串(String),数值(Number),布尔值(boolean),下面是一些简单的例子:

复制代码 代码如下:

var str = "Hello, world";//字符串
var i = 10;//整型数
var f = 2.3;//浮点数

var b = true;//布尔值

我们可以分别查看变量的值及变量的类型:

复制代码 代码如下:

print(str);
print(i);
print(f);
print(b);

print(typeof str);
print(typeof i);
print(typeof f);
print(typeof b);

注意,在此处使用的print()函数为rhino解释器的顶层对象的方法,可以用来打印字符串,通常情况下,在客户端,程序员多使用alert()进行类似的动作,alert()是浏览器中JavaScript解释器的顶层对象(window)的一个方法。

Hello, world
10
2.3
true

string
number
number
Boolean
在JavaScript中,所有的数字,不论是整型浮点,都属于“数字”基本类型。typeof是一个一元的操作符,在本章的另外一个小节会专门讲到。

1.1.2 对象类型

这里提到的对象不是对象本身,而是指一种类型,我们在第三章会对对象进行详细的讨论,此处的对象包括,对象(属性的集合,即键值的散列表),数组(有序的列表),函数(包含可执行的代码)。

对象类型是一种复合的数据类型,其基本元素由基本数据类型组成,当然不限于基本类型,比如对象类型中的值可以是其他的对象类型实例,我们通过例子来说明:

复制代码 代码如下:

var str = "Hello, world";
var obj = new Object();
obj.str = str;
obj.num = 2.3;

var array = new Array("foo", "bar", "zoo");

var func = function(){
print("I am a function here");
}

可以看到,对象具有属性,如obj.str, obj.num,这些属性的值可以是基本类型,事实上还可以更复杂,我们来看看他们的类型:

复制代码 代码如下:

print(typeof obj);
print(typeof array);
print(typeof func);

//将打印出
object
object
function

读者可能会对print(typeof array)打印出object感到奇怪,事实上,对象和数组的界限并不那么明显(事实上它们是属于同一类型的),但是他们的行为却非常不同,本书的后续章节将两个重要的数据类型做了分别介绍。

2.1.3 两者之间的转换

类似与Java中基本数据类型的自动装箱拆箱,JavaScript也有类似的动作,基本数据类型在做一些运算时,会临时包装一个对象,做完运算后,又自动释放该对象。我们可以通过几个例子来说明:

复制代码 代码如下:

var str = "JavaScript Kernal";
print(str.length);//打印17

str为一个字符串,通过typeof运算符可知其type为”string”,而:

复制代码 代码如下:

var str2 = new String("JavaScript Kernal");
print(typeof str2);

可知,str2的type为”object”,即这两者并不相同,那么为什么可以使用str.length来的到str的长度呢?事实上,当使用str.length时,JavaScript会自动包装一个临时的String对象,内容为str的内容,然后获取该对象的length属性,最后,这个临时的对象将被释放。

而将对象转换为基本类型则是通过这样的方式:通过调用对象的valueOf()方法来取得对象的值,如果和上下文的类型匹配,则使用该值。如果valueOf取不到值的话,则需要调用对象的toString()方法,而如果上下文为数值型,则又需要将此字符串转换为数值。由于JavaScript是弱类型的,所以JavaScript引擎需要根据上下文来“猜测”对象的类型,这就使得JavaScript的效率比编译型的语言要差一些。

valueOf()的作用是,将一个对象的值转换成一种合乎上下文需求的基本类型,toString()则名副其实,可以打印出对象对应的字符串,当然前提是你已经“重载”了Object的toString()方法。

事实上,这种转换规则会导致很多的问题,比如,所有的非空对象,在布尔值环境下,都会被转成true,比如:

复制代码 代码如下:

function convertTest(){
if(new Boolean(false) && new Object() &&
new String("") && new Array()){
print("convert to boolean")
}
}
convertTest();//convert to Boolean

初学者容易被JavaScript中的类型转换规则搞晕掉,很多情况下会觉得那种写法看着非常别扭,其实只需要掌握了规则,这些古怪的写法会大大的提高代码的性能,我们通过例子来学习这些规则:

复制代码 代码如下:

var x = 3;
var y = x + "2";// => 32
var z = x + 2;// => 5

print(y);
print(z);

通常可以在JS代码中发现这样的代码:

复制代码 代码如下:

if(datamodel.item){
//do something...
}else{
datamodel.item = new Item();
}

这种写法事实上具有更深层次的含义:

应该注意到,datamodel.item是一个对象(字符串,数字等),而if需要一个boolean型的表达式,所以这里进行了类型转换。在JavaScript中,如果上下文需要boolean型的值,则引擎会自动将对象转换为boolean类型。转换规则为,如果该对象非空,则转换为true,否则为false.因此我们可以采取这种简写的形式。

而在传统的编程语言(强类型)中,我们则需要:

复制代码 代码如下:

if(datamodel.item != null){
//do something...
}else{
datamodel.item = new Item();
}

2.1.4类型的判断

前面讲到JavaScript特性的时候,我们说过,JavaScript是一个弱类型的语言,但是有时我们需要知道变量在运行时的类型,比如,一个函数的参数预期为另一个函数:

复制代码 代码如下:

function handleMessage(message, handle){
return handle(message);
}

当调用handleMessage的函数传递的handle不是一个函数则JavaScript引擎会报错,因此我们有必要在调用之前进行判断:

复制代码 代码如下:

function handleMessage(message, handle){
if(typeof handle == "function"){
return handle(message);
}else{
throw new Error("the 2nd argument should be a function");
}
}

但是,typeof并不总是有效的,比如下面这种情况:

复制代码 代码如下:

var obj = {};
var array = ["one", "two", "three", "four"];

print(typeof obj);//object
print(typeof array); //object

运行结果显示,对象obj和数组array的typeof值均为”object”,这样我们就无法准确判断了,这时候,可以通过调用instanceof来进行进一步的判断:

print(obj instanceof Array);//false
print(array instanceof Array);//true
第一行代码返回false,第二行则返回true。因此,我们可以将typeof操作符和instanceof操作符结合起来进行判断。

2.2 变量

变量,即通过一个名字将一个值关联起来,以后通过变量就可以引用到该值,比如:

复制代码 代码如下:

var str = "Hello, World";
var num = 2.345;

当我们下一次要引用”Hello, Wrold”这个串进行某项操作时,我们只需要使用变量str即可,同样,我们可以用10*num来表示10*2.345。变量的作用就是将值“存储”在这个变量上。

2.2.1基本类型和引用类型

在上一小节,我们介绍了JavaScript中的数据类型,其中基本类型如数字,布尔值,它们在内存中都有固定的大小,我们通过变量来直接访问基本类型的数据。而对于引用类型,如对象,数组和函数,由于它们的大小在原则上是不受任何限制的,故我们通过对其引用的访问来访问它们本身,引用本身是一个地址,即指向真实存储复杂对象的位置。

基本类型和引用类型的区别是比较明显的,我们来看几个例子:

复制代码 代码如下:

var x = 1;//数字x,基本类型
var y = x;//数字y,基本类型
print(x);
print(y);

x = 2;//修改x的值

print(x);//x的值变为2
print(y);//y的值不会变化

运行结果如下:

1

1

2

1

这样的运行结果应该在你的意料之内,没有什么特别之处,我们再来看看引用类型的例子,由于数组的长度非固定,可以动态增删,因此数组为引用类型:

复制代码 代码如下:

var array = [1,2,3,4,5];
var arrayRef = array;

array.push(6);
print(arrayRef);

引用指向的是地址,也就是说,引用不会指向引用本身,而是指向该引用所对应的实际对象。因此通过修改array指向的数组,则arrayRef指向的是同一个对象,因此运行效果如下:

1,2,3,4,5,6

2.2.2变量的作用域

变量被定义的区域即为其作用域,全局变量具有全局作用域;局部变量,比如声明在函数内部的变量则具有局部作用域,在函数的外部是不能直接访问的。比如:

复制代码 代码如下:

var variable = "out";

function func(){
var variable = "in";
print(variable);//打印”in”
}

func();
print(variable);//打印”out”

应该注意的是,在函数内var关键字是必须的,如果使用了变量而没有写var关键字,则默认的操作是对全局对象的,比如:

复制代码 代码如下:

var variable = "out";

function func(){
variable = "in";//注意此variable前没有var关键字
print(variable);
}

func();
print(variable);//全局的变量variable被修改

由于函数func中使用variable而没有关键字var,则默认是对全局对象variable属性做的操作(修改variable的值为in),因此此段代码会打印:

in

in

2.3运算符

运算符,通常是容易被忽略的一个内容,但是一些比较古怪的语法现象仍然可能需要用到运算符的结合率或者其作用来进行解释,JavaScript中,运算符是一定需要注意的地方,有很多具有JS编程经验的人仍然免不了被搞得晕头转向。

我们在这一节主要讲解这样几个运算符:

2.3.1中括号运算符([])

[]运算符可用在数组对象和对象上,从数组中按下标取值:

复制代码 代码如下:

var array = ["one", "two", "three", "four"];
array[0]

而[]同样可以作用于对象,一般而言,对象中的属性的值是通过点(.)运算符来取值,如:

复制代码 代码如下:

var object = {
field : "self",
printInfo : function(){
print(this.field);
}
}

object.field;
object.printInfo();

但是考虑到这样一种情况,我们在遍历一个对象的时候,对其中的属性的键(key)是一无所知的,我们怎么通过点(.)来访问呢?这时候我们就可以使用[]运算符:

复制代码 代码如下:

for(var key in object){
print(key + ":" + object[key]);
}

运行结果如下:

field:slef
printInfo:function (){
print(this.field);
}
2.3.2点运算符(.)

点运算符的左边为一个对象(属性的集合),右边为属性名,应该注意的是右边的值除了作为左边的对象的属性外,同时还可能是它自己的右边的值的对象:

复制代码 代码如下:

var object = {
field : "self",
printInfo : function(){
print(this.field);
},
outter:{
inner : "inner text",
printInnerText : function(){
print(this.inner);
}
}
}

object.outter.printInnerText();

这个例子中,outter作为object的属性,同时又是printInnerText()的对象。

2.3.3 == 和 === 以及 != 和 !==

运算符==读作相等,而运算符===则读作等同。这两种运算符操作都是在JavaScript代码中经常见到的,但是意义则不完全相同,简而言之,相等操作符会对两边的操作数做类型转换,而等同则不会。我们还是通过例子来说明:

print(1 == true);
print(1 === true);
print("" == false);
print("" === false);

print(null == undefined);
print(null === undefined);
运行结果如下:

复制代码 代码如下:

true
false
true
false
true
false

相等和等同运算符的规则分别如下:

相等运算符

如果操作数具有相同的类型,则判断其等同性,如果两个操作数的值相等,则返回true(相等),否则返回false(不相等).

如果操作数的类型不同,则按照这样的情况来判断:

◆ null和undefined相等

◆ 其中一个是数字,另一个是字符串,则将字符串转换为数字,在做比较

◆ 其中一个是true,先转换成1(false则转换为0)在做比较

◆ 如果一个值是对象,另一个是数字/字符串,则将对象转换为原始值(通过toString()或者valueOf()方法)

◆ 其他情况,则直接返回false

等同运算符

如果操作数的类型不同,则不进行值的判断,直接返回false

如果操作数的类型相同,分下列情况来判断:

◆ 都是数字的情况,如果值相同,则两者等同(有一个例外,就是NaN,NaN与其本身也不相等),否则不等同

◆ 都是字符串的情况,与其他程序设计语言一样,如果串的值不等,则不等同,否则等同

◆ 都是布尔值,且值均为true/false,则等同,否则不等同

◆ 如果两个操作数引用同一个对象(数组,函数),则两者完全等同,否则不等同

◆ 如果两个操作数均为null/undefined,则等同,否则不等同

比如:

复制代码 代码如下:

var obj = {
id : "self",
name : "object"
};

var oa = obj;
var ob = obj;

print(oa == ob);
print(oa === ob);

会返回:

true

true

再来看一个对象的例子:

复制代码 代码如下:

var obj1 = {
id : "self",
name : "object",
toString : function(){
return "object 1";
}
}

var obj2 = "object 1";

print(obj1 == obj2);
print(obj1 === obj2);

返回值为:

true

false

obj1是一个对象,而obj2是一个结构与之完全不同的字符串,而如果用相等操作符来判断,则两者是完全相同的,因为obj1重载了顶层对象的toString()方法。

而!=不等和!==不等同,则与==/!==相反。因此,在JavaScript中,使用相等/等同,不等/不等同的时候,一定要注意类型的转换,这里推荐使用等同/不等同来进行判断,这样可以避免一些难以调试的bug。

时间: 2024-10-27 08:35:50

JavaScript内核之基本概念_基础知识的相关文章

JavaScript操作Cookie详解_基础知识

什么是 Cookie "cookie 是存储于访问者的计算机中的变量.每当同一台计算机通过浏览器请求某个页面时,就会发送这个 cookie.你可以使用 JavaScript 来创建和取回 cookie 的值." - w3school cookie 是访问过的网站创建的文件,用于存储浏览信息,例如个人资料信息. 从JavaScript的角度看,cookie 就是一些字符串信息.这些信息存放在客户端的计算机中,用于客户端计算机与服务器之间传递信息. 在JavaScript中可以通过 doc

JavaScript方法和技巧大全_基础知识

这篇介绍JavaScript方面的日志,我在是Clang上看到的.作者介绍挺全面的,所以转载过来让感兴趣的朋友看一下.呵呵--- 有些时候你精通一门语言,但是会发现你其实整天在和其它语言打交道,也许你以为这些微不足道,不至于影响你的开发进度,但恰恰是这些你不重视的东西会浪费你很多时间,我一直以为我早在几年前就已经精通JavaScript了,直到目前,我才越来越觉得JavaScript远比我想象的复杂和强大,我开始崇拜它,就像崇拜所有OOP语言一样- 趁着节日的空隙,把有关JavaScript的方

学习JavaScript的最佳方法分享_基础知识

学习新的东西是件可怕的事.对我来说,掌握一项新技能最大的问题是,我不知道自己懂什么.鉴于此,定个计划,学习你感兴趣的东西应该会有用.这篇文章的主旨就是:你为学习JavaScript 制定的蓝图.路线.行动计划!你不必担心找不到最好的资源,先整理些不好的资源,再确定下一步该学什么.遵循它,一步一步来. 任务0:了解什么是JavaScript 在你真正开始学习JavaScript 之前,花一分钟了解一下什么是JavaScript,它有哪些功能. JavaScript不是jQuery.Flash或Ja

JavaScript中的this机制_基础知识

JavaScript有自己的一套this机制,在不同情况下,this的指向也不尽相同. 全局范围 console.log(this); //全局变量 全局范围使用this指向的是全局变量,浏览器环境下就是window. 注:ECMAScript5的strict模式不存在全局变量,这里的this是undefined. 函数调用中 function foo() { console.log(this); } foo(); //全局变量 函数调用中的this也指向全局变量. 注:ECMAScript5的

使用JavaScript刷新网页的方法_基础知识

 可以使用JavaScript location.reload方法刷新网页.当用户点击一个链接此代码可以自动在一个事件调用. 如果想使用鼠标点击刷新网页,可以用下面的代码: <a href="javascript:location.reload(true)">Refresh Page</a> 要了解它更好的办法,可以刷新页面自动刷新: 还可以使用JavaScript后自动给定时间段,以刷新页面.以下是每5秒后会刷新此页面的例子.可以改变这个时候按您的要求. &l

详解JavaScript中的异常处理方法_基础知识

 有三种类型的编程错误:(1)语法错误和(2)运行时错误(3)逻辑错误:语法错误: 语法错误,也被称为解析错误,在编译时进行传统的编程语言,并出现在JavaScript解释时. 例如,下面一行将导致一个语法错误,因为它缺少一个右括号: <script type="text/javascript"> <!-- window.print(; //--> </script> 当一个语法错误在JavaScript中出现,只有在同一个线程中包含的语法错误的影响

介绍JavaScript的一个微型模版_基础知识

 我一直在使用一个小工具,并发现它在构建Javascript应用过程中非常实用.它是一个非常简单的模板函数,速度快,支持缓存,并容易使用.我想分享一下使用它的过程中的一些技巧. 以下是模板函数的代码(你可以从正要出版的Secrets of the JavaScript Ninja一书中得到更精炼的版本):   // 简单JavaScript模板引擎 // John Resig - http://ejohn.org/ - MIT Licensed (function(){ var cache =

大型JavaScript应用程序架构设计模式_基础知识

PDF版的PPT下载地址:http://www.slideshare.net/jibyjohnc/jqquerysummit-largescale-javascript-application-architecture 注:在整理的过程中,发现作者有些思想是返来复去地说,所以删减了一部分,如果你的英文良好,请直接阅读英文的PPT. 以下是本文的主要章节: 1. 什么叫"JavaScript大型程序"? 2. 顾当前的程序架构 3. 长远考虑 4. 头脑风暴 5. 建议的架构    5.

JavaScript核心语法总结(推荐)_基础知识

本文介绍了JavaScript的基本(常用)语法,供大家参考. Overview 先说一下Javascript该怎么写.两种形式,一种是直接把JavaScript写在HTML页面里,另一种是存在*.js文件里然后在页面内引用. 直接写时,即可以放在<head> </head>内,也可以放在<body> </body>内.一般函数是放在<head>区的,具体的执行代码是在<body>区里的.例如,在body里写: <body>