概念
1、CSS和JS在网页上的放置顺序是怎样的?
- 将CSS放在head标签中:CSS放在后面会造成白屏或者FOUC;
- 将JS放在最后:脚本会阻塞后面内容的呈现和其后组件的下载,所以JS放在页面的顶部也会造成白屏的现象;
- 这样做主要是从用户体验和性能去考虑的。
2、解释白屏和FOUC
如果样式放在头部,不管浏览器是加载到什么时候再解析还是等全部都加载后再解析,都可以在最快的时间把渲染树给得到,CSSOM一开始就有了,只要等你内容来了,我马上就可以给它加上,就不会存在这些现象。
-
白屏现象样式
- 浏览器A(比如chrome)如果获取到的内容没有CSS样式时,那这些无样式内容就不会被渲染,所以这时候就会出现白屏现象。
- 在IE浏览器当中,如果把样式放在底部,在一些场景当中,比如刷新页面、新窗口打开等,页面就会出现白屏,而不是内容逐步展现。
- 如果使用
@import
标签,即使CSS放入link当中且也放在头部,也有可能会出现白屏现象。
- 对于图片和CSS,在加载时会并发加载,然而在加载JS文件时会禁用并发,阻止其他内容的下载。所以把JS代码放在页面顶部也会造成白屏现象。
- 浏览器A(比如chrome)如果获取到的内容没有CSS样式时,那这些无样式内容就不会被渲染,所以这时候就会出现白屏现象。
-
FOUC(Flash Of Unstyled Content)无样式内容闪烁
- 浏览器B(比如firefox)是逐步加载无样式的内容,等CSS加载完成后页面突然展现的样子。也就是说,浏览器加载了无样式内容,又突然解析到了样式,会对页面进行重新的渲染,这时候就会产生FOUC现象;
- 在IE浏览器中,如果把样式放在底部,某些场景下(点击链接、输入URL、使用书签进入等等),就会出现FOUC现象。对于 Firefox 则会一直表现出 FOUC。
总结就是:
1、样式如果放最后,对于Chrome就会白屏,对于Firefox就会FOUC,IE就比较奇葩,都有可能发生。
2、JS如果放在最开头,那就会白屏。
3、async和defer的作用是什么?有什么区别
页面中一个js文件的完整引入流程:
1、引入js文件包括加载、解析和执行3个阶段;
2、加载js默认是同步加载(阻塞加载);
3、加载完js文件后,根据响应头信息的内容类型Content-Type:application/x-javascript
进行js文件的解析(预处理阶段),js引擎首先会解析所有的脚本,然后进行变量提升,此时遇到错误将不报错;
4、执行js文件,按照脚本和代码出现的先后顺序执行,并且遇到错误报错;延迟脚本(执行阶段)
<script src= 'demo.js' defer></scirpt>
上述外部js文件的引入使用了script元素的defer属性,它将会改变script元素引入流程过程中的执行阶段,即延迟执行该脚本,直到页面其他内容解析和渲染完毕;
- 异步脚本(加载阶段)
<script src='demo.js' async></script>
上述外部js文件的引入使用了script元素的async属性,它将会改变scirpt元素引入流程过程中的加载阶段,即异步脚本加载过程中不影响页面其他的操作;
如果你在页面中使用两个以上的异步脚本,那么一定要确保二者不存在依赖,不然可能会导致错误;
- 比较async和defer
- 相同点
- 加载文件时不会阻塞页面的渲染
- 只对外部脚本文件有效
- 相同点
- 不同点
- async不保证按照指定它们的先后顺序执行;
- defer脚本延迟到文档解析和显示后执行,会按照原本给出的顺序先后执行。
4、简述网页的渲染机制
- 解析HTML以构建DOM树及CSSOM树,将标签转化为内容树中的DOM节点,接着把外部引用的CSS文件和style标签中的样式信息解析为CSSOM树;
- 构建渲染树(render树),由DOM树及CSSOM树构建而成;
- 布局render树,在render树的基础上进行布局过程,它将确定每个节点在屏幕上的确切坐标;
- 绘制render树,把每个节点绘制到屏幕上;
下面是chrome浏览器渲染网页的机制:构建好DOM树和CSSOM树之后再去构建渲染树(也是白屏现象的原因);
有空看看:浏览器内部工作原理
5、JavaScript定义了几种数据类型?哪些是简单类型?哪些是复杂类型?
这种分法是从存储的角度来讲的,ECMAScript中有5种简单数据类型(也称为基本数据类型):Undefined、Null、Boolean、Number和String;还有一种复杂数据类型Object,Object本质上是由一组无序的名值对组成的。
1、Undefined类型:
Undefined类型只有一个值,即undefined。意为未定义或不存在;
- 在使用var声明变量但未对其加以初始化时,这个变量的值就是undefined。
var message; //这个变量声明之后默认取得了undefined值
alert(message); //"undefined"
alert(age); //会报错
运行上面的代码,变量message只有一个值,即“undefined”。
- 对未初始化的变量执行typeof操作符会返回undefined值,而对未声明的变量执行typeof操作符同样也会返回undefined值。
var message; //这个变量声明之后默认取得了undefined值
alert(typeof message); //"undefined"
alert(typeof age); //"undefined"
2、Null类型:
Null类型也只有一个值,即null。表示空缺,即此处应该有一个值,但目前为空。null值表示空对象指针,这也是使用typeof检测null值时会返回"object"的原因。
var car = null;
alert(typeof car); //"object"
3、Boolean类型:
该类型有两个字面值:ture和false。
可以对任何数据类型的值调用Boolean()函数,而且总会返回一个Boolean值,下面是转换规则:
数据类型 | 转换为ture的值 | 转换为false的值 |
---|---|---|
Boolean | ture | false |
String | 任何非空字符串 | ""(空字符串) |
Number | 任何非零数字值(包括无穷大) | 0和NaN |
Object | 任何对象 | null |
Undefined | 不适用 | undefined |
4、Number类型:
- 整数(十进制,八进制,十六进制)
- 浮点数(用科学计数法表示,相加不精确,数值范围isFinite()函数)
-
NaN,非数值是一个特殊的数值,用来表示一个本来要返回数值的操作数未返回数值的情况。
值NaN有两个特点:(isNaN()函数)
- 任何涉及NaN的操作都会返回NaN;
- NaN与任何值都不相等,包括NaN本身,如
alert(NaN == NaN); //false
会返回false;
对于非数值可以用三个函数转换为数值:Number()、parseInt()、parseFloat()
。
Number()
可以用于任何数据类型,规则相当复杂而且不合理,几乎不使用,常用的是后两个,专门用于把字符串转换为数值,规则类似:
- 忽略字符串前面的空白字符,找到第一个非空白字符;
- 如果第一个字符不是 - 或者数字返回NaN;
- 如果是继续解析,直到非数值模式为止;
- 0开头会当作八进制,0x开头会当作十六进制,但是可以指定第二个参数指定基数
5、String类型:
字符串,可以由单引号或双引号表示。
要把一个值转换为一个字符串有两种方法:toString()方法、String()转型函数;
- 几乎每个值都有toString()方法,除了null和undefined值之外;
-
在不知道要转换的值是不是null或undefined的情况下使用String();
6、Object对象类型:
JavaScript的所有数据都可以被视为对象,这也是我们常说的一切皆为对象。
对象类型,较为复杂,意为一组数据和功能的集合,包含属性和方法。
所以只要包含属性和功能的一个集合就可以称为Object类型,比如,数组、函数、“标准”的对象、时间对象、基本包装对象、两个单体内置对象、正则表达式都是Object类型。
阮一峰的这个讲得特别好理解:数据类型
6、NaN、undefined、null分别代表什么?
-
NaN,非数值是Number类型中一个特殊的数值,用来表示一个本来要返回数值的操作数未返回数值的情况。
针对NaN的这两个特点,ECMAScript定义了isNaN()函数。它只有一个参数,这个参数可以是任何类型,该函数会帮我们确定这个参数是否“不是数值”。isNaN()接收到一个值之后,会尝试将这个值转换为数值。
- Undefined数据类型:
Undefined类型只有一个值,即undefined。意为未定义或不存在; - 在使用var声明变量但未对其加以初始化时,这个变量的值就是undefined。
var message; //这个变量声明之后默认取得了undefined值
alert(message); //"undefined"
alert(age); //会报错
运行上面的代码,变量message只有一个值,即“undefined”。
- 对未初始化的变量执行typeof操作符会返回undefined值,而对未声明的变量执行typeof操作符同样也会返回undefined值。
var message; //这个变量声明之后默认取得了undefined值
alert(typeof message); //"undefined"
alert(typeof age); //"undefined"
- Null数据类型:
Null类型也只有一个值,即null。表示空缺,即此处应该有一个值,但目前为空。null值表示空对象指针,这也是使用typeof检测null值时会返回"object"的原因。
var car = null;
alert(typeof car); //"object"
实际上undefined的值是派生自null值的:
7、typeof和instanceof的作用和区别?
因为ECMAScript是松散型的,所以需要一种手段来检测给定变量的数据类型。JS中有三种方法来确定一个值到底是什么类型。分别为:typeof运算符、instanceof运算符以及Object.prototype.toString()方法。
- typeof运算符可以返回一个值的数据类型,可能有以下结果:
-
原始类型
-
undefined类型
undefined返回undefined。
利用这一点,typeof可以用来检查一个没有声明的变量,而不报错。
- 函数
函数返回function。
-
// 定义一个空函数
function f(){}
typeof f; // "function"
- 其它
除此之外都返回object
从上面代码可以看到,空数组([])的类型也是object,这表示在JavaScript内部,数组本质上只是一种特殊的对象。另外,null的类型也是object,这是由于历史原因造成的,为了兼容以前的代码,后来就没法修改了,并不是说null就属于对象,本质上null是一个类似于undefined的特殊值。
-
instanceof则为判断一个对象是否为某一数据类型,或一个变量是否为一个对象的实例,返回Boolean类型。
对于用typeof判断都为Object的对象我们就可以用instanceof加以判断:
代码
1、完成如下代码判断一个变量是否是数字、字符串、布尔、函数
function isNumber(el){
if( typeof el === "number" ){
return ture;
}else{
return false;
}
}
function isString(el){
if( typeof el === "string" ){
return ture;
}else{
return false;
}
}
function isBoolean(el){
if( typeof el === "boolean" ){
return ture;
}else{
return false;
}
}
function isFunction(el){
if( typeof el === "function" ){
return ture;
}else{
return false;
}
}
var a = 2,
b = "zhouhuahua",
c =false;
alert( isNumber(a) );
alert( isString(a) );
alert( isString(b) );
alert( isBoolean(c) );
alert( isFunction(a) );
alert( isFunction( isNumber ) );
2、以下代码的输出结果是?
console.log(1+1); //2,两个数相加,输出数值;
console.log("2"+"4"); //"24",两字符串拼接,输出字符串;
console.log(2+"4"); //"24",一个数值和一个字符串相加,输出字符串;
console.log(+new Date()); // 1471048600952,用new Date()参与计算会自动转换为从1970.1.1到现在的时间的毫秒数。
console.log(+"4"); // 4,在只有一个字符串时,会尝试将其转换为数字;
在JavaScript中运算符通常会根据需要对操作数进行类型转换,乘法操作符希望操作数是数字,但是 "3" * "5"也是合法的,JavaScript会自动将其转换为数字计算,返回Number 15;对减法也是一样的。
不过有些操作符对不同的数据类型有不同的含义,比如 +:
- 在两个操作数都是数字的时候,会做加法运算;
- 两个参数都是字符串或在有一个参数是字符串的情况下会把另外一个参数转换为字符串做字符串拼接;
- 在参数有对象的情况下会调用其valueOf或toString方法;
- 在只有一个字符串参数的时候会尝试将其转换为数字;
-
在只有一个数字参数的时候返回其正数值;
3、以下代码的输出结果是?
var a = 1;
a+++a;
typeof a+2;
在a+++a表达式当中,后置递增的优先级最高。所以相当于(a++)+a。a一开始赋值为1,a++表示先赋值再自增,所以a++的计算结果为1,且此时a等于2。所以a+++a表达式的计算结果为3。
而typeof a+2中,typeof的优先级比“+”高,所以它会先计算typeof a,得到的输出是字符串"number"。然后是一个字符串加上一个数字,会把数字转换成字符串。所以得到的输出为"number2"的字符串。
4、遍历数组,把数组里的打印数组每一项的平方
var arr =[3,4,5];
/* for(key in arr){
console.log(arr[key]*arr[key]);
} */
for(i=0;i<arr.length;i++){
console.log(arr[i]*arr[i]);
}
5、遍历JSON,打印里面的值
var obj = {
name: "hunger",
sex: "male",
age: 28
}
for(k in obj){
console.log( k+":"+obj[k] ) ;
}
6、下面代码的输出是?为什么
console.log(a);
var a = 1;
console.log(a);
console.log(b);
JavaScript引擎的工作方式是,先解析代码,获取所有被声明的变量,给他初始值undefined,然后再一行一行地运行。这造成的结果,就是所有的变量的声明语句,都会被提升到代码的头部,这就叫做变量提升。
上面的代码相当于如下代码:
var a;
console.log(a);
a = 1;
console.log(a);
console.log(b);
(完)