变量
由于是动态类型语言,所以变量定义了以后,可以随意更改类型
变量声明
常用的声明关键字有var
/let
,下面来说明两者的区别:
-
var
:声明一个变量,没有代码块作用域的束缚(函数内部声明则为局部变量),可重复声明,自从ES6出了let
关键字以后,尽量不要用var
进行定义 -
let
:在当前代码块声明一个变量,有作用域的概念,并且不能重复声明
举例:
var a = 1;
var a = "sss";
// 可以随意修改类型,并且可以重复声明
let b = 2;
let b = 3;
// 这句会报错:不能重复声明b
注:
变量在定义时也可以不加关键字,两者的区别:加关键字代表在当前作用域的声明局部变量,不加关键字定义的话,如果变量原来存在,则进行赋值操作,如果不存在,则定义一个全局变量(相当于window.xxx = yyy;
)
参考:https://www.cnblogs.com/juejiangWalter/p/5725220.html
常量
常量定义了以后,如果是一般数据类型(如数字/字符串等)则不能再进行修改,而引用类型(如数组/对象等),则可以改变内容
声明常量
使用 const
关键字声明,举例:
const a = {};
a.x = 1;
// 可以修改引用类型常量内容
const b = 1;
b = "sss";
// 修改基本数据类型常量会报错
数据类型
number
数字,包括整数、小数等(基本数据类型)
string
字符串(基本数据类型)
boolean
布尔类型,true
、false
(小写),其中变量里的数字0
、空字符串''
、空对象(null
)和undefined
是false,其他都是true(基本数据类型)
object
对象(引用类型),举例:
var o = {x:1};
function
函数
undefined
就是只定义还没赋值的变量,这个如果直接放在判断语句中就属于false,其他类型都是true(除了bool的false和0以外),比如:
var a
if(a)
{
alert("true")
}
else
{
alert("false")
}
结果显示为false
null
空
数据转型
获取数据类型
通过typeof 变量名
查看,举例::
let a = 10
typeof a
// number
字符串转整数
parseInt()
,该方法是从左到右取到第一个不是数字的内容为止,所以比如:parseInt('12b34')
,结果就是:12
字符串转小数
parseFloat()
注:
当对不含数字的字符串强制转型int时或者数字和非数字进行操作时,会出现NaN
(not a number),如果用typeof会发现NAN类型竟然还是number,而且NaN之间不相等,举例:
b = parseInt('s') //是NaN,c同样
c = parseInt('a')
b == c
结果为:false
所以如果要判断函数是不是NaN时不能用==
来判断,有一个专门的isNaN()
方法判断
eval
可以把一个变量转成他本应该是的类型,比如:'1'+'1'
因为是两个字符串相加,所以结果是'11',而eval能把他们转成本应该是的number型,所以eval('1')+eval('1')
结果就是2。
其还能做些更可怕的比如把一段本该是语句的字符串变成语句来执行,比如下面这句:
eval('document.body.style.background = "blue"')
结果这句话就变成了语句执行,最后背景就变蓝了
运算符
==/===
这两种都是判断等于,主要区别在于第一种会将两边的值转换成同一类型然后进行判断,第二种则不转换类型直接判断,相当于其他语言的==,举例:
var a = 5;
var b = '5';
a == b; //返回true,其将5转换成string型,然后才比较
a === b; //返回false,直接比较
上面两个等于对应的不等于分别是:!=
/!==
,即转换后不等的和不转换不等的
基本语法
if
if(条件)
{
语句
}
else
{
语句
}
条件?语句1:语句2
三目运算符,当条件符合时执行语句1,否则执行语句2,相当于if的简化版
while
while(条件)
{
语句
}
可选链
一个对象如果某些属性不存在,我们直接调用将可能出现问题,例如:
a = {};
// 假设a中的b如果存在则是个函数,我们就会调用它,这里因为b没有定义,所以是undefined,结果就会报错
a.b();
所以我们就可能会先校验是否存在对应属性,如下:
if (a.b) {
b();
}
但如果是嵌套的情况,可能代码就比较多了,例如下面:
if (a.b) {
if (a.b.c) {
if (a.b.c.d) {
a.b.c.d();
}
}
}
此时我们可以通过return
或者逻辑运算符的短路方式来优化代码,从而避免过深的嵌套,例如下面:
if (!a.b) return;
if (!a.b.c) return;
if (!a.b.c.d) return;
a.b.c.d();
但是使用可选链能够更大程度地简化代码,例如上面的代码可以简化如下:
a?.b?.c?.d();
因为可选链自带短路特性,如果某一层属性返回不存在,则不会继续往下继续执行
for
有几种写法:
- 常用写法:
for(;;)
{
...
}
遍历对象key写法:
for(let k in xxx)
{
...
}
遍历对象value写法:
for(let v of xxx)
{
...
}
switch
switch(变量)
{
case x:
语句
case y:
语句
…
default:
语句
}
举例:
switch(fun.arguments.length) //判断函数fun接收的参数个数
{
case 0 : //参数个数为0
return 0
case 1 :
return 1
default :
return "error"
}
异常
try
异常,格式和java差不多
try{
可能异常语句
}
catch(Exception)
{
抛出异常
}
补充
可以赋值语句里再赋值
举例:
a = window.b || (window.b = 10)
相当于:
if (window.b) {
a = window.b;
} else {
window.b = 10;
a = window.b;
}
变量和函数提升
参考:https://segmentfault.com/a/1190000008568071
valueOf/toString隐式调用
https://www.cnblogs.com/tincyho/p/9582680.html
严格模式
严格模式下的代码必须遵循一定的规范才能够正常执行,并且如this
在非严格模式下指向window
对象,而严格模式下为undefined
定义
在开头加上:"use strict"
注:
严格模式只会对其当前作用域及其子作用域有影响,例如在函数里定义使用严格模式,那么函数外部不遵循也可以
参考:https://www.jianshu.com/p/39e295f4526d
分号补全机制
JS解释器有一个Semicolon Insertion规则,它会按照一定规则,在适当的位置补充分号,例如其中几条自动加分号的规则:
- 当有换行符(包括含有换行符的多行注释),并且下一个token没法跟前面的语法匹配时,会自动补分号
- 当有
}
时,如果缺少分号,会补分号- 程序源代码结束时,如果缺少分号,会补分号
例如下面:
function b() {
return
{
a: 'a'
};
}
console.log(b()); // undefined
会被解析成:
function b() {
return;
{
a: 'a'
};
}
console.log(b()); // undefined
参考:https://www.jianshu.com/p/e375f0fbb71c