js基础篇——变量
a.变量类型
变量类型 | 构造函数 | 举例 |
类型检测typeof |
字符串 | function String() |
var t = "chua"; var m = new String("chua"); |
"string" |
数字 | function Number() |
var t = 12; var m = new Number(12); |
"number" |
布尔 | function Boolean() |
var t = false; var m = new Boolean(0); var m1 = new Boolean(false); |
"boolean" |
数组 | function Array() |
var t = [1,2,3]; var m = new Array(1,2,3); var m1 = new Array(3); m1[0] = 1; m1[1] = 2; m1[2] = 3; |
"object" |
对象 | function Object() |
var t = {name:"chua"}; var m = new Object({name:"chua"}); var m1 = new Object(); m1.name = "chua"; |
"object" |
Null |
无,表示不该有值(无效值) ,null 被认为是对象的占位符 |
var t = null; //注意小写 function m(name){ if(name == null){alert(name)} } m(null); //null |
"object" |
Undefined |
无,表示变量未初始化值 或函数中参数没有传递 |
var t = undefined;//小写 var tUn; alert(tUn);//undefined function m(name){ if(name == undefined){ alert("没有传递参数") } } m();//"没有传递参数" |
"undefined" |
函数(这算是一个 比较特殊的变量类型) |
function Function() |
var t = function(){}; //构造了一个名为t的函数 var m = new Function();/*t指向一个匿名函数, 目前Function无法构造拥有实体的函数 由此可见t和m根本就是两回事,不等价*/ //匿名函数的写法 (function(){}); //不加括号运算符会报语法错误 //一个小运用 (function(){alert(1)})(); //1,构建匿名函数并马上执行 (function(name){alert(name)})("chua"); //"chua",构建匿名函数并马上执行 |
"function" |
日期类型 | function Date() |
var t = new Date();//获取当前时间 var m = new Date("January 1,2000 22:00:00"); //设置一个时间 后面的备注会详细简介日期初始化的兼容写法 |
"object" |
正则类型 |
function RegExp(pattern, attributes) |
var t = /\d+/;//匹配一个或多个数字 var m = new RegExp("\\d+"); //更多正则表达式内容参考 http://blog.csdn.net/zaifendou/article/details/5746988 http://www.w3school.com.cn/jsref/jsref_obj_regexp.asp |
"object" |
Error类型 | function Error() |
var t = new Error("语法错误"); alert(t.message); //"语法错误" |
"object" |
注意:非广义对象类型(函数,数组都属于广义对象类型)构造函数构造出来的变量是一个特殊的对象,只是在和其他非广义对象类型比较的时候先转化为非广义对象类型在比较。所以
new String("chua") == "chua"; //true new String("chua") === "chua"; //false
Date初始化:
总的来说有三种初始化日期的方式得到了所有浏览器的支持:
1.字符串创建一个日期对象:
new Date("month dd,yyyy hh:mm:ss");
new Date("month dd,yyyy");
还有一种被各大浏览器支持的方式:
new Date("yyyy/monthN/dd hh:mm:ss")
2.多个数字参数创建日期对象:
new Date(yyyy,mth,dd,hh,mm,ss);//其中mtd取值是0-11
new Date(yyyy,mth,dd);
3.使用毫秒创建日期
new Date(ms);//参数表示的是需要创建的时间和 GMT时间1970年1月1日之间相差的毫秒数
各种函数的含义如下:
month:用英文 表示月份名称,大小写无所谓,从January到December,或Jan到Dec简写形式
monthN:整数月份,从1到12
mth:用整数表示月份,从0(1月)到11(12月)
dd:表示一个 月中的第几天,从1到31
yyyy:四位数表示的年份
hh:小时数,从0(午夜)到23(晚11点)
mm: 分钟数,从0到59的整数
ss:秒数,从0到59的整数
ms:毫秒数,为大于等于0的整数
对于那些个位数来说,写0x或x都可以
如:
new Date("January 1,2001 12:00:00");
new Date("January 1,2001");
new Date("2001/1/1 12:00:00")
new Date(2000,0,1,12,0,0);
new Date(2000,0,1);
new Date(978321600000);
上面的各种创建形式都表示2000年1月1日这一天。
未声明的变量使用除typeof 之外的其他运算符的话,会引起错误,因为其他运算符只能用于已声明的变量上。
表格中检测类型看出,typeof只是广义类型。如果想要检测出变量真正的类型,可以参考jQuery的做法
var core_toString = {}.toString; core_toString.call([]); //"[object Array]" core_toString.call({}); //"[object Object]" core_toString.call(function(){}); //"[object Function]" core_toString.call(1); //"[object Number]" core_toString.call(""); //"[object String]" core_toString.call(new Date()); //"[object Date]" core_toString.call(/\d+/); //"[object RegExp]" core_toString.call(new Error()); //"[object Error]"
b.原始类型
原始值与引用值
在ECMAScript 中,变量可以存放两种类型的值,即原始值和引用值。
原始值(primitive value)是存放在栈(stack)中的简单数据字段,也就是说,它们的值直接存储在变量访问的位置。 引用值(reference value)是存储在堆(heap)中的对象,也就是说,存储在变量出的值是一个指针(point),指向存储对象的内存处。
ECMAScript 有 5 种原始类型(primitive type),即 Undefined、Null、Boolean、Number 和 String
这5种类型有些关键点需要注意
undefined:
undefined有几个意义:变量定义(声明)但是没有赋值、函数调用中缺少的参数会被认为是undefined、当函数无明确返回值时返回的也是值 undefined
需要注意的是值 undefined 并不同于未定义(声明)的值。但是,typeof 运算符并不真正区分这两种值
var un; alert(typeof un); //"undefined" alert(typeof demo); //"undefined",变量demo并未定义
未定义的变量只能使用typeof这一个运算符,其他运算符都必须作用于已定义的变量
alert(demo2 == undefined); //会报错,因为demo2未定义
null:
null 则用于表示尚未存在的对象(在讨论 typeof 运算符时,简单地介绍过这一点)。如果函数或方法要返回的是对象,那么找不到该对象时,返回的通常是 null。
为什么 typeof 运算符对于 null 值会返回 "Object"。这实际上是 JavaScript 的历史遗留问题。现在,null 被认为是对象的占位符,从而解释了这一矛盾,但从技术上来说,它仍然是原始值。
值 undefined 实际上是从值 null 派生来的,因此 ECMAScript 把它们定义为相等的
alert(null == undefined); //"true"
布尔类型:
false 不等于 0,0 也可以在必要时被转换成 false,true和1同理。这样在 Boolean 语句中使用两者都是安全的。
alert(false == 0); //true alert(true == 1); //true alert(true == 11); //false alert(false == -1); //false
Number类型:
八进制字面量的首数字必须是 0,其后的数字可以是任何八进制数字(0-7);
十六进制的字面量,首位数字必须为 0,后面接字母 x,然后是任意的十六进制数字(0 到 9 和 A 到 F)。这些字母可以是大写的,也可以是小写的。
07; //7 011; //9 0xf; //15 0Xf; //15 0XF; //15
尽管所有整数都可以表示为八进制或十六进制的字面量,但所有数学运算返回的都是十进制结果
要定义浮点值,必须包括小数点和小数点后的一位数字(例如,用 1.0 而不是 1)
用科学计数法表示浮点数,可以把一个数表示为数字(包括十进制数字)加 e(或 E),后面加乘以 10 的倍数。
1.22e5; //122000 1.22e-5; //0.0000122
ECMAScript 默认把具有 6 个或 6 个以上前导 0 的浮点数转换成科学计数法。
几个特殊值也被定义为 Number 类型:
1. Number.MAX_VALUE 和 Number.MIN_VALUE,它们定义了 Number 值集合的外边界。所有 ECMAScript 数都必须在这两个值之间。不过计算生成的数值结果可以不落在这两个值之间。
2.无穷大Number.POSITIVE_INFINITY与无穷小Number.NEGATIVE_INFINITY。两者都表示值不再是数字了
使用isFinite() 判断数值是否是有限的。
isFinite(Number.NEGATIVE_INFINITY); //false isFinite(Number.POSITIVE_INFINITY ); //false isFinite(Number.MAX_VALUE); //true isFinite(11); //true
3.NaN,表示非数(Not a Number)。NaN 是个奇怪的特殊值。一般说来,这种情况发生在类型(String、Boolean 等)转换失败时。例如字符串"chua" 转换成数值就会失败,因为没有与之等价的数值。与无穷一样,NaN 也不能用于算术计算。NaN 的另一个奇特之处在于,它与自身不相等:
NaN == NaN; // false
出于这个原因,不推荐使用 NaN 值本身。使用函数 isNaN判断是否是非数值
alert(isNaN("chua")); // "true" alert(isNaN("666")); //"false"
String:
String类型是唯一没有固定大小的原始类型。
c.变量声明(这里把函数类型也看成一个变量)
JS中变量声明分显式声明和隐式声明。
显示声明指使用使用var开头的声明(函数声明除外)。
var t; //声明一个变量为t function m(){}; //声明一个名为m的函数
隐式声明指没有使用var明确声明的变量。
a = 1;
需要注意的是隐式声明并不是在执行代码之前的声明中声明变量的,而是当执行到该代码段时没有查找到该变量,然后创建一个该作用域下的一个变量的,所以如果在变量表达式之前使用该变量则会报变量未定义的错误。
alert(b); //报错,b未定义 b = 1; //声明变量b,并给b赋值为1 alert(b); //1
所以隐式声明是该语言的便利之处,不过如果不能紧密跟踪变量,这样做也很危险。最好的习惯是像使用其他程序设计语言一样,总是声明所有变量。
声明变量的特点
1.无需明确的类型声明
2.用同一个 var 语句定义的变量不必具有相同的类型
var name="chua",age=20;
3.不一定要初始化(它们是在幕后初始化的)
var name;
4.可以存放不同类型的值
var name = "chua; name = 11;
使用变量时,好的编码习惯是始终存放相同类型的值。
变量命名
- 第一个字符必须是字母、下划线(_)或美元符号($)
- 余下的字符可以是下划线、美元符号或任何字母或数字字符
d.变量申明在所有代码执行之前
先看一个例子
var in_window = 'a' in window; alert(in_window);//true if (!("a" in window)) { var a = 1; }
alert(in_window)显示true,很惊诧是不。
如果去掉var a = 1;这段代码则alert(in_window)显示为false。
我们再次来看一看标题:变量申明在所有代码执行之前。
解析:脚本加载完成以后,浏览器扫描整个脚本,会将所有window下的显示声明(包括表达式中的声明)的变量都先声明,然后才执行表达式。
上面例子中声明变量a是在表达式中声明的,虽然表达式还没有执行,但是声明却已经提前声明了。当然,这个声明表达式不能在函数中。如下
var in_window = 'a' in window; alert(in_window);//false function b(){ var a = 1; }
隐式声明是不会提前声明的,前面变量声明已经分析。
刚才那个是普通变量的显示声明,如果是函数的声明呢?
var in_window = 'a' in window; alert(in_window);//IE/chrome显示true,Firefox显示false if (!("a" in window)) { function a(){} }
很遗憾的是IE/chrome会扫描全局作用域下表达式中的函数声明并提前声明,但是Firefox却没有。
所以这个没有定论。Firefox会把判断语句里面的函数申明当成函数表达式(整个if判断看成一个表达式),执行到那句话的时候才申明函数;chrome则会提前申明所有函数申明(包括类似var m = function(){…}这样明显是函数表达式的函数)。
但是一点可以肯定的是,函数申明和赋值是在声明期间同时完成的,变量赋值语句是作为表达式来执行的。
var a = '1'; function a(){} alert(a); //1
解析步骤为先申明了一个变量a,然后是一个无效的申明(申明都提前了,同一个申明只会有一次),给a赋值为函数(函数申明是在申明过程中赋值),申明完成以后执行代码表达式a = 1。所以结果为1。
function a(){}; var a; alert(a); //function a(){}
解析步骤就是先申明了一个变量,然后赋值为a函数,然后没有然后了(申明都提前了,同一个申明只会有一次)。
var a = function () { return true }; var a;
alert(a); //function () { return true };
解析步骤就是先申明了一个变量为a, 然后是一个无效的申明(函数申明是在申明过程中赋值),申明完成以后执行表达式给a赋值为一个函数,然后没有然后了(申明都提前了)。
这里涉及几个重要概念:
1 变量声明在进入执行表达式之前就完成了
2 函数声明也是提前的,所有的函数声明都在执行代码之前都已经完成了声明,和变量声明一样
3 函数声明会在申明的过程中就对申明的变量赋值为函数
但是我们不提倡在声明变量的代码之前使用该变量,这种写法不直观也不好