1. async和defer的区别(★★★)
答:defer和async都不会阻塞文档的解析,但是不同的是:
- async是在下载脚本结束后立即解析。defer不是。
- defer按顺序下载和执行,async没有顺序。
- defer会在load事件和DOMContentLoad事件之前执行,async在load事件之前执行,对DOMContentLoad事件没有顺序。
详细解释:
一般的渲染的过程是自上而下,同步进行的,也就是说遇到外部的脚本,就得暂停文档的解析,下载并且解释执行,这种方式是阻塞的,会造成网页空白的现象。
关于defer
用于开启新的线程下载脚本文件,并使脚本在文档解析完成后执行。
- defer只适用于外联脚本,如果script标签没有指定src属性,只是内联脚本,不要使用defer
- 如果有多个声明了defer的脚本,则会按顺序下载和执行
- defer脚本会在DOMContentLoaded(document.)和load事件(window.)之前执行
关于async
HTML5新增属性,用于异步下载脚本文件,下载完毕立即解释执行代码。
- 只适用于外联脚本,这一点和defer一致 。
- 如果有多个声明了async的脚本,其下载和执行也是异步的,不能确保彼此的先后顺序。
- async会在load事件之前执行,但并不能确保与DOMContentLoaded的执行先后顺序。
- async和defer一样,不会阻塞当前文档的解析,它会异步地下载脚本,但和defer不同的是,async会在脚本下载完成后立即执行,如果项目中脚本之间存在依赖关系,不推荐使用async。
2. JS的数据类型以及判断方法(★★★★★)
JavaScript 中常见的几种数据类型:
基本类型:string, number, boolean
特殊类型:undefined, null
引用类型:Object, Function, Array, RegExp, Date,…
判断方法:(四种)
- typeOf
返回一个表示数据类型的字符串,返回结果包括:number、boolean、string、object、undefined、function等6种数据类型。- instanceof
用来判断 A 是否为 B 的实例对,表达式为:A instanceof B,如果A是B的实例,则返回true,否则返回false。 instanceof检测的是原型,只能用来判断两个对象是否属于原型链的关系, 而不能获取对象的具体类型。- constructor
当一个函数F被定义时,JS引擎会为F添加prototype原型,然后再在prototype上添加一个constructor属性,并让其指向F的引用。当F被当作构造函数用来创建对象时,创建的新对象就被标记为了“F” 类型。
注意:null和undefined是无效的对象,不会有constructor存在的,这两种类型的数据需要通过typeof来判断。
JS对象的constructor是不稳定的,体现在自定义对象上,当开发者重写prototype后,原有的constructor会丢失,constructor会默认为Object。- Object.prototype.toString
toString是Object原型对象上的一个方法,该方法默认返回其调用者的具体类型,更严格的讲,是toString运行时this指向的对象类型,
返回的类型格式为[object,xxx],xxx是具体的数据类型,包括:String, Number, Boolean, Undefined, Null, Function, Date, Array, RegExp, Error, HTMLDocument,…
基本上所有对象的类型都可以通过这个方法获取到。
eg:Object.prototype.toString.call( '' ) ; // [object String]
3. 隐式转换和显式转换(★★★)
某些运算符会做隐式的类型转换。eg: x+" " and !! ‘x’ and +x
x+"" // 等价于 String(x) 如88 + '6' => ’886’
+x // 等价于 Number(x).也可以写成x-0 如+'886' => number类型的886
!!x // 等价于Boolean(x) 如 !!'886' => true
显式类型转换最简单的方法就是使用
Boolean()、Number()、String() 或 Object() 函 数。
Number( "3“ ) // 3
String(false) // "false" 或使用false.toString()
Object(3) // Number(3)
Boolean([]) // true
Boolean('') // false
解释:
Boolean()用的是ToBoolean方法;参数为String中,string长度为0,
也就是空字符串""时,Boolean显式转换为false,非空字符串为true;
参数只要是Object类型,都被Boolean显示转换成true,
[] 数组属于Object类型的一种。
4. var、let、const作用区别(★★★★★)
var
- var 声明一个变量,那么这个变量就属于当前的函数作用域,如果声明是发生在任何函数外的顶层声明,那么这个变量就属于全局作用域。
- 省略 var,该变量就会变成全局变量,如全局作用域中存在该变量,就会更新其值。
- 只有变量声明才会提升,对变量赋值并不会提升。
let
- let 声明的变量具有块作用域的特征。
- 在同一个块级作用域,不能重复声明变量。
- let 声明的变量不存在变量提升,就是 let 声明存在暂时性死区(TDZ)。
- 块级作用域,由花括号括起来的所有的内容。let和const是块作用域,意味着无论你在块中无论定义了什么变量,什么时候定义的,它都不会跑到块作用域外面去。
以下是一个经典的关于 var 和 let 的一个例子:
for (var i = 0; i < 10; i++) {
setTimeout(function(){
console.log(i);
},100)
};
该代码运行后,会在控制台打印出10个10.若修改为:
变量i不会被重新定义。它的值只会在每次的迭代中不断地被改变。
他实际上只有一个值 - 就是在最后一次循环赋给的那个值。
for (let i = 0; i < 10; i++) {
setTimeout(function(){
console.log(i);
},100)
};
则该代码运行后,就会在控制台打印出0-9.
现在的每一次循环都有它自己的变量定义,所以变量不会被重写。
const
- 除了具有 let 的上述特点外,其还具备一个特点,即 const 定义的变量,一旦定义后,就不能修改,即 const 声明的为常量。
但是,并不是说 const 声明的变量其内部内容不可变,如:
const obj = {a:1,b:2};
console.log(obj.a);//1
obj.a = 3;
console.log(obj.a);//3
所以准确的说,是 const 声明创建一个值的只读引用。
但这并不意味着它所持有的值是不可变的,只是变量标识符不能重新分配。