脚本引入,变量声明以及数据类型

481 阅读8分钟

开发过程中总有一些细节是被我们忽略掉的,这个系列就是重温一下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>标签中加载导致页面的空白期过长,降低了用户体验

开发中建议还是引入外部脚本还是内部脚本?

外部脚本

相对于内部脚本来说,外部脚本的优势如下:

  1. 代码的可维护性更高,代码相对独立。
  2. 浏览器对多个页面引入同一脚本文件的情况,外部引入所使用的缓存会更低,内部可能需要多次开辟,而外部引入只需要一次。

变量声明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而不是未定义
  • varlet的区别在于
  1. 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-infor-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声明,只用letconst可以避免var带来的各种问题
  • let来声明未来会修改的变量,const来声明未来不会改变的变量,可以理解为声明一个常量

数据的类型

原始类型一共有6种Number String Boolean Undefined Null Symbol

引用数据类型Object Function Array

可以利用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)Object
  • null == undifined 返回true,这个是因为==转化了操作数的原因

Boolean类型

  • Boolean有两个字面量,分别是truefalse,不同于数值,true不等于1,false不等于0
  • 布尔值是区分大小写的,因此True和False均不为布尔值
  • 不同类型的布尔值转化
能转化为true的布尔值有:
String型      非空字符串 
Number型      非0数值(包括无穷值)
Object型      任意对象
Undefined型   N/A(不存在)

能转化为false的布尔值有:
String""(空字符串)
Number0NaN
Objectnull
Undefinedundefined

这块用于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类型

  1. 字符串长度为length属性,可用str.length获取。
  2. 除了nullundifined,其他类型皆可用toString()方法转换为字符串,例如a.toString(),同时toString(进制数)接收进制数值为参数,数值类型可以得到对应的进制数字符串。
  3. 确定一个值是否是null或者undifined可以使用String()方法。

Symbol类型

  • Symbol(符号)是ES6的新增数据类型,是用来创建唯一表示的字符串形式的对象属性。具体大家可以自行查阅文档了解一下。

Object类型 Object实例都有如下属性和方法:let obj = new Object()

  • constructor:用于创建当前对象的函数
  • hasOwnProperty(propertyName):用于判断当前对象实例上是否存在给定的属性
  • isPrototypeOf(Object):用于判断当前对象是否为另一个对象的原型
  • propertyIsEnumerable(propertyName):用于判断给定的属性是否可用
  • toLocaleString():返回对象的字符串表示(反映对象所在的本地化执行环境)
  • toString():返回对象的字符串表示
  • valueOf():返回对象对应的字符串,数值或布尔值表示,一般和toString()相同