JS错题锦集记录一下常考易错知识点

Posted 安之ccy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JS错题锦集记录一下常考易错知识点相关的知识,希望对你有一定的参考价值。

本文原创为CSDN博主:安之ccy,博客首页地址:https://blog.csdn.net/qq_43523725
转载请注明出处,谢谢支持和鼓励




    前阵子在刷牛客网的js选择题库,后来一个多月没刷,感觉很多知识点又忘记了,所以整理一下自己觉得重要、易错的题~本文中涉及的题均来自牛客网题库,题解参考牛客网答友或搜索到的资料。掺杂了些CSS和html的题,见谅,可以根据目录挑选自己想看的题。如果有解释不当的地方,还望指教

1. 关于this指针的指向
2. prototype和__proto__
3. call与apply对比
4. 强制转换、隐式转换
    4.1 双等号==
    4.2 Boolean类型转换
    4.3 加号与减号
    4.4 API强制类型转换
    4.5 new String 与 ’ ’
5. API使用
    5.1 map函数
    5.2 parseInt函数
6.立即执行函数
7.ES5的变量提升
8.JS对象转基本类型
9.W3C标准盒模型
10. 其他
    10.1 margin塌陷问题
    10.2 promise的all方法
    10.3 浏览器渲染流程与页面加载过程
    10.4 HTML语义化
    10.5 position定位
    10.6 回流和重排
    10.7 CSS的引入
    10.8 Javascript的引入(未写待更)
    10.9 Javascript的相关概念
    10.10 a标签——链接
    10.11 定义函数
    10.12 for循环条件表达式和遍历
    10.13 运算符优先级




1.关于this指针的指向

单选题1:关于this的工作原理,下面4种情况的描述哪一个是错误的?
 
    A.在全局范围内,this指向全局对象(浏览器下指window)
    B.对象函数调用时,this指向当前对象
    C.全局函数调用时,this指向全局函数
    D.使用new实例化对象时,this指向新创建的对象

分析:this指针是函数体内自带的一个对象指针;也可以理解成,this出现在某个函数中。在ES5的语法,this指针指向的简单判断规则是:哪个对象拥有了这个函数,this就是这个对象的指代

结合例子分析能更好地理解题意,具体可以查看我的这篇文章

文章重点与选项的对应:
1.普通对象使用函数,即对象函数,this指向这个对象(选项B正确)
2.直接使用函数(调用全局函数),即在全局范围内,this指向window(选项A对C错)
3.函数对象使用函数,this指向函数对象
4.函数中嵌套另一个函数,内嵌函数下的this指向的是window
5.事件函数的this指向“绑定了该事件函数的对象(dom元素)”
6.定时器setTimeOut中的this指向window
7.使用new实例化对象时,this指向新创建的对象(选项D正确)
 
本题答案选C

另:如果是在ES6的箭头函数体中, this 对象指向定义函数时的对象,而不是使用函数时的对象

      有时我们会遇到这种情况:我们需要使用外层函数的this环境,于是提前保存this对象,如:var vm = this;,到内层函数使用时,直接用预保存的vm变量即可
      ES6的this机制就很好地改善了这个情况,我们可以直接在内层函数中使用this指针,无需预保存this对象,具体可以看我的这篇文章




单选题2:程序的输出是什么??

var myObject = 
    foo: "bar",
    func: function() 
        var self = this;
        console.log(this.foo);   
        console.log(self.foo);   
        (function() 
            console.log(this.foo);   
            console.log(self.foo);   
        ());
    
;
myObject.func();

A.bar
bar
bar
bar
 
B.bar
bar
bar
undefined
 
C.bar
bar
undefined
bar
 
D.undefined
bar
undefined
bar

把这题做对了,我就又是最靓的仔了!<( ̄︶ ̄)↗[GO!]


判断this指向的小技巧:

- 哪个对象拥有了这个函数,this就是这个对象的指代

程序的最后,运行的是myObject对象下的func方法,也就是myObject.func();,说明在func作用域下,this指代的是myObject对象

- 匿名函数的执行环境具有全局性
匿名函数里的this一般指向window

有了这两个知识点,我们就可以来做这道题了

var myObject = 
    foo: "bar",
    func: function() 
        var self = this; 
        // 此处的this指的是myObject,而self则保存了这this指向
        // 后续出现self,我们就知道,只是是指myObject
        console.log(this.foo);   // this指的是myObject,输出"bar"
        console.log(self.foo);   // self指的是myObject,输出"bar"
        (function() 			// 匿名函数,this指向window对象
            console.log(this.foo);   // this指的是window,输出undefined
            console.log(self.foo);   // self指的是myObject,输出"bar"
        ());
    
;
myObject.func();

答案:C



2.prototype和__proto__

单选题:下面说法错误的是:
 
    A. 每个对象都具有一个名为__proto__的属性
    B. 每个对象都具有一个名为prototype的方法
    C.每个对象的__proto__属性指向自身构造函数的prototype
    D.对象不具有prototype属性,只有函数才有prototype属性

这个知识点,貌似比较深奥,也比较有争议。看了评论区各位大佬和网络的解答,觉得本人目前还没有能力理解透彻

此处贴上某位大佬的一个解答,建议点开详情看评论回复,here
还有一位大佬的良心解答,应该是比较完善的:here
呜呜呜,太强了,忍不住崇拜一下


大佬在最后贴心地总结了一下,截图如下:

式子再写一遍:

函数创建的对象.__proto__ === 该函数.prototype
该函数.prototype.constructor===该函数本身
例子:
    function Foo() …
    let f1 = new Foo();
重点:f1.__proto__ === Foo.prototype

回到题目

比较有争议的是这两个疑点:
    “函数也是对象”——D咋办?
    “null是对象?null没有__proto__” ——A咋办?

 
我的想法:

  • 在这道题中,函数和对象应该是特意区分了一下,为了辅助区别__proto__和prototype

  • 由于typeof null返回“object”是一个历史错误(JS的发明者Brendan Eich自己也是这样说的),只是因为要保持语言的兼容性而维持至今
    而且,null属于基本数据类型之一,因此,我倾向于,用”null不是对象“来解释这道题

再根据大佬的文章,这道题就可以做出来了:

  • 对象都有__proto__属性,A选项正确;
  • 函数独有一个prototype,B选项错误,D选项正确;
  • 函数创建的对象.__proto__ === 该函数.prototype,C选项正确;

 
答案:B




这个知识点比较重要,所以把遇到的题都整理出来,便于加深理解

不定项选择题:下列说法正确的是():
 
    A. 每个JS对象一定对应一个原型对象,并从原型对象继承属性和方法
    B. 对象的__proto__指向自己构造函数的prototype
    C.Object.prototype. __proto__=== null,说明原型链到Object.prototype终止
    D.表达式 Function.prototype.__proto__.__proto__ === null 的运行结果为true
 
根据大佬的文章,这道题BCD选项均正确
B选项是对的,根据该选项,可以知道Object.create(null)得到的对象obj,没有原型对象,因此选项A错误

 
答案:BCD



3.call与apply对比

单选题1:下面有关javascript中call和apply的描述,错误的是?
 
    A.apply传入的是一个参数数组,也就是将多个参数组合成为一个数组传入
    B.call与apply都属于Function.prototype的一个方法,所以每个function实例都有call,apply属性
    C.两者传递的参数不同,call函数第一个参数都是要传入给当前对象的对象,apply不是
    D.call传入的则是直接的参数列表,call方法可将一个函数的对象上下文从初始的上下文改变为由thisObj指定的新内容

看起来有点绕,别担心,绕着绕着就出去了😜仔细看题就好~
前面已经讲到,在ES5语法中,this指向的判断规则是:哪个对象拥有了这个函数,this就指向这个对象
而call和apply就是用于:改变this指向为自己特定的对象,并且这两个方法是非继承而来的(Function.prototype.call()和Function.prototype.apply()),每个函数都包含这两个方法,这是两个方法的基本概念~

apply语法:fun.apply([thisObj [,argArray] ]);
call语法:fun.call([thisObj[,arg1 [,arg2 [,...,argn]]]]);

使用了apply和call之后,this指向了thisObj,即第一个参数均是要特定的this对象,是传入给当前函数(对象)的对象
apply的第二个参数是一个数组,call则是一个个列出参数的


这是官方给出的两者区别~

到此,我们已经可以解题了,答案选C,apply和call接收不同的参数在于后面的参数,apply接收数组,call逐个接收;第一个参数的用法是一致的,都是this指向




单选题2:请阅读以下代码,该代码在浏览器中执行,输出的日志结果是什么?
 
    A.undefined
    B.window
    C.console
    D.obj

var obj = ;
obj.log = console.log;
obj.log.call(console,this);

分析:

  • 将console.log的功能复制给obj.log,因此后者功能也是输出;
  • call将log方法的执行权给了window.console,要求它输出this,所以绕了个弯,求的是
console.log(this); // 输出window对象

答案:B
评论区有大佬提到了严格模式,放上官网链接:here



4.强制转换、隐式转换

4.1 双等号==

不定项选择题:以下哪些表达式的结果为true?
 
    A. undefined == null
    B. isNaN(“100”) ——不好意思,isNaN乱入了,见谅
    C. parseInt(“1a”) === 1
    D. [ ] instanceof Array
 
答友精彩解析:
A. undefined == null 为true; undefined===null为false
 
B. 当传入NaN或能被转换成NaN的值(不能转成Number型数据的字符串、对象、undefined等非数字值),isNaN会返回true,即使是isNaN(“true”)。传入"100"会被先转成Number–>100,不为NaN,因此返回false
 
C. parseInt(“1a”)只会解析前面是数字的部分,即只解析"1",parseInt(“1a1”) === 1也为true
 
D. [ ]是个空数组
 
—— 隐式转换
 
答案:ACD

题解中还有其他宝藏信息,整理如下~ ヾ(•ω•`)o:

  1. 对于parseInt的考点(C选项的扩展),一位网友给出了其他常考的考点,放在第6点中
  2. 看下面一段代码:if ([]) console.log(true);
    结果输出了true
    其实[ ] == false,因为在等号比较时,如果有一边是Boolean值,会优先将左右两边的数据转为Number,Number([]) == 0Number(false)==0,因此[] == false
    但进行if判断时,会将数据转为Boolean类型,Boolean([])=true,所以可以输出true
  3. 关于js中涉及的隐式类型转换,此处有一篇好文可以参考:here,从双等号的比较延申到.toString()方法和.valueOf()方法,很赞( •̀ ω •́ )✧
    部分截图如下:
  4. 2==“2” 返回true(都转成了Number);2===“2"返回false,因为恒等号还要比较"数据类型”


4.2 Boolean类型转换

单选题:上述代码的输出结果为?
 
    A. false false false false false
    B. false true false false false
    C. false false true test Boolean
    D. 其他几项都不对
 
答友精彩解析:
1.当作为一个构造函数(带有运算符 new)调用时,Boolean() 将把它的参数转换成一个布尔值,并且返回一个包含该值的 Boolean 对象。
    如果作为一个函数(不带有运算符 new)调用时,Boolean() 只将把它的参数转换成一个原始的布尔值,并且返回这个值——强制类型转换
 
2.如果省略 value 参数,或者设置为 0、-0、null、""、false、undefined 或 NaN,则该对象设置为 false。否则设置为 true(即使 value 参数是字符串 “false”)
 
答案:A
 
上面讲的是Boolean()的转换,还有一个关于逻辑非的转换,在第4.5点的题里一起写



4.3 加号与减号

单选题:如下代码输出的结果是什么?
 
    console.log( 1+ “2”+“2”);
    console.log( 1+ +“2”+“2”);
    console.log( “A”-“B”+“2”);
    console.log( “A”-“B”+2);
 
    A. 122 122 NaN NaN
    B. 122 32 NaN NaN2
    C. 122 32 NaN2 NaN
    D. 122 32 NaN2 NaN2
 
答友精彩解析:

  • 数字和字符串相加,会将数字转为字符串,所以结果是字符串拼接,第一句输出"122"
  • +“2”,这里的一元运算符+,会将字符串转为数字,于是1+ +“2” = 1+2 = 3,再与后面的字符串合并,所以第二句输出”32“
  • 减号会将减号两边都先转化成数字,而Number(“A”)、Number(“B”)结果是NaN,减法操作中,只要有一方为NaN,结果都是NaN,因此第三句是NaN和"2"的拼接,结果为NaN2(第4.1点中提到,双等号其中一方为NaN,结果为false)
  • 根据前一句的解析,“A”-"B"结果为NaN,与数字2相加,结果还是NaN
     
    —— 隐式转换
     
    答案:C


4.4 API强制类型转换

不定项选题:对于代码var a = 10.42; 取出a的整数部分,以下代码哪些是正确的?
 
    A. parseInt( a );
    B. Math.floor( a );
    C. Math.ceil( a );
    D. a.split(’.’)[0];
 
答友精彩解析:
A. parseInt转换为整数,默认为10进制,结果为10
B.floor向下取整,结果为10 —— floor是地板的意思,向下取整,辅助记忆
C.ceil向上取整,结果为11
D.split操作数必须是正则或字符串,结果为TypeError
 
答案:AB



4.5 new String 与 ' '

不定项选题:下面哪些执行结果为true()?
 
    A. ‘foo’ == new function() return String(‘foo’); ;
    B. ‘foo’ == new function() return new String(‘foo’); ;
    C. [] == 0
    D. ![]
    E: !0
 
分析:
AB选项的分析可以看这两篇文章:文一文二
C.前面讲解双等号时也提到过,Number([])结果是0,因此C选项正确
D.一位牛友给出了一个很赞的解析,另一位牛友的提问帮助我们理解,概括如下:

  • 牛友观点:对象总等于真
  • 问:那为什么在控制台测试时, == true, === true得到的结果均为false呢?(以下截图是我模拟的,有误之处还请指正)
  • 答:因为双等号有一方为布尔值时,会先将两边都转为Number类型,所以,在控制台测试 == true和 === true,实际上是测试 == 1, === 1,所以结果才都是false。因此,如果你想要测试"对象总等于真",应该使用 ! 和!!

    对象是引用类型的值,引用地址是判断对象为不为真的依据,每一个对象都有自己的引用地址,因此每一个对象都必然为真,而不是的属性和属性值,没有属性和属性值只能说他是一个空对象,空对象和其他对象一样都有引用地址(原文地址

 
E.由于Boolean(0) == false,因此!0 = true;,E选项正确
 
答案:BCE



5.API使用

5.1 map函数

以下代码执行后,array的结果是?
let array = [,1,,2,,3];
array = array.map((i)=>++i);

A. [,2,,3,,4](为了看得清楚些,使用了中文的逗号,本应是英文半角的逗号)
B. [NaN, 2, NaN, 3, NaN,4]
C. [1,2,1,3,1,4]
D. [null, 2, null, 3, null, 4]
 
分析:
摘自这篇文章
ES5:

  • 在大多数情况下会忽略空位,例如forEach()、for in、filter()、every()、reduce()和some()都会跳过空位,
  • map()会跳过空位,但会保留这个值,join()和toString()会将空位与undefined以及null处理成空字符串

ES6则是将空位转为undefined:

  • 例如Array.form()方法会将数组的空位转为undefined
  • 扩展运算符也会将空位转为undefined,
  • copyWithin()会连同空位一起拷贝
  • for of循环也会遍历空位并将值作为undefined,
  • includes()、entries()、keys()、values()、find()和findIndex()等会将空位处理成undefined

 
答案:A



5.2 parseInt函数

第4点的那道题的题解中,有网友给出了parseInt函数的其他常考考点,此处截图出来:


其中提到的易考点:parseInt函数的第二个参数——数组的下标,经典题如下:

var arr = [1,2,3,2,5];
console.log(arr.map(parseInt));// [1, NaN, NaN, 2, NaN]

parseInt函数有三个参数,分别是:数组元素、该元素下标、数组本身
因此,这个过程其实是这样的:

arr.map( (i)=>parseInt(arr[i], i, arr) );
/*
计算过程如下,第三个参数是数组本身,此处省略不写:
parseInt(1,0) —— 十进制,1在0-9之间,输出1
parseInt(2,1) —— 进制小于2,返回NaN
parseInt(3,2) —— 二进制,但3不在0-1之间,输出NaN
parseInt(2,3) —— 三进制,2在0-2之间,输出2
parseInt(5,4) —— 四进制,5不在0-3之间,输出NaN
最终结果为:[1, NaN, NaN, 2, NaN]
*/


6. 立即执行函数

单选题1:假设 output 是一个函数,输出一行文本。下面的语句输出结果是什么?
 
output(typeof (function() output(“Hello World!”))());
 
    A. undefined Hello World!
    B. Object
    C. String
    D. function
    E. Hello World! undefined

题目给的代码看起来不太方便,于是我把它们放到编辑器里,帮助看清括号的归属。
typeof是可以不需要括号的,就像这样:

题目里紧挨着typeof的括号应该是用于构成后面的立即执行函数的,因此,我把代码的排版改成这样:

output( typeof 
    (
    function() 
	output("Hello World!")
	
    )()
);

分析:
output是一个用于输出文本的的函数

  • 先执行立即执行函数,调用output函数,输出"Hello World!",
  • 然后output出这个立即执行函数的返回值,由于没有写return,默认会返回undefined,所以输出undefined

答案:E



7. ES5的变量提升

(function() 

    var x=foo();

    var foo=function foo() 
        return "foobar"
    ;
    return x;
)();

单选题1:上述代码执行结果为?
 
    A. foo()
    B. 类型错误
    C. undefined
    D. foobar
 

答友精彩解析:

  • 变量提升,但是函数表达式不会提升。
  • x在foo之前定义,此时foo是undefined。运行到x = foo();时,会报错TypeError: foo is not a function。
  • 如果把x定义放在foo的后面,就不会报错

    变量提升之后,应该是这样的:
    var x;
    var foo;
    x = foo(); //此时的foo还只是undefined,不是函数
    foo = function foo();
     
    答案:B
    这里还有一篇好文:here



单选题2:写出下面代码的运行结果

var a,b;
(function()
    alert(a);
    alert(b);
    var a=b=3;
    alert(a);
    alert(b);
)();
alert(a);
alert(b);

A. undefined,undefined,3,3,undefined,3
B. undefined,undefined,3,3,undefined,undefined
C. 0,0,3,3,undefined,undefined
D. undefined,undefined,3,3,0,0
 
分析:立即执行函数里,变量a和b的声明会提升到函数最前头,所以,第一个alert出的a是函数里的局部变量a。整段代码经变量提升后,可以看作是这样的:

var a,b;
(function()
	var a;
    alert(a); // 此处的a是局部变量a,未初始化,为undefined
    alert(b); // 此处的b是全局变量b,未初始化,为undefined
    a=b=3; // 全局b=3,局部a=3
    alert(a); // 输出3
    alert(b); // 输出3
)();
alert(a); // 全局a,为undefined
alert(b); // 全局b,为3

因此,答案选A



8.JS对象转基本类型

不定项选题:以下哪些代码执行后i的值为10:
 
    A. let i =1 +
            valueOf() return 9;
         ;
    B. let i = 0;
        new Array(10).forEach(() =>
            i++;
         );
    C. let i = parseInt(‘0xA’);
    D. let i = 5;
         function a(i)
            i *= 2;
         
         a(i);
 
分析:可以看这篇文章:here
 
A. 数字1和一个对象相加,会触发"对象–>基本类型"机制。
     由于是加法运算,且该对象重写了ValueOf函数,根据文章描述,该对象会根据重写的ValueOf函数,转变成Number类型,也就是9;
     式子就转变为let i = 1+ 9 = 10;,因此返回的是10
 
B.new Array(10)创建了数组但未初始化,里面都是empty,forEach不处理为空的数组元素,即不会执行回调函数,因此,B选项的结果 i 还是0
 
C.parseInt可以识别‘0x’,‘0x’代表十六进制,十六进制的A是10,因此C选项结果为10
 
D.向函数a传入基本数据类型的数据 i 作为形参,在a函数的作用域内改变了这个形参的值,但不会影响全局中的 i 本身,因为传的是值,相当于深拷贝(如果传入的是复杂数据类型的数据,才会影响全局变量,因为传的是引用,相当于浅拷贝)

 
关于"JS对象转为基本类型"这个知识点,还有一篇好文:here
 
答案:AC



9.W3C标准盒模型

单选题1:在W3C标准盒模型中,默认情况下块元素的总宽度为?
    A. content
    B. content + 2 * padding
    C. content + 2 * padding + 2 * border
    D. content + 2 * padding + 2 * border + 2 * margin
 
答友精彩解析:
W3C标准盒子模型 = margin + border + padding + width (width = content)
IE盒子模型 = margin + width (width = border + padding + content)
 
这道题问的是元素的宽度,不是盒子的宽度
 
答案:A




单选题2:CSS盒子模型中()是透明的,这部分可以显示背景
 
    A. border
    B. margin
    C. padding
    D. content
 
分析:
    CSS3中,新增了background-origin属性,
    默认值是padding-box,代表从padding区域开始放置图片,其他区域平铺,本题考的应该是默认情况
    如果background-origin值为content-box代表从content区域放置图片;
    如果值为border-box代表从border区域就放置图片了
 
可以参考我的这篇文章
 
答案:C




单选题3:根据规范,以下 HTML 和 CSS 代码解析后, container.clientWidth的值是:
 
    A. 200
    B. 240
    C. 280
    D. 300

<style>
	#container 
		width: 200px;
		height: 200px;
		padding: 20px;
		margin: 20px;
		border: solide 10px black;
	
</style>

<div id="container">content</div>

分析:官方给出的element.clientWidth是这样的:
 

内联元素以及没有 CSS 样式的元素的 clientWidth 属性值为 0。Element.clientWidth 属性表示元素的内部宽度,以像素计。该属性包括内边距 padding,但不包括边框 border、外边距 margin 和垂直滚动条(如果有的话)

官网链接:here
因此,本题中的container.clientWidth = width + padding * 2 = 200 + 20 * 2 = 240
 
答案:B




单选题4:当margin-top、padding-top的值是百分比时,分别是如何计算的?
 
    A. 相对父级元素的height,相对自身的height
    B. 相对最近父级块级元素的height,相对自身的height
    C. 相对父级元素的width,相对自身的width
    D. 相对最近父级块级元素的width,相对最近父级块级元素的width
 
答友精彩解析:可参考《CSS权威指南(第三版)》中第220页‘百分数和外边距’说明:“百分数是相对于父元素的width计算的,所以如果父元素的width以某种方式发生变化,百分数也会变化”。
 
我OS:这位大佬太6了真的
 
答案:D



10.其他

刷题的时候出现频率不那么高,但觉得很有必要学习和拓展的知识点,暂时放在”其他“中

10.1 margin塌陷问题

<div style="width: 100px; height: 100px; margin-bottom: 100px;"></div>
<div style="width: 100px; height: 100px; margin-top: 200px;"></div>

单选题:根据上述代码,两个div元素垂直间距为?
    A. 100px
    B. 200px
    C. 300px
    D. 400px
 
分析:可以看这篇文章的解释

  • margin重叠问题发生在垂直方向上
  • 如果div没有加边框,也没有加文字内容,即div没有被封起来或填充时,会出现margin重叠的问题,即垂直相邻边界会重合
  • 最终的margin值计算方法如下:
    a、全部都为正值,取最大者;
    b、不全是正值,则都取绝对值,然后用正值减去最大值;
    c、没有正值,则都取绝对值,然后用0减去最大值

 
因此本题的div图示应该是这样的:

 
答案:B



10.2 promise的all方法

单选题:下面关于promise的all方法说法错误的是?
 
    A. promise.all(iterable),参数是一个数组
    B. 只有这个数组中的所有promise实例都resolve之后才会触发其返回的promise实例的then
    C. 只要其中有任何一个promise实例被reject,那么最终的promise实例将触发catch
    D. 触发then时可以只带上iterable参数中的部分值,也可以带所有值。
 
答友精彩解析:
    iterable是一个全部为promise对象的数组,只要数组中有一个promise实例被reject,那么最终的promise触发catch,只有数组中全部promise实例都resolve才会触发then,并且要带上iterable中全部promise,其中promise实例将会被结果代替
 
也可以参考这篇文章:here
答案:D



10.3 浏览器渲染流程与页面加载过程

单选题:浏览器渲染流程,以下哪个顺序是正确的?
 
    1构建render树
    2绘制render树
    3布局render树
    4解析HTML并构建DOM树
 
    A. 1432
    B. 4123
    C. 4132
    D. 1423
 
可以参考这篇文章:here
 
答案:C




不定项选择题:关于页面加载过程,以下描述正确的有哪些?
 
    A. 页面加载 html 中的外联样式表时,不会阻塞后面的 JS 代码执行
    B. 由于 html 的层次结构已经是树状结构,因此可以实现边加载边生成 DOM 树
    C. 修改元素的颜色会造成重绘,同时触发回流
    D. 页面所有资源加载完毕后,会触发 onload 事件
 
分析:

  1. css加载不会阻塞DOM树的解析
  2. css加载会阻塞DOM树的渲染
  3. css加载会阻塞后面js语句的执行

 
答案:BD



10.4 HTML语义化

单选题:关于HTML语义化,以下哪个说法是正确的?
 
    A. 语义化的HTML有利于机器的阅读,如PDA手持设备、搜索引擎爬虫;但不利于人的阅读
    B. Table 属于过时的标签,遇到数据列表时,需尽量使用 div 来模拟表格
    C. 语义化是HTML5带来的新概念,此前版本的HTML无法做到语义化
    D. header、article、address都属于语义化明确的标签
 
分析:

  • A. HTML语义化不仅有利于机器阅读,还便于开发者阅读和写出更优雅的代码,A错误
  • B.应尽可能少地使用无语义的标签div和span;使用表格时,标题要用caption,表头用thead,主体部分用tbody包围,尾部用tfoot包围。表头和一般单元格要区分开,表头用th,单元格用td,B错误
  • C.HTML5新增了一些语义化标签,不代表之前没有语义化标签,C错误
  • D.HTML5新增了一些语义化标签,如:header、article、nav、footer;address定义了地址格式,也是语义化标签,D正确
    参考博客:here
     
    答案:D


10.5 position定位

单选题:关于position定位,下列说法错误的是?
 
    A. fixed元素,可定位于相对于浏览器窗口的指定坐标,它始终是以 body 为依据
    B. relative元素以它原来的位置为基准偏移,在其移动后,原来的位置不再占据空间
    C. absolute 的元素,如果它的父容器设置了position属性,并且 position的属性值为 absolute 或者 relative,那么就会依据父容器进行偏移
    D. fixed 属性的元素在标准流中不占位置
 
官网截图:

其中,fixed一般被称为固定定位
另外,relative元素以它原来的位置为基准偏移,在其移动后,原来的位置依然占据空间;absolute和fixed则是脱离文档流,原来位置不再保留
 
也可以参考这篇文章:here
 
答案:B



10.6 回流和重绘

var obj = document.getElementById("test");

不定项选题:以下哪些操作会触发Reflow?
 
    A. alert(obj.className)
    B. alert(obj.offsetHeight)
    C. obj.style.height = “100px”
    D. obj.style.color = “red”
 
答友给了一篇好文:here,里面详细解说了浏览器浏览原理以及影响页面渲染速度的重要原因:回流和重绘,可以与第9.3点联系
 
文中列举了导致回流Reflow的原因:

鼠标滑过、点击……只要这些行为引起了页面上某些元素的占位面积、定位方式、边距等属性的变化,都会引起它内部、周围甚至整个页面的重新渲染

导致重绘Repaint的原因:

如果只是改变某个元素的背景色、文字颜色、边框颜色等等不影响它周围或内部布局的属性,将只会引起浏览器重绘

可能导致发生回流的情况(此处仅列出几个,具体请看文章):