学习内容:JavaScript基本概念,基础数据类型,运算符,流程控制语句
一、CSS和JS在网页中的放置顺序是怎样的?
1.在开发网页时,尽量将css放置在页面的head里,js放在页面的尾部。
① 网页渲染时,先解析HTML标签,生成DOM树,然后解析CSS标签,构成CSSOM树,然后再把DOM和CSSOM组合成渲染树,如果把CSS放在后面,可能会出现白屏问题或者无样式内容闪烁。
②使用内嵌<script>标签引用js文件时,当浏览器遇到js标签的时候,它不知道js是否会修改页面,所以它会先停止解析页面,先执行JS代码之后再来继续渲染页面 。所以当浏览器遇到js标签,它会优先下载解析执行JS代码,禁用并发,同样的情况也发生在外嵌js,这样就会阻塞后面页面的加载和渲染,造成白屏现在,所以js放在body后面。
参考:并行加载与顺序执行
二、解释白屏和FOUC
1.不同浏览器对于CSS和HTML的处理方式不同,一些浏览器如chrome,它是把所有的样式加载完成之后,然后做一个统一的最终的绘制,这个等待的时间就造成了白屏。而另一些浏览器如Firefox,它是先把内容绘制出来,然后发现新的样式再去重新加载,加载完成后再去绘制一遍。这就造成了FOUC((Flash of Unstyled Content),即无样式闪烁。
2.白屏发生情况
①如果把样式放在底部,对于IE浏览器,在某些场景下(新窗口打开,刷新等)页面会出现白屏,而不是内容逐步展现;
②如果使用 @import标签,即使 CSS 放入 link, 并且放在头部,也可能出现白屏
③如果将js放在页面的头部也会可能出现白屏现象,因为js会阻塞后面其他内容的下载和阻塞后面组件的下载。
3.fouc发生的情况
如果把样式放在底部,对于IE浏览器,在某些场景下(点击链接,输入URL,使用书签进入等),会出现 FOUC 现象(逐步加载无样式的内容,等CSS加载后页面突然展现样式)。对于 Firefox 会一直表现出 FOUC 。
三、async和defer的作用是什么?有什么区别
如图:
蓝色线代表网络读取(等于下载),红色线代表执行时间,这俩都是针对脚本的;绿色线代表 HTML 解析
1.<script src="script.js"></script>
没有 defer或 async,浏览器会立即加载并执行指定的脚本,“立即”指的是在渲染该 script标签之下的文档元素之前,也就是说不等待后续载入的文档元素,读到就加载并执行。
2.<script async src="script.js"></script>
async属性标注的脚本是异步脚本,即异步下载脚本时,不会阻塞文档解析,但是一旦下载完成后,立即执行,会阻塞文档解析。
3.<script defer src="myscript.js"></script>
defer属性标注的脚本是延迟脚本,使得浏览器延迟脚本的执行,也就是说,脚本会被异步下载但是不会被执行,直到文档的载入和解析完成,并可以操作,脚本才会被执行
区别:
async加载完了就会立刻执行,但是不能保证执行顺序,有可能后面出现的脚本先执行,所以要确认脚本间没有依赖关系;defer要等待整个页面内容及样式全部加载完后再执行,defer会按他们在文档里的出现顺序执行
三、简述网页的渲染机制
1.解析 HTML 标签, 构建 DOM 树
2.解析 CSS 标签, 构建 CSSOM 树
3.把 DOM 和 CSSOM 组合成 渲染树 (render tree)
4.在渲染树的基础上进行布局, 计算每个节点的几何结构
5.把每个节点绘制到屏幕上 (painting)
参考
参考
五、JavaScript 定义了几种数据类型? 哪些是简单类型?哪些是复杂类型?
JavaScript语言的每一个值,都属于某一种数据类型。JavaScript的数据类型一共有六种,有5种简单数据类型和1种复杂数据类型
五种简单数据类型:
- 数值(number):整数和小数(比如1和3.14)
- 字符串(string):字符组成的文本(比如"Hello World")
- 布尔值(boolean):true(真)和false(假)两个特定值
- undefined:表示“未定义”或不存在,即此处目前没有任何值
- null:表示空缺,即此处应该有一个值,但目前为空
注意:
通常,我们将数值、字符串、布尔值称为原始类型(primitive type)的值,即它们是最基本的数据类型,不能再细分了。
而将对象称为合成类型(complex type)的值,因为一个对象往往是多个原始类型的值的合成,可以看作是一个存放各种值的容器。
至于undefined和null,一般将它们看成两个特殊值。
1种复杂数据类型
object对象类型,各种值组成的集合。它可以分成三个子类型:狭义的对象,数组,函数。它是一组数据和功能的集合,包含属性和方法。
说明:
狭义的对象和数组是两种不同的数据组合方式,而函数其实是处理数据的方法。
JavaScript把函数当成一种数据类型,可以像其他类型的数据一样,进行赋值和传递,这为编程带来了很大的灵活性,体现了JavaScript作为“函数式语言”的本质。
JavaScript的所有数据,都可以视为广义的对象。
不仅数组和函数属于对象,就连原始类型的数据(数值、字符串、布尔值)也可以用对象方式调用。
六、NaN、undefined、null分别代表什么?
1.NaN表示not a Number,非数字,但它属于Number类型,表示一个本来要返回数值的操作数未返回数值的情况(比方在ECMAScript中,任何数值除以0会返回NaN,而不会导致错误,不会停止代码的执行,因此不会影响其他代码的执行)。
它有两个特点:一个是NaN和任何值都不相等,包括自己;另一个是任何涉及NaN的运算(比如NaN/1)都会返回NaN
ECMAScript定义了isNaN()函数,这个函数可以接受一个任何类型的参数,该函数表示这个参数是不是NaN。
2.undefined表示“未定义”,不存在值,就是此处目前不存在任何值。也就是有这个指针,但是这个指针没有指向任何空间
典型用法是:
- 变量被声明了,但没有赋值时,就等于undefined。
- 调用函数时,应该提供的参数没有提供,该参数等于undefined。
- 对象没有赋值的属性,该属性的值为undefined。
-
函数没有返回值时,默认返回undefined。
3.null表示空值,即该处的值现在为空。也就是表示空指针,就是不存在的东西。
null表示一个“空”的值,它和0以及空字符串'' "不同,0是一个数值," ''表示长度为0的字符串,而null表示“空”。
- 作为函数的参数,表示该函数的参数是一个没有任何内容的对象。
- 作为对象原型链的终点。
七、typeof和instanceof的作用和区别?
1.typeof运算符可以返回一个值的数据类型,可以是数字number,字符串string,布尔值boolean,函数function,除此以外,其他情况都返回对象object.
例如:
2.使用typeof,无论引用的是什么类型的对象,都会返回object。针对这个问题,js引入了instanceof来解决这个问题。
instanceof用于判断一个变量是否是某个对象的实例,也可以说用来检测对象的类型(也可叫做引用类型)。instanceof只输出true和false。
参考
八、代码题
1.完成如下代码判断一个变量是否是数字、字符串、布尔、函数 (难度*)
ps: 做完后可参考 underscore.js 源码中部分实现
function isNumber(el){
// todo ...
}
function isString(el){
//todo ...
}
function isBoolean(el){
//todo ...
}
function isFunction(el){
//todo ...
}
var a = 2,
b = "jirengu",
c = false;
alert( isNumber(a) ); //true
alert( isString(a) ); //false
alert( isString(b) ); //true
alert( isBoolean(c) ); //true
alert( isFunction(a)); //false
alert( isFunction( isNumber ) ); //true
2.以下代码的输出结果是?(难度**)
console.log(1+1);
console.log("2"+"4");
console.log(2+"4");
console.log(+new Date());//从1971到到现在的毫秒数
console.log(+"4");
"+"运算符对操作数进行类型转换:
- 在两个操作数都是数字的时候,会做加法运算
- 两个参数都是字符串或在有一个参数是字符串的情况下会把另外一个参数-- 转换为字符串做字符串拼接
- 在参数有对象的情况下会调用其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",typeof返回的全是string。然后是一个字符串加上一个数字,会把数字转换成字符串,所以得到的输出为"number2"的字符串。
参考:运算符的优先级
4.遍历数组,把数组里的打印数组每一项的平方 (难度**)
var arr = [3,4,5]
// todo..//
输出 9, 16, 25
5.遍历 JSON, 打印里面的值(难度**)
var obj = {
name: 'hunger',
sex: 'male',
age: 28
}
//todo ...
// 输出 name: hunger, sex: male, age:28
6.下面代码的输出是? 为什么 (难度***)
console.log(a);
var a = 1;
console.log(a);
console.log(b);
JavaScript引擎的工作方式是,先解析代码,获取所有被声明的变量,给他初始值undefined,然后再一行一行地运行。这造成的结果,就是所有的变量的声明语句,都会被提升到代码的头部,这就叫做变量提升。
也就是js加载代码完成后,它会先把变量给定义好,后面再进行赋值。
在上面的代码中,变量a先被声明,再执行console.log(a);,也就是相当于执行了var a; console.log(a);。因为此时a没有赋值,所以console.log(a);结果为undefined。然后a被赋值为1,再执行console.log(a);,所以console.log(a);结果为1。最后,console.log(b);,由于b变量不存在,所以结果报错