一、简介
- 数值:整数和小数
- 字符串:文本
- 布尔值:true和false
- undefined:未定义或不存在
- null:空值
- 对象:各种值组成的集合
二、null和undefined
/*
null:转成数值是0
undefined转换数值是NAN
*/
// 变量声明了,但没有赋值
var i;
i // undefined
// 调用函数时,应该提供的参数没有提供,该参数等于 undefined
function f(x) {
return x;
}
f() // undefined
// 对象没有赋值的属性
var o = new Object();
o.p // undefined
// 函数没有返回值时,默认返回 undefined
function f() {}
f() // undefined
三、布尔值
布尔值为false的六种情况:undefined,null,false,0,NAN,""(空字符串),其它情况都是真
四、数值
JavaScript内部,所有数字都是以64位浮点数形式储存,整数也是一样
1 === 1.0 //true
由于浮点数不是精确的值,所以涉及小鼠的比较和运算要特别小心。
0.1+0.2===0.3 //false
0.3/0.1 // 2.99999999999
(0.3-0.2) === (0.2-0.1) // false
-
NAN:是JavaScript的特殊值,表示"非数字",主要出现在将字符串解析成数字出错的场合
s-"x" // NAN(Not A Number) 0/0 //NAN
-
注意NAN不是一种数据类型,是一个值,它的数据类型依然是
Number
typeof NAN // 'number'
-
NAN不等于任何值,包括它本身
NAN === NAN // false
-
NAN与任何数(包括它自己)的运算,得到的结果都是NAN
NAN+11 // NAN NAN+22 // NAN NAN+NAN // NAN
Infinity
表示无穷,-infinity
表示负无穷
与数值相关的全局方法
-
parseint
:将字符串转换为整数,如果头部有空格会自动帮忙去除parseint(" 123") // 123 parseint(1.23) // 1 // 字符串转换为整数的时候,是一个一个字符一次转换,如果不能转换了,就返回之前转好的部分 parseint("123adasd") // 123 parseint("asdasd") // 进制转换 parseint("1000"); parseint("1000",10) // 两者都是1000 parseint("1000",2) //8 parseint("1000",6) // 216
-
parsefloat
:将一个字符串转为浮点数 -
isNAN
:用来判断一个值是否为NAN
,返回值为布尔isNAN(123) //false isNAN("zhuyu") //true
-
isFinite
: 返回一个布尔值,表示某个值是否为正常的数值
五、字符串
-
定义
var str = 'a b c'; // 上面这样的表示方法,是会报错的,改为下面这种 var str = 'a b c'; // 使用 + 号进行字符串的拼接 var name = "zhu" + "yu";
-
字符串与数组
var str = "zhuyu"; str[0] // "z" str[1] // "h" // 可以通过索引(下标)取值 str[10] //undefined,索引值超过了str字符串的最大索引值,返回undefined // 字符串不能和数组那样,对元素进行增删改
-
length
属性:返回字符串的长度var name = "zhuyu"; name.lenght // 5
六、对象:对象(object)是JavaScript语言的核心概念,也是最重要的数据类型
-
生成方法
var obj = { foo : "hello", bar : "world" }
-
键名:对象的所有键名都是字符串,所以加不加引号都可以
var obj = { foo:"hello", bar:"world" } // 如果键名是数值,会自动转换为字符串 var objj = { 1:"a", 2:"b" }
-
对象的引用
如果不同的变量名指向同一个对象,那么它们都是这个对象的引用,也就是说指向同一个内存地址,修改其中一个变量,会影响到其他所有变量。
var o1 = {}; var o2 = o1; o2.name = "zhuyu"; console.log(o1.name); // zhuyu o1.age = 22; console.log(o2.age); // 22
-
属性操作:
-
读取对象属性有两种方法,以是.运算符,一种是方括号运算符
var obj = { name:"zhuyu" } obj.name; // zhuyu objp[name]; // zhuyu // 注意:数值键名不能使用.运算符,只能使用方括号运算符 var aa = { 1:"one" } aa.1; // 报错 aa[1]; // one
-
属性赋值
var obj = { name:"zhuyu" }; obj.age = 22; obj["sex"] = "男";
-
属性的查看
var obj = { name:"zhuyu", age:22 } Object.keys(obj); // ["name","age"]
-
属性的删除
var obj = { name:"zhuyu" } delete obj.name; // 注意删除一个不存在的键值,是不会报错的,返回值为True
-
属性是否存在:
in
运算符var obj = { name :"zhuyu" } "name" in obj; //true "toString" in obj; //true 结果是true,说明该属性存在,应该默认继承类中有这个属性 // hasOwnProperty对象方法可以判断自身是否有什么属性
-
属性的遍历:for...in循环
var obj = { a:1, b:2, c:3 } for (var i in obj) { // i 就是键名 console.log("键名:",i); console.log("键值:",obj[i]); }
for...in
循环有两个使用注意点:- 它是遍历对象所有可以遍历的属性,会跳过不可遍历的属性
- 它不仅遍历对象自身的属性,还可以遍历继承的属性
// 只想遍历对象本身的属性 var person = { name:"朱春宇" } for (key in person) { if (person.hasOwnProperty(key)) { console.log(key); } }
-
-
with 语句 : 操作同一个对象的多个属性时,提供一些书写的方便
with 语句的格式如下
with (对象) { 语句; } var aa = { a1:1, a2:2 } with (aa) { a1 = 11; a2 = 22; } // 等同于 aa.a1 = 11; aa.a2 = 22;
注意:with区域内部赋值操作,必须时对象已有的属性,否则会在当前作用域创建一个全局变量
var aa = {}; // 一个空对象 with (aa) { name = "zhuyu"; age = 22; } aa.name; // name; // zhuyu
七、函数:函数是一段可以反复调用的代码块。
-
JavaScript有三种声明函数的方法
-
function命令
function print(str) { console.log(str); }
-
函数的表示式
var print = function(str) { console.log(str); } // 上面这种声明方式,function后不能带有函数名,如果加上了,那么该函数名只有在函数体内部有效,在函数外部是无效的。 var print = function f () { console.log(typeof f); } f; // f is not undefined; print(); // function
-
Function构造函数
var print = new Function( "x", "return x"; )
-
-
函数的重复声明:同一个函数被多次声明,后面的声明就会覆盖前面的声明
function f () { console.log(1); }; function f () { console.log(2); }; f(); // 2
-
圆括号运算符,return语句和递归
- ():调用函数,参数写在括号里
- return:函数的返回值,不会再执行该函数的其他代码
- 函数里还可以调用函数本身,但是必须要有一个结束的标志,不然会无限循环
-
第一公民
function add(x, y) { return x + y; } // 将函数赋值给一个变量 var operator = add; // 将函数作为参数和返回值 function a(op){ return op; } a(add)(1, 1) // 2
-
函数名的提升
JavaScript引擎将函数名同视为变量名,也有函数名的提升
f(); function f () { console.log(1); } ------------------------------ var f = function () { console.log('1'); }; function f() { console.log('2'); }; f(); // 1
-
函数的属性属性和方法
-
name
属性:获取函数的名字function f () {}; f.name; // f1 ---------------------------- var f2 = function () {}; f2.name; // f2 ---------------------------- var f3 = function func () {}; f3.name; // func
-
length
属性:返回函数参数的个数function f (a,b) {}; f.length; // 2
length
属性提供了一种机制,判断定义时和调用时参数的差异,以便实现面向对象编程的方法"方法重载"(overload)。 -
toString
:返回字符串,内容时函数的源码function f () { console.log("1"); } f.toString(); /* function f () { console.log("1"); } */
-
-
函数作用域
-
作用域指的是变量存在的范围。ES5中,JavaScript只有两种作用域,全局作用域,局部作用域
全局作用域:函数外部声明的全局变量 局部作用域:函数内部定义变量的一块空间
-
函数内部的变量提升
与全局作用域一样,函数作用域内部也会产生"变量提升"现象。
var
命令声明的变量。不管在什么位置,变量声明都会被提升到函数体的头部function foo(x) { if (x > 100) { var tmp = x - 100; } } // 等同于 function foo(x) { var tmp; if (x > 100) { tmp = x - 100; }; }
-
函数本身的作用域
函数本身也是一个值,也有自己的作用域。它的作用域与变量一样,就是其
声明时所在的作用域
,与其运行时所在的作用域无关var a = 1; var x = function () { console.log(a); }; function f() { var a = 2; x(); } f(); // 1 -------------------------- var x = function () { console.log(a); }; function y(f) { var a = 2; f(); } y(x) // ReferenceError: a is not defined -------------------------- function foo() { var x = 1; function bar() { console.log(x); } return bar; } var x = 2; var f = foo(); f() // 1
-
-
参数
-
概述:根据外部传递参数的不同,得到的返回值也不同
function add (x,y) { return x+y; } add(1,2); // 3 add(11,22); // 33
-
参数的省略:JavaScript对函数的要求不高,你可以多传,也可以不传
function print (a,b) { return a; }; print(1,2,3); // 1 print(1); // 1 print(); // undefined
-
参数传递方式
函数参数如果时原始类型的值(数值,字符串,布尔值),传递方式为值传递
var name = "zhuyu"; function setName (str) { str = "zhanghao"; }; setName(name); name; // zhuyu
函数参数是复合类型的值(数值,对象,其他函数),传递方式为址传递(也就是内存地址)
var obj = { name:"zhuyu" } function setName (obj) { obj.name = "zhanghao"; }; setName(obj); obj.name; // zhanghao ---------------------------- var obj = [2,4,6] function setName (obj) { obj = [1,2,3] }; setName(obj); obj; // [2,4,6] /* 解析上面这段代码,函数里的参数obj,在开始对应的是[2,4,6]对应的内存地址,再执行obj=[1,2,3],它是将[1,2,3]的内存地址赋值给它了,并没有改变[2,4,6]的值,所以函数执行完毕,obj这个变量对应的内存地址是没有改变的。 */
-
同名参数
function f (a,a) { console.log(a); } f(1,3); // 3
-
arguments对象
由于JavaScript允许函数有不定数的参数,所以需要一种机制,可以在函数体内部地区所有参数。这就是
argument
对象的由来function f (args) { console.log(argument[0]); console.log(argument[1]); }; f(1,2); // 1,2
正常模式下,是可以改变
argument
对象内部的值function add (a,b) { argument[0] = 5; argument[1] = 5; retuen a+b }; add(1,1); // 10
严格模式下,修改
argument
对象内部值,是不会影响实际参数传递function add (a,b) { "use strict"; // 开启严格模式 argument[0] = 5; argument[1] = 5; retuen a+b }; add(1,1); // 2
通过对象
argument
中length
属性,可以判断函数调用时到底带了几个参数function f () { return argument.length; }; f(1,2,3,4); // 4 f(); // 0
-
-
函数的其他知识点
-
闭包:JavaScript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现
理解闭包,首先必须要理解变量作用域,函数内部可以直接读取全局变量的
var n = 123; function f () { console.log(n); } f(); // 123
写一个实现闭包的例子
function aa () { var name = "zhuyu"; function bb () { console.log(name); } return bb; } var bb = aa(); bb(); // zhuyu
闭包的最大用处有两个,一个时可以读取内部的变量,另一个就是让这些变量始终保存在内存中,即闭包可以使得它诞生环境一直在。
// 闭包使得内部变量记住上一次调用时的运算结果。 function createIncrementor(start) { return function () { return start++; }; } var inc = createIncrementor(5); inc() // 5 inc() // 6 inc() // 7
// 闭包的另一个用处,是封装对象的私有属性和私有方法。 function Person(name) { var _age; function setAge(n) { _age = n; } function getAge() { return _age; } return { name: name, getAge: getAge, setAge: setAge }; } var p1 = Person('张三'); p1.setAge(25); p1.getAge() // 25
-
立即调用的函数表达式
(function () {}());
-
-
eval命令
-
基本用法:
eval
命令接受一个字符串作为参数,并将这个字符串党委语句执行eval("var a= 1;"); a; // 1
参数字符串无法当作语句运行,就会报错
eval("3x"); // 语法错误
eval
没有自己的作用域,都在当前作用域执行,可能会更改当前作用域的变量var a = 1; eval("a = 2"); a; // 2
为了防止这种风险,JavaScript规定,如果使用严格模式,
eval
内部声明的变量,不会影响到外部的作用域(function f() { "use strict"; eval("var foo = 123"); console.log(foo); // undefined; })
不过在严格模式下,
eval
依然可以读写当前作用域的变量(function f() { 'use strict'; var foo = 1; eval('foo = 2'); console.log(foo); // 2 })()
总之,
eval
的本质是在当前作用域之中,注入代码,一般不推荐使用,最常见的地方是解析JSON数据的字符串,不过正确的做法还是JSON.parse方法。
-
八、数组:是按次序排列的一组值,每个值的位置都是有编号(从0开始),用[]
表示
-
定义数组
var arr = [1,2,3]; var arr2 = [{"name":"zhuyu"},[1,2,3],function(){return true}]
-
数组的本质:属于一种特殊的对象,
typeof
返回的类型是object
typeof [1,2]; // object var arr = ["a","b","c"]; object.keys(arr); // ["0","1","2"]
JavaScript规定对象的键名必须是字符串
var arr = [1,2]; arr[0]; // 1 arr["0"]; // 1 // 这是因为被自动转换成了字符串
-
length
属性:返回数组的成员个数["a","b","c"].length // 3
length
属性是可写的,如果人为设置一个小于当前成员的个数,那么数组会自动减少到设置length
的值var arr = ["a","b","c","d"]; arr.length; // 4 arr.length = 2; arr; // ["a","b"] arr.length = 100; arr[80]; // undefined
清空数组的方法:
arr.length=0
;数组也是一种特殊的对象,可以为它添加属性,不会影响到
length
的长度var arr = []; arr["name"] = "zhuyu"; arr.length; // 0 arr["age"] = 23; arr.length; // 0
-
in
运算符:检测某个键名是否存在,适用于对象,也适用于数组 -
for...in
:遍历整个数组var arr = ["a","b","c"]; arr["name"] = "zhuyu"; for (var i in arr) { console.log(i); } // 输出效果为 0,1,2,name
-
数组的空位:数组的某个元素是空元素,即两个逗号之间没有任何值
var a = [1,,1]; a.length; // 输出为3 a[1]; // undefined
使用
delete
命令删除一个数组成员,会形成空位,并且不会影响lenght
属性var arr = [1,2,3]; delete arr[0]; arr.length; // 3 arr[0]; // undefined
-
类似数组的对象
如果一个对象的所有键名都是正整数或零,并且有
length
属性,那么这个对象就很像数组,称为"类数组对象"。