一、简介
- 数值:整数和小数
- 字符串:文本
- 布尔值:true和false
- undefined:未定义或不存在
- null:空值
- 对象:各种值组成的集合
二、null和undefined
/*null:转成数值是0undefined转换数值是NAN*/// 变量声明了,但没有赋值var i;i // undefined// 调用函数时,应该提供的参数没有提供,该参数等于 undefinedfunction f(x) { return x;}f() // undefined// 对象没有赋值的属性var o = new Object();o.p // undefined// 函数没有返回值时,默认返回 undefinedfunction f() {}f() // undefined
三、布尔值
布尔值为false的六种情况:undefined,null,false,0,NAN,""(空字符串),其它情况都是真
四、数值
JavaScript内部,所有数字都是以64位浮点数形式储存,整数也是一样
1 === 1.0 //true
由于浮点数不是精确的值,所以涉及小鼠的比较和运算要特别小心。
0.1+0.2===0.3 //false0.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 // NANNAN+22 // NANNAN+NAN // NAN
Infinity
表示无穷,-infinity
表示负无穷
与数值相关的全局方法
parseint
:将字符串转换为整数,如果头部有空格会自动帮忙去除parseint(" 123") // 123parseint(1.23) // 1// 字符串转换为整数的时候,是一个一个字符一次转换,如果不能转换了,就返回之前转好的部分parseint("123adasd") // 123parseint("asdasd")// 进制转换parseint("1000");parseint("1000",10) // 两者都是1000parseint("1000",2) //8parseint("1000",6) // 216
parsefloat
:将一个字符串转为浮点数isNAN
:用来判断一个值是否为NAN
,返回值为布尔isNAN(123) //falseisNAN("zhuyu") //true
isFinite
: 返回一个布尔值,表示某个值是否为正常的数值
五、字符串
定义
var str = 'abc';// 上面这样的表示方法,是会报错的,改为下面这种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); // zhuyuo1.age = 22;console.log(o2.age); // 22
属性操作:
读取对象属性有两种方法,以是.运算符,一种是方括号运算符
var obj = { name:"zhuyu"}obj.name; // zhuyuobjp[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); // 3add(11,22); // 33
参数的省略:JavaScript对函数的要求不高,你可以多传,也可以不传
function print (a,b) { return a;};print(1,2,3); // 1print(1); // 1print(); // 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); // 4f(); // 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() // 5inc() // 6inc() // 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]; // objectvar arr = ["a","b","c"];object.keys(arr); // ["0","1","2"]
JavaScript规定对象的键名必须是字符串
var arr = [1,2];arr[0]; // 1arr["0"]; // 1// 这是因为被自动转换成了字符串
length
属性:返回数组的成员个数["a","b","c"].length // 3
length
属性是可写的,如果人为设置一个小于当前成员的个数,那么数组会自动减少到设置length
的值var arr = ["a","b","c","d"];arr.length; // 4arr.length = 2;arr; // ["a","b"]arr.length = 100;arr[80]; // undefined
清空数组的方法:
arr.length=0
;数组也是一种特殊的对象,可以为它添加属性,不会影响到
length
的长度var arr = [];arr["name"] = "zhuyu";arr.length; // 0arr["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; // 输出为3a[1]; // undefined
使用
delete
命令删除一个数组成员,会形成空位,并且不会影响lenght
属性var arr = [1,2,3];delete arr[0];arr.length; // 3arr[0]; // undefined
类似数组的对象
如果一个对象的所有键名都是正整数或零,并且有
length
属性,那么这个对象就很像数组,称为"类数组对象"。