第一章.基础JavaScript
1.4 原始值和对象
1. 原始值:
- 布尔值:true、false
- 数字:123、0.123
- 字符串:‘ab’、“abcA我”
- 空值:undefined、null
原始值有如下特点:
(1)比较(对内容进行比较)
(2)不可改变(属性不能增删改)
读取未知属性时,总会返回undefined
其中null表示没有该变量(没有对象),undefined表示变量未被初始化(没有值)
2. 对象:
- 简单对象(json):
{
firstName: ‘Jane’,
lastName: ‘Doe’
} - 数组(array):
[
‘apple’, ‘banana’, ‘cherry’
] - 正则表达式(Reg):
/^a+b+$/
对象有如下特点:
(1)比较(按引用进行比较)
可以理解为不同对象的内存地址不同,所以他们是不同的。
下图可以看到obj2 =obj1,这样,obj2就引用了obj1
(2)默认可改变
对象可自由的增删改
3. 空值(undefined)和空对象(undefined)的检查:
可以通过显式的检查:
if(x === undefined || x === null ){
...
}
也可以利用undefined和null都被视为false来处理:
if(!x){
...
}
4. typeof和instanceof对值分类
typeof主要用于原始值、instanceof用于对象
- typeof
注意:typeof null返回object是一个不能去修正的bug,因为修正之后会破坏js底层。但是需要注意的是null并不是一个对象!
补充:这里可以用另一种方法来检测对象类型!
Object.prototype.toString.call(arr) === “[object Array]”
2. instanceof
这里需要注意:instanceof前的操作数需要时一个对象,而{}同时也代表空代码块。所以js无法判断{}究竟代表代码块还是空对象,而js是语句优先,所以优先识别为代码块,所以就会报错(instanceof无前操作数)
解决:分组操作符()控制了表达式中计算的优先级。分组操作符()优先级最高,强制表达式运算。
1.5 布尔值
1. 真与假
被视为false的7个值和对象:false、0、-0、NaN、’’、undefined、null
其他所有的值(包括所有对象)都被当作true。
2. 二元运算符
js的二元运算符是短路的
(1)&&
如果第一个运算数是假,则返回它(因为由于是与,第一个是假,整体一定是假,就无需看第二个了)。否则,返回第二个运算数。
(2)||
如果第一个运算数是真,则返回它。否则,返回第二个运算数。
可以这么记:只看第一个个操作数,与判假,或判真
1.6 数字
1. 浮点数
JS中所有的数均为浮点数
2. 无穷
Infinity与-Infinity一个表示正无穷大一个表示负无穷大(不包含于NaN相比)
3. 转变为数字
通过-0将字符串转变为数字
1.10 函数
1. 函数声明的提升特性
在js中函数、var都具有提升特性。什么是提升特性呢?就是你声明一个函数,或者通过var声明一个变量,无需考虑声明的位置,在别处可以随意引用。例如:
function foo(){
bar(); //在bar函数声明前就调用了,但是不会出错
function bar(){
...
}
}
但是需要注意,通过function执行的赋值不具备提升特性:
function foo(){
bar(); //function执行的赋值不具备提升特性
var bar = function(){
...
}
}
2. arguments
(1)函数的所有参数都可以被自由调用,通过arguments变量来使得所有参数可用。arguments是一个用来存放变量的类似数组的东西。
可以用下列方法把arguments转化为数组:
function toArray(arrayLikeObject){
return Array.prototype.slice.call(arrayLikeObject);
}
(2)可以通过arguments.length来强制参数长度:
1.11 异常捕获
异常捕获用try{}catch(e){},抛出异常用throw new Error:
这里return {id: id}返回一个对象,前面的是key,后面的是value。key默认就是一个字符串(“id”)
插入:
- 字符串与数组之间的相互转换
- 对数组的头、尾添加及删除元素
添加 | 删除 | |
---|---|---|
头 | unshift(’’) | shift() |
尾 | push(’’) | pop() |
1.13 变量作用域和闭包
-
变量是函数作用域的
-
var声明的变量会被认为是在调用处之前声明的,而let则不会(let与java中的变量声明相同—必须在调用前声明)
可以看到直接对tmp赋值而没声明,程序却没有报错(变量提升会出现很多问题,ES6使用let代替var,使得程序更加健壮)
-
闭包
函数及它所连接的周围作用域中的变量即为闭包。所以createIncrementor()返回的其实是一个闭包。 -
IIFE模式(立即调用函数表达式):
IIFE模式格式:
(function(){
var tmp = ...;
}()
);
var作用域为全局,所以在for循环中使用了var,在循环结束后依然会获取到i的值。而let的作用域是局部的,所以在循环外,k的值无法被获取到。
IIFE模式是为了解决var造成的变量提升,从而使闭包中函数返回值错误而设计的,如果使用let声明,则不需要引入IIFE。
1.14 对象
-
使用in运算符检查属性是否存在:
如果读取一个不存在的属性,会得到undefined,所以也可以通过与undefined比较:
-
提取方法
针对jane对象,提取describe方法,如果直接从对象点出来然后赋值给变量func,会发现函数无法获取到正确结果。因为在describe中,return ‘Person named ’+this.name;其中this代表的是jane对象,但是赋值后,这个this的指代就找不到了。所以想要正确找到this的指向,需要使用bind()方法。通过jane.describe.bind(jane),它会创建一个this总是指向给定值得新函数。 -
方法中的函数(嵌套函数)
所有函数都有其特殊的this变量,这个this代表的是与函数同级的作用域,比如下述代码中:
var jane = {
name: 'Jane',
friends: ['Tarzan', 'Cheeta'],
logHiToFriends: function(){
this.friends.forEach(function(friend){
console.log(this.name+' say hi to '+friend);
})
}
}
logHiToFriends外层的function中的this代表的是与logHiToFriends同级的作用域,在该作用域下有friends属性,所以可以正常获取。而对于嵌套的函数,this作用域是与子函数同级的,也就是外层的function内。在这里没有name属性,所以无法获取。
想要在嵌套函数中获取外层的name,有两种方法:
第一种比较通用:将this通过var保存不同的变量中,从而使得作用域可以通过不同的全局变量被各个地方获取到。
可以看到非严格模式下,this是可以指向全局变量的。所以,this.name可以获取到。
第二种方法是利用forEach的第二个参数,它可以给this指定一个值,因为比较特殊,就不赘述了。
1.15 数组
注意:数组是对象,所以可以拥有对象属性。
遍历数组:
数组遍历的方法有很多,其中forEach和map最为重要,两者都可以接受一个函数作为参数。
forEach():
map():
1.16 正则表达式
JS内置的正则表达式使用斜线进行分割:
/^abc$/
/[A-Za-z0-9]+/
方法:
- test()
判断是否匹配
- exec()
匹配以及捕获分组
- replace()
搜索和替换
注:replace的第一个参数必须是带着/g的正则表达式,否则只会替换第一次出现的内容。(猜测g代表global)