0408JS面经

24.如何判断一个对象是否为数组?

利用typeof除了array和null判断为object外,其他的都可以正常判断

不可以使用typeof,typeof返回结果包括:number、boolean、string、object、undefined、function等6种基本数据类型,不包括Array
第一种方法:对于一个网页或者一个全局作用域,可使用 instanceof 操作符。这个操作符是检测对象的原型链是否指向构造函数的prototype对象的。instanceof 是用来判断 A 是否为 B 的实例.

[] instanceof Array; //true‘
if(value instanceof Array{
//对数组执行某些操作
}

对象的constructor 属性

var arr = [1,2,3,1];
console.log(arr.constructor === Array); // true

instanceof操作符的问题在于,它假定只有一个全局执行环境。如果网页中包含多个框架,实际上就存在两个以上不同的全局执行环境,从而存在两个以上不同版本的Array构造函数。如果从一个框架向另一个框架传入一个数组,那么传入的数组与在第二个框架中原生创建的数组分别具有各自不同的构造函数。由于每个iframe都有一套自己的执行环境,跨frame实例化的对象彼此是不共享原型链的,因此导致上述检测代码失效.
为了解决这个问题,ES5新增了Array.isArray()方法。
第二种方法:使用 ECMAScript 5 新增的 Array. isArray()方法。这个方法的目的是最终确定某个值到底是不是数组,而不管它实在哪个全局执行环境中创建的。

if(Array.isArray(value){
})

IE9+、 Firefox 4+、Safari 5+、Opera 10.5+和Chrome都实现了这个方法。但是在*IE8之前的版本是不支持的,看浏览器支不支持
第三种方法:使用 Object. prototype 上的原生 toString()方法判断。

Object.prototype.toString.call( [] ) === '[object Array]'  // true

第四种方法:使用 原型链 来完成判断

[].__proto__ === Array.prototype  // true

综上所述,我们可以综合上面的几种方法,有一个当前的判断数组的最佳写法

var arr = [1,2,3];
var arr2 = [{ name : 'jack', age : 22 }];
function isArrayFn(value){
    // 首先判断浏览器是否支持Array.isArray这个方法
    if (typeof Array.isArray === "function") {
        return Array.isArray(value);
    }else{
        return Object.prototype.toString.call(value) === "[object Array]";
        // return obj.__proto__ === Array.prototype;
    }
}
console.log(isArrayFn(arr));  // true
console.log(isArrayFn(arr2));  // true   

为何我们不直接使用原型链的方式判断(兼容性好),而是先判断浏览器支不支持Array.isArray()这个方法,如果不支持才使用原型链的方式呢?我们可以从代码执行效率上看:Array.isArray()这个方法的执行速度比原型链的方式快了近一倍

25.

答案:

1、defer 和 async 的网络加载过程是一致的,都是异步执行。
2、区别在于加载完成之后什么时候执行,可以看出 defer 是文档所有元素解析完成之后才执行的。
3、如果存在多个 defer 脚本,那么它们是按照顺序执行脚本的,而 async,无论声明顺序如何,只要加载完成就立刻执行
解析:

无论

嵌入代码的解析=执行 外部文件的解析=下载+执行

script 标签存在两个属性,defer 和 async,这两个属性只对外部文件有效.

只有一个脚本的情况

<script src = "a.js" />

没有 defer 或 async 属性,浏览器会立即下载并执行相应的脚本,并且在下载和执行时页面的处理会停止。

<script defer src = "a.js" />

有了 defer 属性,浏览器会立即下载相应的脚本,在下载的过程中页面的处理不会停止,等到文档解析完成脚本才会执行。

<script async src = "a.js" />

有了 async 属性,浏览器会立即下载相应的脚本,在下载的过程中页面的处理不会停止,下载完成后立即执行,执行过程中页面处理会停止。

<script defer async src = "a.js" />

如果同时指定了两个属性, 则会遵从 async 属性而忽略 defer 属性。

多个脚本的情况
这里只列举两个脚本的情况:

<script src = "a.js"> </script>
<script src = "b.js"> </script>

没有 defer 或 async 属性,浏览器会立即下载并执行脚本 a. js,在 a. js 脚本执行完成后才会下载并执行脚本 b. js,在脚本下载和执行时页面的处理会停止。

<script defer src = "a.js"> </script>
<script defer src = "b.js"> </script>

有了 defer 属性,浏览器会立即下载相应的脚本 a. js 和 b. js,在下载的过程中页面的处理不会停止,等到文档解析完成才会执行这两个脚本。HTML5 规范要求脚本按照它们出现的先后顺序执行,因此第一个延迟脚本会先于第二个延迟脚本执行,而这两个脚本会先于 DOMContentLoaded 事件执行。 在现实当中,延迟脚本并不一定会按照顺序执行,也不一定会在 DOMContentLoaded 事件触发前执行,因此最好只包含一个延迟脚本。

<script async src = "a.js"> </script>
<script async src = "b.js"> </script>

有了 async 属性,浏览器会立即下载相应的脚本 a. js 和 b. js,在下载的过程中页面的处理不会停止,a. js 和 b. js 哪个先下载完成哪个就立即执行,执行过程中页面处理会停止,但是其他脚本的下载不会停止。标记为 async 的脚本并不保证按照制定它们的先后顺序执行。异步脚本一定会在页面的 load 事件前执行,但可能会在 DOMContentLoaded 事件触发之前或之后执行。

26. Object. prototype. toString. call() 和 instanceOf 和 Array. isArray() 区别好坏

  • Object. prototype. toString. call()
    优点:这种方法对于所有基本的数据类型都能进行判断,即使是 null 和 undefined 。
    缺点:不能精准判断自定义对象,对于自定义对象只会返回[object Object]
  • instanceOf
    优点:instanceof 可以弥补 Object. prototype. toString. call()不能判断自定义实例化对象的缺点。
    缺点: instanceof 只能用来判断对象类型,原始类型不可以。并且所有对象类型 instanceof Object 都是 true,且不同于其他两种方法的是它不能检测出 iframes。
  • Array. isArray()
    优点:当检测 Array 实例时,Array. isArray 优于 instanceof ,因为 Array. isArray 可以检测出 iframes
    缺点:只能判别数组

Object. prototype. toString. call()

每一个继承 Object 的对象都有 toString 方法,如果 toString 方法没有重写的话,会返回 [Object type],其中 type 为对象的类型。但当除了 Object 类型的对象外,其他类型直接使用 toString 方法时,会直接返回都是内容的字符串,所以我们需要使用 call 或者 apply 方法来改变 toString 方法的执行上下文。

const an = ["Hello", "An"];
an.toString(); // "Hello,An"
Object.prototype.toString.call(an); // "[object Array]"

这种方法对于所有基本的数据类型都能进行判断,即使是 null 和 undefined 。

Object.prototype.toString.call("An"); // "[object String]"
Object.prototype.toString.call(1); // "[object Number]"
Object.prototype.toString.call(Symbol(1)); // "[object Symbol]"
Object.prototype.toString.call(null); // "[object Null]"
Object.prototype.toString.call(undefined); // "[object Undefined]"
Object.prototype.toString.call(function() {}); // "[object Function]"
Object.prototype.toString.call({
    name: "An"
}); // "[object Object]"

缺点:不能精准判断自定义对象,对于自定义对象只会返回[object Object]

function f(name) {
    this.name = name;
}
var f1 = new f("martin");
console.log(Object.prototype.toString.call(f1)); //[object Object]

Object.prototype.toString.call(); // 常用于判断浏览器内置对象。

instanceof

instanceof 的内部机制是通过判断对象的原型链中是不是能找到类型的 prototype。

使用 instanceof 判断一个对象是否为数组,instanceof 会判断这个对象的原型链上是否会找到对应的 Array 的原型,找到返回 true,否则返回 false。

[] instanceof Array; // true

但 instanceof 只能用来判断对象类型,原始类型不可以。并且所有对象类型 instanceof Object 都是 true。

[] instanceof Object; // true

优点:instanceof 可以弥补 Object. prototype. toString. call()不能判断自定义实例化对象的缺点。

缺点:instanceof 只能用来判断对象类型,原始类型不可以。并且所有对象类型 instanceof Object 都是 true,且不同于其他两种方法的是它不能检测出 iframes

function f(name) {
    this.name = name;
}
var f1 = new f("martin");
console.log(f1 instanceof f); //true

Array. isArray()

  • 功能:用来判断对象是否为数组
  • instanceof 与 isArray

当检测 Array 实例时,Array. isArray 优于 instanceof ,因为 Array. isArray 可以检测出 iframes

var iframe = document.createElement("iframe");
document.body.appendChild(iframe);
xArray = window.frames[window.frames.length - 1].Array;
var arr = new xArray(1, 2, 3); // [1,2,3]

// Correctly checking for Array
Array.isArray(arr); // true
Object.prototype.toString.call(arr); // true
// Considered harmful, because doesn't work though iframes
arr instanceof Array; // false

缺点:只能判别数组
Array. isArray() 与 Object. prototype. toString. call()
Array. isArray()是 ES5 新增的方法,当不存在 Array. isArray() ,可以用 Object. prototype. toString. call() 实现。

if (!Array.isArray) {
    Array.isArray = function(arg) {
        return Object.prototype.toString.call(arg) === "[object Array]";
    };
}

27. 什么是面向对象?

答案:面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。

解析:
面向对象和面向过程的异同

  • 面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。
  • 面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。

28. 你对松散类型的理解

答案:
JavaScript 中的变量为松散类型,所谓松散类型就是指当一个变量被申明出来就可以保存任意类型的值,就是不像 SQL 一样申明某个键值为 int 就只能保存整型数值,申明 varchar 只能保存字符串。一个变量所保存值的类型也可以改变,这在 JavaScript 中是完全有效的,只是不推荐。相比较于将变量理解为“盒子“,《JavaScript 编程精解》中提到应该将变量理解为“触手”,它不保存值,而是抓取值。这一点在当变量保存引用类型值时更加明显。

JavaScript 中变量可能包含两种不同的数据类型的值:基本类型和引用类型。基本类型是指简单的数据段,而引用类型指那些可能包含多个值的对象。

29. JS 严格模式和正常模式

答案:严格模式使用"use strict";

作用:

  • 消除 Javascript 语法的一些不合理、不严谨之处,减少一些怪异行为;
  • 消除代码运行的一些不安全之处,保证代码运行的安全;
  • 提高编译器效率,增加运行速度;
  • 为未来新版本的 Javascript 做好铺垫。
    表现:
  • 严格模式下, delete 运算符后跟随非法标识符(即 delete 不存在的标识符),会抛出语法错误; - 非严格模式下,会静默失败并返回 false
  • 严格模式中,对象直接量中定义同名属性会抛出语法错误; 非严格模式不会报错
  • 严格模式中,函数形参存在同名的,抛出错误; 非严格模式不会
  • 严格模式不允许八进制整数直接量(如:023)
  • 严格模式中,arguments 对象是传入函数内实参列表的静态副本;非严格模式下,arguments 对象里的元素和对应的实参是指向同一个值的引用
  • 严格模式中 eval 和 arguments 当做关键字,它们不能被赋值和用作变量声明
  • 严格模式会限制对调用栈的检测能力,访问 arguments. callee. caller 会抛出异常
  • 严格模式 变量必须先声明,直接给变量赋值,不会隐式创建全局变量,不能用 with,
  • 严格模式中 call apply 传入 null undefined 保持原样不被转换为 window

解析:

一、概述

除了正常运行模式,ECMAscript 5 添加了第二种运行模式:“严格模式”(strict mode)。顾名思义,这种模式使得 Javascript 在更严格的条件下运行。
设立"严格模式"的目的,主要有以下几个:

  • 消除 Javascript 语法的一些不合理、不严谨之处,减少一些怪异行为;
  • 消除代码运行的一些不安全之处,保证代码运行的安全;
  • 提高编译器效率,增加运行速度;
  • 为未来新版本的 Javascript 做好铺垫。

"严格模式"体现了 Javascript 更合理、更安全、更严谨的发展方向,包括 IE 10 在内的主流浏览器,都已经支持它,许多大项目已经开始全面拥抱它。

另一方面,同样的代码,在"严格模式"中,可能会有不一样的运行结果;一些在"正常模式"下可以运行的语句,在"严格模式"下将不能运行。掌握这些内容,有助于更细致深入地理解 Javascript,让你变成一个更好的程序员。

二、进入标志

进入"严格模式"的标志,是下面这行语句:

"use strict";

老版本的浏览器会把它当作一行普通字符串,加以忽略。

三、如何调用
"严格模式"有两种调用方法,适用于不同的场合。
3. 1 针对整个脚本文件
将"use strict"放在脚本文件的第一行,则整个脚本都将以"严格模式"运行。如果这行语句不在第一行,则无效,整个脚本以"正常模式"运行。如果不同模式的代码文件合并成一个文件(不利于),这一点需要特别注意。

(严格地说,只要前面不是产生实际运行结果的语句,"use strict"可以不在第一行,比如直接跟在一个空的分号后面。)

<script>
    "use strict";
    console.log("这是严格模式。");
  </script>

  <script>
    console.log("这是正常模式。");kly, it's almost 2 years ago now. I can admit it now - I run it on my school's network that has about 50 computers.
  </script>

上面的代码表示,一个网页中依次有两段 Javascript 代码。前一个 script 标签是严格模式,后一个不是。

  1. 2 针对单个函数
    将"use strict"放在函数体的第一行,则整个函数以"严格模式"运行。
function strict() {
    "use strict";
    return "这是严格模式。";
}

function notStrict() {
    return "这是正常模式。";
}
  1. 3 脚本文件的变通写法
    因为第一种调用方法不利于文件合并,所以更好的做法是,借用第二种方法,将整个脚本文件放在一个立即执行的匿名函数之中。
(function() {
    "use strict"; // some code here

})();

四、语法和行为改变
严格模式对 Javascript 的语法和行为,都做了一些改变。
4. 1 全局变量显式声明
在正常模式中,如果一个变量没有声明就赋值,默认是全局变量。严格模式禁止这种用法,全局变量必须显式声明。

"use strict";

v = 1; // 报错,v未声明

for (i = 0; i < 2; i++) {
    // 报错,i未声明
}//因此,严格模式下,变量都必须先用 var 命令声明,然后再使用。

Javascript 语言的一个特点,就是允许"动态绑定",即某些属性和方法到底属于哪一个对象,不是在编译时确定的,而是在运行时(runtime)确定的

严格模式对动态绑定做了一些限制。某些情况下,只允许静态绑定。也就是说,属性和方法到底归属哪个对象,在编译阶段就确定。这样做有利于编译效率的提高,也使得代码更容易阅读,更少出现意外。
具体来说,涉及以下几个方面。
1)禁止使用 with 语句
因为 with 语句无法在编译时就确定,属性到底归属哪个对象。

"use strict";

var v = 1;

with(o) { // 语法错误
    v = 2;
}

2)创设 eval 作用域
正常模式下,Javascript 语言有两种变量作用域(scope):全局作用域和函数作用域。严格模式创设了第三种作用域:eval 作用域。

正常模式下,eval 语句的作用域,取决于它处于全局作用域,还是处于函数作用域。严格模式下,eval 语句本身就是一个作用域,不再能够生成全局变量了,它所生成的变量只能用于 eval 内部。

"use strict";

var x = 2;

console.info(eval("var x = 5; x")); // 5

console.info(x); // 2,没有受到影响
  1. 3 增强的安全措施
    1)禁止 this 关键字指向全局对象
function f() {
    return !this;
} // 返回false,因为"this"指向全局对象,"!this"就是false
function f() {
    "use strict";
    return !this;
} // 返回true,因为严格模式下,this的值为undefined,所以"!this"为true。

因此,使用构造函数时,如果忘了加 new,this 不再指向全局对象,而是报错。
补充:js中的this指向问题https://blog.csdn.net/foreverwy/article/details/78150563

function f() {
    "use strict";

    this.a = 1;
}

f(); // 报错,this未定义

2)禁止在函数内部遍历调用栈 ????

function f1() {
    "use strict";

    f1.caller; // 报错
    //如果一个函数f是在全局作用域内被调用的,则f.caller为null,
    //相反,如果一个函数是在另外一个函数作用域内被调用的,则f.caller指向调用它的那个函数.

    f1.arguments; // 报错
    //function.arguments 已经被废弃了, 现在推荐的做法是使用函数内部可用的 arguments 对象来访问函数的实参。

//在函数递归调用的时候(在某一刻同一个函数运行了多次,也就是有多套实参),那么 arguments 属性的值是最近一次该函数调用时传入的实参
}

f1();
  1. 4 禁止删除变量
    严格模式下无法删除变量。只有 configurable 设置为 true 的对象属性,才能被删除。
"use strict";

var x;

delete x; // 语法错误

var o = Object.create(null, {
    'x': {
        value: 1,
        configurable: true
    }
});

delete o.x; // 删除成功
  1. 5 显式报错

正常模式下,对一个对象的只读属性进行赋值,不会报错,只会默默地失败。严格模式下,将报错。

"use strict";

var o = {};

Object.defineProperty(o, "v", {
    value: 1,
    writable: false
});

o.v = 2; // 报错

严格模式下,对一个使用 getter 方法读取的属性进行赋值,会报错。???

"use strict";

var o = {
    get v() {
        return 1;
    }
};

o.v = 2; // 报错

严格模式下,对禁止扩展的对象添加新属性,会报错。

"use strict";

var o = {};

Object.preventExtensions(o);

o.v = 1; // 报错

严格模式下,删除一个不可删除的属性,会报错。

"use strict";

delete Object.prototype; // 报错
  1. 6 重名错误

严格模式新增了一些语法错误。

(1)对象不能有重名的属性

正常模式下,如果对象有多个重名属性,最后赋值的那个属性会覆盖前面的值。严格模式下,这属于语法错误。

"use strict";

var o = {
    p: 1,
    p: 2
}; // 语法错误

2)函数不能有重名的参数

正常模式下,如果函数有多个重名的参数,可以用 arguments[i]读取。严格模式下,这属于语法错误。

"use strict";

function f(a, a, b) { // 语法错误

    return;

}
  1. 7 禁止八进制表示法

正常模式下,整数的第一位如果是 0,表示这是八进制数,比如 0100 等于十进制的 64。严格模式禁止这种表示法,整数第一位为 0,将报错。

"use strict";

var n = 0100; // 语法错误
  1. 8 arguments 对象的限制

arguments 是函数的参数对象,严格模式对它的使用做了限制。

(1)不允许对 arguments 赋值

"use strict";

arguments++; // 语法错误

var obj = {
    set p(arguments) {}
}; // 语法错误

try {} catch (arguments) {} // 语法错误

function arguments() {} // 语法错误

var f = new Function("arguments", "'use strict'; return 17;"); // 语法错误

(2)arguments 不再追踪参数的变化

function f(a) {
    a = 2;

    return [a, arguments[0]];
}

f(1); // 正常模式为[2,2]

function f(a) {
    "use strict";

    a = 2;

    return [a, arguments[0]];
}

f(1); // 严格模式为[2,1]

3)禁止使用 arguments. callee

这意味着,你无法在匿名函数内部调用自身了。

"use strict";

var f = function() {
    return arguments.callee;
};

f(); // 报错
  1. 9 函数必须声明在顶层

将来 Javascript 的新版本会引入"块级作用域"。为了与新版本接轨,严格模式只允许在全局作用域或函数作用域的顶层声明函数。也就是说,不允许在非函数的代码块内声明函数。

"use strict";

if (true) {
    function f() {} // 语法错误
}

for (var i = 0; i < 5; i++) {
    function f2() {} // 语法错误
}
  1. 10 保留字

为了向将来 Javascript 的新版本过渡,严格模式新增了一些保留字:implements, interface, let, package, private, protected, public, static, yield。

使用这些词作为变量名将会报错。

function package(protected) { // 语法错误

    "use strict";

    var implements; // 语法错误

}

此外,ECMAscript 第五版本身还规定了另一些保留字(class, enum, export, extends, import, super),以及各大浏览器自行增加的 const 保留字,也是不能作为变量名的。

30. 移动端 click 事件、touch 事件、tap 事件的区别

300ms
  300ms问题是指在某个元素执行它的功能和执行touch事件之间有一个300毫秒的间隔。鼠标事件、焦点事件、浏览器默认行为(链接跳转)等相较于touch事件,都存在着300ms的延迟

  1. click 事件在移动端会有 200-300ms ms 的延迟,主要原因是苹果手机在设计时,考虑到用户在浏览网页时需要放大,所以,在用户点击的 200-300ms 之后,才触发 click,如果 200-300ms 之内还有 click,就会进行放大缩小。

  2. touch 事件是针对触屏手机上的触摸事件。现今大多数触屏手机 webkit 内核提供了 touch 事件的监听,让开发者可以获取用户触摸屏幕时的一些信息。其中包括:touchstart, touchmove, touchend, touchcancel 这四个事件,touchstart touchmove touchend 事件可以类比于 mousedown mouseover mouseup 的触发

  3. tap 事件在移动端,代替 click 作为点击事件,tap 事件被很多框架(如 zepto)封装,来减少这延迟问题, tap 事件不是原生的,所以是封装的,那么具体是如何实现的呢?

< script >
      function tap(ele, callback) {
          // 记录开始时间
          var startTime = 0,
              // 控制允许延迟的时间
              delayTime = 200,
              // 记录是否移动,如果移动,则不触发tap事件
              isMove = false;

          // 在touchstart时记录开始的时间
          ele.addEventListener('touchstart', function(e) {
              startTime = Date.now();
          });

          // 如果touchmove事件被触发,则isMove为true
          ele.addEventListener('touchmove', function(e) {
              isMove = true;
          });

          // 如果touchmove事件触发或者中间时间超过了延迟时间,则返回,否则,调用回调函数。
          ele.addEventListener('touchend', function(e) {
              if (isMove || (Date.now() - startTime > delayTime)) {
                  return;
              } else {
                  callback(e);
              }
          })
      }

  var btn = document.getElementById('btn');
  tap(btn, function() {
      alert('taped');
  }); <
  /script>

补充:点透问题
如果我们在移动端所有的 click 都替换为了 tap 事件,还是会触发点透问题的,因为实质是: 在同一个 z 轴上,z-index 不同的两个元素,上面的元素是一个绑定了 tap 事件的,下面是一个 a 标签,一旦 tap 触发,这个元素就会 display: none,而从上面的 tap 可以看出,有 touchstart、touchend,所以会 300ms 之后触发 click 事件,而 z-index 已经消失了,所以,触发了下面的 a 的 click 事件,注意: 我们认为 a 标签(超链接)默认是绑定了 click 事件的。而这种现象不是我们所期待的。
解决方案:
(1)使用fastclick插件
FastClick 是 FT Labs 专门为解决移动端浏览器 300 毫秒点击延迟问题所开发的一个轻量级的库。FastClick的实现原理是在检测到touchend事件的时候,会通过DOM自定义事件立即出发模拟一个click事件,并把浏览器在300ms之后的click事件阻止掉

(2)添加一个延迟,对上一个tap做延迟
tap(ele, function() {
    setTimeout(function() {
        ele.style.display = "none";
    }, 300);
});

这样,过了 300ms,那么 click 事件就不会触发在下面的 a 标签上了。
但这个方法有一个弊端,一次只能给一个元素去解决问题。

自我补充:DOMContentLoaded
当一个 HTML 文档被加载和解析完成后,DOMContentLoaded 事件便会被触发.“HTML 文档被加载和解析完成”是什么意思呢?或者说,HTML 文档被加载和解析完成之前,浏览器做了哪些事情呢?那我们需要从浏览器渲染原理来谈谈。
浏览器向服务器请求到了 HTML 文档后便开始解析,产物是 DOM(文档对象模型),到这里 HTML 文档就被加载和解析完成了。如果有 CSS 的会根据 CSS 生成 CSSOM(CSS 对象模型),然后再由 DOM 和 CSSOM 合并产生渲染树。有了渲染树,知道了所有节点的样式,下面便根据这些节点以及样式计算它们在浏览器中确切的大小和位置,这就是布局阶段。有了以上这些信息,下面就把节点绘制到浏览器上。所有的过程如下图所示:
在这里插入图片描述
现在你可能了解 HTML 文档被加载和解析完成前浏览器大概做了哪些工作,但还没完,因为我们还没有考虑现在前端的主角之一 JavaScript。

JavaScript 可以阻塞 DOM 的生成,也就是说当浏览器在解析 HTML 文档时,如果遇到

到这里,我们可以总结一下。当文档中没有脚本时,浏览器解析完文档便能触发 DOMContentLoaded 事件;如果文档中包含脚本,则脚本会阻塞文档的解析,而脚本需要等 CSSOM 构建完成才能执行。在任何情况下,DOMContentLoaded 的触发不需要等待图片等其他资源加载完成。
我们到这里一直在说同步脚本对网页渲染的影响,如果我们想让页面尽快显示,那我们可以使用异步脚本。HTML5 中定义了两个定义异步脚本的方法:defer 和 async。我们来看一看他们的区别。https://zhuanlan.zhihu.com/p/25876048

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值