开发过程中总有一些细节是被我们忽略掉的,这个系列就是重温一下js,告诉大家一些被忽略的细节,希望大家可以多多交流。
script标签需要注意的点
-
<script></script>标签内部可以直接写js的代码,这里必须避免内部出现'</script>'字符串,不然浏览器会进行报错。因为浏览器解析行内脚本会将'</script>'字符串看做结束标签,要想避免这个问题,我们需要在字符串的前面加上\转义字符,即'\</script>' -
一组
<script></script>标签中如果同时引入外部脚本和写入内部脚本,这样的话我们的<script></script>标签会直接忽略掉内部的js代码,只执行外部脚本的引入。 -
<script></script>标签的src属性不仅可以引入同域的文件,也可引入不在同一个域中的脚本文件,Jsonp跨域实现可以用该标签来实现。浏览器解析该资源时会向url发送一个get请求来获取到资源,使用时一定要保证该外部域的脚本是可信的 -
<script></script>标签一般放在<body></body>标签中html代码的最后面,这样是为了避免将脚本放在<head></head>标签中加载导致页面的空白期过长,降低了用户体验
开发中建议还是引入外部脚本还是内部脚本?
外部脚本
相对于内部脚本来说,外部脚本的优势如下:
- 代码的可维护性更高,代码相对独立。
- 浏览器对多个页面引入同一脚本文件的情况,外部引入所使用的缓存会更低,内部可能需要多次开辟,而外部引入只需要一次。
变量声明var和let,const
-
不管用
var还是let,声明的变量未赋值时均为undifined -
在函数体内用
var声明的变量作用域仅存在于函数内,函数执行完将被销毁,如果不使用关键字则会在函数体内部创建一个全局变量,但最好不要这样做,严格模式下也会抛出错误 -
var关键字声明的变量,在函数执行时都会被提升到函数作用域顶部,也叫变量提升。
function foo() {
console.log(name)
var name = '法外狂徒张三'
}
这时代码运行时会将变量提前,如下:
function foo() {
var name
console.log(name)
name = '法外狂徒张三'
}
所以是会打印出name为undifined而不是未定义
var和let的区别在于
var声明作用于函数作用域,let声明作用于块级作用域。
if(true){
var name = '张三'
console.log(name) // 张三
}
console.log(name) // 张三
if(true){
let name = '张三'
console.log(name) // 张三
}
console.log(name) // name未定义报错
这里let声明的变量在if块之外就无法进行调用,因为它相对于块级作用域
2.var声明的变量存在变量提升,但是let声明的变量没有变量提升。
//变量提升
console.log(name) // undifined
var name = '张三'
//变量不会被提升
console.log(name) // ReferenceError : name未定义
let name = '张三'
在let声明变量的代码之前,被称为"暂时性死区",在此阶段引用任何后面才声明的变量都会抛出ReferenceError
3.var在全局作用域声明的变量会成为window对象的属性,但是let声明的变量并不会
全局作用域下:
var name = '张三'
console.log(window.name) //张三
let age = 999
console.log(window.age) //undifined
4.在同一个作用域下多次声明同一变量,var不会报错,因为变量提升会将多个相同变量合并为一个。let会报错,因为作用域是块,所以无法知道之前是否声明过同名变量。
5.在for循环中,以及for-in和for-of循环中,假设存在迭代变量为i,如果迭代变量用var声明,在循环体外是可以拿到这个i的值的,如果用let的话不会存在这种问题。
6.用var声明迭代变量时,迭代变量保存的是导致循环退出的值。用let声明迭代变量时,js引擎会在后台为每个迭代循环声明一个新的迭代变量。
for(var i = 0 ; i < 5 ; i++){
setTimeout(()=> console.log(i),0)
}
输出:5 5 5 5 5
for(let i = 0 ; i < 5 ; i++){
setTimeout(()=> console.log(i),0)
}
输出:0 1 2 3 4
const声明的变量必须同时初始化,且当你修改const声明的变量的时候会导致运行错误,且不允许重复声明,作用域也是块级作用域const的限制指向的是变量的引用,换句话说如果声明一个对象,修改对象中的属性则不受到限制const不能用来声明迭代变量,因为迭代变量会不断改变。
如何声明才是最佳选择
- 不使用
var声明,只用let和const可以避免var带来的各种问题 let来声明未来会修改的变量,const来声明未来不会改变的变量,可以理解为声明一个常量
数据的类型
原始类型一共有6种
NumberStringBooleanUndefinedNullSymbol
引用数据类型有
ObjectFunctionArray
可以利用typeof方法来检测数据的类型是什么
需要注意:typeof (null) 会显示类型为Object,这是因为null被认为是一个对空对象的引用
各种类型需要注意到的点
Undifined类型
undifined类型只有一个值就是undifined,当声明变量却未初始化赋值的时候,相当于给变量赋值undifined- 未声明变量和已声明变量初始化需要注意的点
let name;
console.log(name) //undifined
console.log(age) //报错不存在
let name;
console.log(typeof name) //undifined
console.log(typeof age) //undifined
当typeof去检测一个未声明的变量的时候,也会默认显示undifined类型
Null类型
null类型同样只有一个值就是null,被认为是一个空对象的引用,typeof(null)为Objectnull == undifined返回true,这个是因为==转化了操作数的原因
Boolean类型
Boolean有两个字面量,分别是true和false,不同于数值,true不等于1,false不等于0- 布尔值是区分大小写的,因此True和False均不为布尔值
- 不同类型的布尔值转化
能转化为true的布尔值有:
String型 非空字符串
Number型 非0数值(包括无穷值)
Object型 任意对象
Undefined型 N/A(不存在)
能转化为false的布尔值有:
String型 ""(空字符串)
Number型 0,NaN
Object型 null
Undefined型 undefined
这块用于if后的判断条件,会将数据类型自动转换为布尔值
Number类型
-
0.1 + 0.2 != 0.3由于使用了IEEE 754数值,所以存在这种舍入错误,因为正常会得到0.30000000000000004 -
ECMAScript可以表示的值是有范围的,超出这个范围的数自动转化为
Infinity(无穷大),-Infinity表示负无穷大,Infinity表示正无穷大,我们可以用isFinite(num)这个方法来检测是否为无穷大,是返回true,否返回false -
特殊值
NaN,字面意思"not a number",用于表示本来要返回数值的操作失败了。任何涉及NaN的操作始终返回NaN,且NaN不等于包括NaN在内的任何值。数值转换
Number()方法转换规则: -
布尔值:true转化为1,false转化为0
-
数值:直接返回
-
null:返回0
-
undefined:返回NaN
-
字符串:数值类字符串会自动抹去前面的0,转化为十进制数字,除了数值型字符串,其他同一返回NaN
parseInt()方法转换规则: -
数值型字符串会被转换为整数,且自动识别进制数,接收第二个参数指定进制数。
-
对于第一个字符不是数值型的会直接返回NaN。
String类型
- 字符串长度为
length属性,可用str.length获取。 - 除了
null和undifined,其他类型皆可用toString()方法转换为字符串,例如a.toString(),同时toString(进制数)接收进制数值为参数,数值类型可以得到对应的进制数字符串。 - 确定一个值是否是
null或者undifined可以使用String()方法。
Symbol类型
Symbol(符号)是ES6的新增数据类型,是用来创建唯一表示的字符串形式的对象属性。具体大家可以自行查阅文档了解一下。
Object类型 Object实例都有如下属性和方法:
let obj = new Object()
constructor:用于创建当前对象的函数hasOwnProperty(propertyName):用于判断当前对象实例上是否存在给定的属性isPrototypeOf(Object):用于判断当前对象是否为另一个对象的原型propertyIsEnumerable(propertyName):用于判断给定的属性是否可用toLocaleString():返回对象的字符串表示(反映对象所在的本地化执行环境)toString():返回对象的字符串表示valueOf():返回对象对应的字符串,数值或布尔值表示,一般和toString()相同