js相关面试题总结
异步加载JS有哪些方式?
浏览器在解析HTML中,如果遇到script脚本,会停止页面的解析和渲染,去下载script脚本,多个script脚本下载是并行的,但按照html中的先后顺序依次执行(即使后面的脚本先下载完,也要等到前面的脚本下载完并执行完后,才能执行)。script脚本执行时,页面也是停止解析和渲染的。页面渲染完,才会触发DOMContentLoaded(所以script的下载和执行如果慢,会延迟DOMContentLoaded事件的触发时间)。下面的图展示了浏览器下载和执行script过程
在开发中脚本往往比HTML页面更“重”,处理时间更长,所以会造成页面的解析阻塞,在脚本下载和执行之前,用户在界面上什么都看不到。为了解决这个问题,我们可以采用异步加载JS脚本的方式。
异步加载js脚本常用方式:
1. defer 异步加载
* 在script标签中添加defer属性
* defer脚本的 下载和执行 都不会阻塞页面的解析渲染。因为要等到页面解析渲染完毕后,defer脚本才执行
* 多个defer脚本的下载是并行的,但执行却是按照顺序依次执行
* 当页面的解析和渲染完毕后,触发HTMLContentLoaded事件前,依次执行defer脚本。所以defer脚本的下载和执行如果慢,会延迟DOMContentLoaded触发时间
* 浏览器加载和执行 defer脚本的顺序如下图
2.async异步加载
*在script标签中添加async属性
* async 脚本的 下载 不会阻塞页面的解析和渲染。但async脚本的 执行 会阻塞页面的解析和渲染
* 多个async脚本的下载是并行的,哪个先下载完哪个脚本就立即执行,所以async不会按照页面的脚本顺序执行
* async 脚本的执行 只有在DOMContentLoaded事件之前时,才会影响DOMContentLoaded触发时间。又因为脚本的执行时间一般都比较短,所以可以认为async脚本基本不影响DOMContentLoaded事件的触发时间
* 浏览器加载和执行 async脚本的顺序如下图
3. 动态创建script标签 (基本不用了)
* 在还没有定义defer和async 前,异步加载的方式是通过动态创建script,通过window.onload方法确保页面加载完毕,再将script标签插入到DOM中
var let const 区别
- var 有声明提升,let与const 不存在变量声明提升的问题。
console.log(num) //undefined console.log(num1) //Cannot access 'num1' before initialization //console.log(num2) //Cannot access 'num2' before initialization var num = 1; let num1 = 2; //const num2 = 3
上面例子中,var如果在声明之前调用会显示undefined,但let和const 则直接报错
- var定义的变量可以覆盖,记可以重复定义(后面定义的覆盖前面定义的);let和const定义的变量不可以重复定义
var num = 1; var num = 2; console.log(num) //2 // let num1 = 1; // let num1 = 2 //Identifier 'num1' has already been declared //const num1 = 1; //const num1 = 2 //Identifier 'num2' has already been declared
- var定义的变量没有块级作用域;let和const定义的变量存在块级作用域
for(var k = 0; k < 3 ;k++){ console.log(k) //0,1,2 } console.log(k) //k is not defined for(let i = 0; i < 3 ;i++){ console.log(i) //0,1,2 } console.log(i) //i is not defined
- const声明的变量必须赋值,否则会报错;var 和 let 则允许先声明后赋值
const a; //控制台会报错
- const 定义的变量不允许修改,否则会报错;var 和let 则允许修改
JS数据类型有哪些?
基本数据类型:
- 字符串 string
字符串与任何类型的数据结合,都转化成字符串拼接形式 。如下例子:
var a = 'hello' var c = true var b var d = null alert(a + true) //hellotrue alert(a + b) //helloundefined alert(a + d) //hellonull alert(a + 1) //hello1
- 数值 number
- 取值范围 (-2^53, 2^53)范围内,开区间。超出范围,会表示为Infinity 或者-Infinity
- 数字类型采用64位浮点数表示,从最左边开始:
- 第1位:符号位,决定了一个数的正负。0表示正数,1表示负数
- 第2位~第12位:存储指数部分(共11位),指数部分决定了数值的大小
- 第13位~第64位:存储小数部分,决定了数值的精度。(有效数字52位)
- NaN是number类型,但不是一个具体的数字。NaN与任何值都不相等,包括NaN本身即 NaN != NaN
- isNaN() 判断数据是否是NaN
- isFinite() 判断数据是否在范围内
-
var a = 1 alert(a + true) //2 alert(a + undefined) //NaN alert(a + null) //1
- 布尔值 boolean
- 布尔值只能有两个值:true 或者 false
- undefined
- 表示未定义或不存在,本来应该有值但没定义
- null
- 表示空值,即此处的值为空
- typeof null 是 object
- symbol
- 表示独一无二的值
- 格式: let xxx = Symbol('标识字符串')
- Symbol()通常作为属性名,在开发中需要对第三方插件或者框架添加自定应属性或者方法时会用到,防止跟框架的原有属性或者方法重名
引用类型(对象类型):
- 对象Object
- 数组Array
- 函数Function
- 正则RegExp
- 日期Date
null 和 undefined 区别
大多数计算机语言,有且仅有一个表示“无”的值(比如:C语言NULL,java的null),但是JavaScript居然有两个表示“无”的值:null和 undefined.这又是为什么呢?
这与JsvaScript的历史有关。JsvaScript诞生时,借鉴了Java,只设置了一个null作为表示“无”的值,被当成对象。有根据C语言的传统,将null设计成可以自动转为0。但是设计者后来又觉得null像Javay一样被当成一个对象不是很好,再加上作者又觉得null自动转为0很不容易发现错误,因此,作者就又设计了一个undefined,为了填补之前的坑。
二者的具体区别:
null 是表示一个“无”的对象,转为数值时为0
undefined 是表示一个“无”的原始值,转为数值时为NaN
null 和 undefined 进行 == 比较时两者相等,全等===比较时不相等
== 和 === 有什么不同?
==:表示相等(比较的是值)
1.如果两边数据类型不同时,会将两个数据先转换为同一类型(隐式转换),再进行比较。具体的规则如下:
1)数字 和 字符串 进行比较时,会将字符串转换成为数字值
2)如果操作数之一是Boolean,会将Boolean转换成1或者0
3)如果操作数之一是对象,另一个是数字或者字符串,则会调用对象的 valueOf() 和 toString() 方法将对象转换为数字或者字符串
4)只有 null == undefined 情况为true,其他null和undefined以任何类型组合都是false
2.如果两边数据类型相同,则直接比较值、
1 == '1' // true '1' -> 1 1 == 'true' // false 0 == false // true false转化成数值0 [] == false // true []先调用valueOf()->转化成空字符串''->空字符串再转化成数值0; false转化成数值0 [] == 0 // true []先调用valueOf()->转化成空字符串''->空字符串再转化成数值0 ![] == [] //true ![]-> false -> false转化成数值0 ;[]先调用valueOf()->转化成空字符串''->空字符串再转化成数值0 null == undefined // true null == 0 // false ( 虽然null转换为数值是0,但依然不相等 ) null == false // false undefined == 0 // false
==:表示严格相等(除了比较值,没还比较类型)
1.如果两边数据类型不同时,会直接返回false,不会进行比较
2.只有两边数据类型相同,会判断值是否相同
3. 如果两个都是对象类型,那么会潘丹她们引用地址是否一致
0 === '0' //false 0 === false // false null === undefined // false let a = {} let b = {} let c = a a === b // false a === c // true