new一个对象,这个过程中发生了什么?
var obj = new Object("name","sansan");
- 创建一个新对象,如:var obj = {};
- 新对象的_proto_属性指向构造函数的原型对象。
- 将构造函数的作用域赋值给新对象。(也所以this对象指向新对象)
- 执行构造函数内部的代码,将属性添加给obj中的this对象。
- 返回新对象obj。
数组中常用的方法
改变原数组
splice() 添加/删除数组元素
let a = [1, 2, 3, 4, 5, 6, 7];
let item = a.splice(0, 3); // [1,2,3]
console.log(a); // [4,5,6,7]
// 从数组下标0开始,删除3个元素
let item1 = a.splice(0,3,'添加'); // [4,5,6]
console.log(a); // ['添加',7]
// 从数组下标0开始,删除3个元素,并添加元素'添加'
sort() 数组排序
var array = [10, 1, 3, 4,20,4,25,8];
// 升序 a-b < 0 a将排到b的前面,按照a的大小来排序的
array.sort(function(a,b){
return a-b;
});
console.log(array); // [1,3,4,4,8,10,20,25];
// 降序
array.sort(function(a,b){
return b-a;
});
console.log(array); // [25,20,10,8,4,4,3,1];
pop() 删除一个数组中的最后的一个元素
shift() 删除数组的第一个元素
push() 向数组的末尾添加元素
unshift()向数组开头添加元素
reverse()
let a = [1,2,3];
a.pop(); // 3, 返回被删除的元素
console.log(a); // [1,2]
a.shift(); // 1
console.log(a); // [2]
a.push("末尾添加"); // 2 ,返回数组长度
console.log(a) ; [2,"末尾添加"]
a.unshift("开头添加"); // 3
console.log(a); //["开头添加", 2, "末尾添加"]
a.reverse(); // ["末尾添加", 2, "开头添加"]
console.log(a) // ["末尾添加", 2, "开头添加"]
copyWithin() 指定位置的成员复制到其他位置
let a = ['zhang', 'wang', 'zhou', 'wu', 'zheng'];
// 1位置开始被替换, 2位置开始读取要替换的 5位置前面停止替换
a.copyWithin(1, 2, 5);
// ["zhang", "zhou", "wu", "zheng", "zheng"]
fill() 填充数组
['a', 'b', 'c'].fill(7)
// [7, 7, 7]
['a', 'b', 'c'].fill(7, 1, 2)
// ['a', 7, 'c']
不改变原数组
join() 数组转字符串
let a= ['hello','world'];
let str2=a.join('+'); // 'hello+world'
cancat 合并两个或多个数组
let a = [1, 2, 3];
let b = [4, 5, 6];
//连接两个数组
let newVal=a.concat(b); // [1,2,3,4,5,6]
ES6扩展运算符...合并数组
let a = [2, 3, 4, 5]
let b = [ 4,...a, 4, 4]
console.log(a,b);
//[2, 3, 4, 5] [4,2,3,4,5,4,4]
indexOf() 查找数组是否存在某个元素,返回下标
let a=['啦啦',2,4,24,NaN]
console.log(a.indexOf('啦')); // -1
console.log(a.indexOf('啦啦')); // 0
ES7 includes() 查找数组是否包含某个元素 返回布尔
indexOf方法不能识别NaN
indexOf方法检查是否包含某个值不够语义化,需要判断是否不等于-1,表达不够直观
let a=['OB','Koro1',1,NaN];
a.includes(NaN); // true 识别NaN
a.includes('Koro1',100); // false 超过数组长度 不搜索
a.includes('Koro1',-3); // true 从倒数第三个元素开始搜索
slice() 浅拷贝数组的元素
//字符串也有一个slice() 方法是用来提取字符串的,不要弄混了。
let a = [{name: 'OBKoro1'}, {name: 'zhangsan'}];
let b = a.slice(0,1);
console.log(b, a);
// [{"name":"OBKoro1"}] [{"name":"OBKoro1"}]
a[0].name='改变原数组';
console.log(b,a);
// [{"name":"改变原数组"}] [{"name":"改变原数组"}]
遍历方法
forEach:按升序为数组中含有效值的每一项执行一次回调函数
1.无法中途退出循环,只能用return退出本次回调,进行下一次回调.
2.它总是返回 undefined值,即使你return了一个值。
every 检测数组所有元素是否都符合判断条件
如果数组中检测到有一个元素不满足, 则整个表达式返回false,且元素不会再进行检测
function isBigEnough(element, index, array) {
return element >= 10; // 判断数组中的所有元素是否都大于10
}
[12, 5, 8, 130, 44].every(isBigEnough); // false
[12, 54, 18, 130, 44].every(isBigEnough); // true
// 接受箭头函数写法
[12, 5, 8, 130, 44].every(x => x >= 10); // false
[12, 54, 18, 130, 44].every(x => x >= 10); // true
some 数组中的是否有满足判断条件的元素
如果有一个元素满足条件,则表达式返回true, 剩余的元素不会再执行检测
filter 过滤原始数组,返回新数组
map 对数组中的每个元素进行处理,返回新的数组
reduce 为数组提供累加器,合并为一个值
reduce() 方法对累加器和数组中的每个元素(从左到右)应用一个函数,最终合并为一个值
// 数组求和
let sum = [0, 1, 2, 3].reduce(function (a, b) {
return a + b;
}, 0);
// 6
// 将二维数组转化为一维 将数组元素展开
let flattened = [[0, 1], [2, 3], [4, 5]].reduce(
(a, b) => a.concat(b),
[]
);
// [0, 1, 2, 3, 4, 5]
ES6:find()& findIndex() 根据条件找到数组成员
这两个方法都可以识别NaN,弥补了indexOf的不足.
[1, 4, -5, 10,NaN].find((n) => Object.is(NaN, n));
// 返回元素NaN
[1, 4, -5, 10].findIndex((n) => n < 0);
// 返回索引2
ES6 keys()&values()&entries() 遍历键名、遍历键值、遍历键名+键值
for (let index of ['a', 'b'].keys()) {
console.log(index);
}
// 0
// 1
for (let elem of ['a', 'b'].values()) {
console.log(elem);
}
// 'a'
// 'b'
for (let [index, elem] of ['a', 'b'].entries()) {
console.log(index, elem);
}
// 0 "a"
// 1 "b"
判断对象是否为空
const isEmpty = (obj) => obj.keys().length !== 0;
判断对象是否是数组
方法一:使用 Object.prototype.toString 来判断是否是数组
function isArray(obj){
return Object.prototype.toString.call( obj ) === '[object Array]';
}
这里使用call来使 toString 中 this 指向 obj。进而完成判断
方法二:使用原型链 来完成判断
function isArray(obj){
return obj.__proto__ === Array.prototype;
}
基本思想: 实例如果是某个构造函数构造出来的那么 它的__proto__是指向构造函数的 prototype属性
继承有哪些方式?
- ES6中的class继承
class Animal {
constructor(name) {
this.name = name;
};
eat() {
console.log(this.name + '正在吃东西');
};
}
//继承动物类
class Cat extends Animal {
catchMouse(){
console.log(`${this.name}正在捉老鼠`);
}
}
var cat= new Cat('Tom猫');
cat.catchMouse();// Tom猫正在捉老鼠
- 原型继承
function Animal(name) {
this.name = name;
}
Animal.prototype.eat= function () {
console.log(this.name + '正在吃东西')
};
function Cat(furColor){
this.furColor = furColor ;
};
Cat.prototype = new Animal();
let tom = new Cat('black');
console.log(tom)
- 构造继承
- 寄生组合式继承
- 实例继承
call、apply、bind之间的关系
bind,apply,call三者都可以用来改变this的指向;
- 三者都可以用来改变
this
的指向 - 三者第一个参数都是this要指向的对象,也就是想指定的上下文,上下文就是指调用函数的那个对象。(点前的那个对象,没有就是全局window)
- 三者都可以传参,但是apply是数组,而call是有顺序的传入
- bind 是返回对应函数,便于稍后调用;apply 、call 则是立即执行
异步过程的构成要素有哪些?和异步过程是怎样的 ?
总结一下,一个异步过程通常是这样的:
- 主线程发起一个异步请求,相应的工作线程接收请求并告知主线程已收到(异步函数返回);
- 主线程可以继续执行后面的代码,同时工作线程执行异步任务;
- 工作线程完成工作后,通知主线程;
- 主线程收到通知后,执行一定的动作(调用回调函数)。
- 异步函数通常具有以下的形式:A(args..., callbackFn)。
- 它可以叫做异步过程的发起函数,或者叫做异步任务注册函数。
- args 和 callbackFn 是这个函数的参数。
所以,从主线程的角度看,一个异步过程包括下面两个要素:
- 发起函数(或叫注册函数) A。
- 回调函数 callbackFn。
它们都是在主线程上调用的,其中注册函数用来发起异步过程,回调函数用来处理结果。
举个具体的例子:
setTimeout(fn, 1000);
其中的 setTimeout 就是异步过程的发起函数,fn 是回调函数。
注意:前面说的形式 A(args..., callbackFn) 只是一种抽象的表示,并不代表回调函数一定要作为发起函数的参数。
例如:
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = xxx; // 添加回调函数
xhr.open('GET', url);
xhr.send(); // 发起函数
发起函数和回调函数就是分离的。
说说消息队列和事件循环
- 主线程在执行完当前循环中的所有代码后,就会到消息队列取出这条消息(也就是 message 函数),并执行它。
- 完成了工作线程对主线程的通知,回调函数也就得到了执行。
- 如果一开始主线程就没有提供回调函数,AJAX 线程在收到 HTTP 响应后,也就没必要通知主线程,从而也没必要往消息队列放消息。
异步过程的回调函数,一定不在当前的这一轮事件循环中执行
eval() 函数有什么用?
eval() 函数可计算某个字符串,并执行其中的的 JavaScript 代码。
字符串转数组
console.log(Object.values('abc')); // => [ 'a', 'b', 'c' ]
console.log(Array.from('abcd'));
console.log([...'abcd']);
console.log('abcd'.split(''));
console.log([].slice.call('abcd'));
构造元素重复的数组
可以使用 array.fill:
const arr = Array(6).fill(6);
console.log(arr); // => [ 6, 6, 6, 6, 6, 6 ]
构造元素连续的数组
// length 设置为你需要获取的整数的个数,index + 1 这个 1 可以替换为你要设置的第一个数的大小
const continuousIntegers = Array.from({ length: 10 }, (__, index) => index + 1);
console.log(continuousIntegers); // => [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
JS中如何将页面重定向到另一个页面?
- 使用
window.location.href =“https://www.onlineinterviewquestions.com/”
- 使用
location.replace: window.location.replace(" https://www.onlineinterviewquestions.com/;")
JS中的Array.splice()
和Array.slice()
方法有什么区别
var arr=[0,1,2,3,4,5,6,7,8,9];//设置一个数组
console.log(arr.slice(2,7));//2,3,4,5,6
console.log(arr.splice(2,7));//2,3,4,5,6,7,8
//由此我们简单推测数量两个函数参数的意义,
slice(start,end)第一个参数表示开始位置,第二个表示截取到的位置(不包含该位置)
splice(start,length)第一个参数开始位置,第二个参数截取长度
var x=y=[0,1,2,3,4,5,6,7,8,9]
console.log(x.slice(2,5));//2,3,4
console.log(x);[0,1,2,3,4,5,6,7,8,9]原数组并未改变
//接下来用同样方式测试splice
console.log(y.splice(2,5));//2,3,4,5,6
console.log(y);//[0,1,7,8,9]显示原数组中的数值被剔除掉了
如何在JS中动态添加/删除对象的属性?
咱们可以使用object.property_name = value
向对象添加属性,delete object.property_name
用于删除属性。
例如:
let user = new Object();
// adding a property
user.name='Anil';
user.age =25;
console.log(user);
delete user.age;
console.log(user);
解释一下什么是 promise ?
promise
是js中的一个对象,用于生成可能在将来产生结果的值。 值可以是已解析的值,也可以是说明为什么未解析该值的原因。
promise 可以有三种状态:
- pending:初始状态,既不是成功也不是失败
- fulfilled:意味着操作完全成功
- rejected:意味着操作失败
一个等待状态的promise对象能够成功后返回一个值,也能失败后带回一个错误 当这两种情况发生的时候,处理函数会排队执行通过then方法会被调用
数组去重复的方法有哪些
1.使用set
function uniquearray(array) { let unique_array= Array.from(set(array)) return unique_array; }
2.使用filter
function unque_array (arr) {
let unique_array = arr.filter(function(elem, index, self) {
return index == self.indexOf(elem);
})
return unique_array;
}
console.log(unique_array(array_with_duplicates));
3.使用for
循环
Array dups_names = ['Ron', 'Pal', 'Fred', 'Rongo', 'Ron'];
function dups_array(dups_names) {
let unique = {};
names.forEach(function(i) {
If (!unique[i]) {
unique[i] = true; }
});
return Object.keys(unique);} // Ron, Pal, Fred, Rongo
Dups_array(names);
undefined,null 和 undeclared 有什么区别?
1.null表示"没有对象",即该处不应该有值,转为数值时为0。典型用法是:
(1) 作为函数的参数,表示该函数的参数不是对象。
(2) 作为对象原型链的终点。
2.undefined表示"缺少值",就是此处应该有一个值,但是还没有定义,转为数值时为NaN。典型用法是:
(1)变量被声明了,但没有赋值时,就等于undefined。
(2) 调用函数时,应该提供的参数没有提供,该参数等于undefined。
(3)对象没有赋值的属性,该属性的值为undefined。
(4)函数没有返回值时,默认返回undefined。
3.undeclared:js语法错误,没有申明直接使用,js无法找到对应的上下文。
JS 中 == 和 === 区别是什么?
1、对于string
,number
等基础类型,==
和===
有区别
1)不同类型间比较,==
之比较“转化成同一类型后的值”看“值”是否相等,===
如果类型不同,其结果就是不等。 2)同类型比较,直接进行“值”比较,两者结果一样。
2、对于Array
,Object
等高级类型,==
和===
没有区别
进行“指针地址”比较。
3、基础类型与高级类型,==
和===
有区别
1)对于==
,将高级转化为基础类型,进行“值”比较。
2)因为类型不同,===
结果为false
。
解释JS中的事件冒泡和事件捕获
事件捕获和冒泡: 在HTML DOM API中,有两种事件传播方法,它们决定了接收事件的顺序。两种方法是事件冒泡和事件捕获。第一个方法事件冒泡将事件指向其预期的目标,第二个方法称为事件捕获,其中事件向下到达元素。
事件捕获
捕获过程很少被使用,但是当它被使用时,它被证明是非常有用的。这个过程也称为滴流模式
。在这个过程中,事件首先由最外层的元素捕获,然后传播到最内部的元素。例如:
<div>
<ul>
<li></li>
</ul>
</div>
从上面的示例中,假设单击事件发生在li
元素中,在这种情况下,捕获事件将首先处理div
,然后处理ul
,最后命中目标元素li
。
事件冒泡
冒泡的工作原理与冒泡类似,事件由最内部的元素处理,然后传播到外部元素。
<div>
<ul>
<li></li>
</ul>
</div>
从上面的例子中,假设click
事件确实发生在冒泡模型中的li
元素中,该事件将首先由li
处理,然后由ul
处理,最后由div
元素处理。
module.exports 和 exports 之间有什么区别?
module
和exports
是Node.js
给每个js
文件内置的两个对象。可以通过console.log(module)
和console.log(exports)
打印出来。如果你在main.js
中写入下面两行,然后运行$ node main.js
:
console.log(exports);//输出:{}
console.log(module);//输出:Module {..., exports: {}, ...} (注:...代表省略了其他一些属性)
从打印咱们可以看出,module.exports
和exports
一开始都是一个空对象{}
,实际上,这两个对象指向同一块内存。这也就是说module.exports
和exports
是等价的(有个前提:不去改变它们指向的内存地址)。
例如:exports.age = 18
和module.export.age = 18
,这两种写法是一致的(都相当于给最初的空对象{}
添加了一个属性,通过require
得到的就是{age: 18}
)
import 和 exports 是什么?
import
和exports
帮助咱们编写模块化的JS代码。使用import
和exports
,咱们可以将代码分割成多个文件。import
只允许获取文件的某些特定变量或方法。可以导入模块导出的方法或变量。
//index.js
import name,age from './person';
console.log(name);
console.log(age);
//person.js
let name ='Sharad', occupation='developer', age =26;
export { name, age};
如何在JS中克隆对象
Object.assign()
方法用于在JS中克隆对象。如:
var x = {myProp: "value"};
var y = Object.assign({}, x);
如何在JS中编码和解码 URL?
var uri = "my profile.php?name=sammer&occupation=pāntiNG";
var encoded_uri = encodeURI(uri);
decodeURI(encoded_uri);
BOM 和 DOM 的关系
BOM全称Browser Object Model
,即浏览器对象模型,主要处理浏览器窗口和框架。
DOM
全称Document Object Model
,即文档对象模型,是 HTML 和XML 的应用程序接口(API),遵循W3C 的标准,所有浏览器公共遵守的标准。
JS是通过访问BOM(Browser Object Model)对象来访问、控制、修改客户端(浏览器),由于BOM的window
包含了document
,window
对象的属性和方法是直接可以使用而且被感知的,因此可以直接使用window
对象的document
属性,通过document属性就可以访问、检索、修改XHTML文档内容与结构。因为document
对象又是DOM
的根节点。
可以说,BOM
包含了DOM
(对象),浏览器提供出来给予访问的是BOM
对象,从BOM
对象再访问到DOM
对象,从而js可以操作浏览器以及浏览器读取到的文档。
列出一些内置方法及其返回的值
内置方法返回值CharAt()它返回指定索引处的字符。Concat()它连接两个或多个字符串。forEach()它为数组中的每个元素调用一个函数。indexOf()它返回指定值第一次出现时调用字符串对象中的索引。length()它返回字符串的长度。pop()它从数组中删除最后一个元素并返回该元素。push()它将一个或多个元素添加到数组的末尾,并返回数组的新长度。reverse()反转数组元素的顺序。
null 和 undefined 区别
undefined
是基本数据类型 表示未定义 缺少的意思。
null
是引用数据类型,是对象,表示空对象
undefined
是从null
派生出来的 所以undefined==null
为true
undeclared 和 undefined 区别?
undeclared的变量是程序中不存在且未声明的变量。 如果程序尝试读取未声明变量的值,则会遇到运行时错误。undefined的变量是在程序中声明但未赋予任何值的变量,如果程序试图读取未定义变量的值,则返回undefined的值。
call 和 apply有什么区别
call
和apply
可以用来重新定义函数的执行环境,也就是this
的指向;call
和apply
都是为了改变某个函数运行时的context
,即上下文而存在的,换句话说,就是为了改变函数体内部this
的指向。
call()
调用一个对象的方法,用另一个对象替换当前对象,可以继承另外一个对象的属性,它的语法是:
Function.call(obj[, param1[, param2[, [,...paramN]]]]);
说明:call
方法可以用来代替另一个对象调用一个方法,call
方法可以将一个函数的对象上下文从初始的上下文改变为obj
指定的新对象,如果没有提供obj
参数,那么Global
对象被用于obj
apply()
和call()
方法一样,只是参数列表不同,语法:
Function.apply(obj[, argArray]);
说明:如果argArray
不是一个有效数组或不是arguments
对象,那么将导致一个TypeError
,如果没有提供argArray
和obj
任何一个参数,那么Global
对象将用作obj。
如何在JS中清空数组
有许多方法可以用来清空数组:
方法一:
arrayList = []
上面的代码将把变量arrayList
设置为一个新的空数组。如果在其他任何地方都没有对原始数组arrayList
的引用,则建议这样做,因为它实际上会创建一个新的空数组。咱们应该小心使用这种清空数组的方法,因为如果你从另一个变量引用了这个数组,那么原始的引用数组将保持不变。
方法二:
arrayList.length = 0;
上面的代码将通过将其length
设置为0
来清除现有数组。这种清空数组的方式还会更新指向原始数组的所有引用变量。 因此,当你想要更新指向arrayList
的所有引用变量时,此方法很有用。
方法三:
arrayList.splice(0, arrayList.length);
这处方法也行,当然这种清空数组的方法也将更新对原始数组的所有引用。
方法四:
while(arrayList.length)
{
arrayList.pop();
}
上面的实现也可以空数组,但通常不建议经常使用这种方式。
new 操作符具体干了什么呢 ?
- 创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。
- 属性和方法被加入到 this 引用的对象中。
- 新创建的对象由 this 所引用,并且最后隐式的返回 this 。
把伪数组转换为数组
只需使用 [].slice.call(elements) 即可实现:
var elements = document.querySelectorAll("p"); // NodeList
var arrayElements = [].slice.call(elements); // 现在 NodeList 是一个数组
var arrayElements = Array.from(elements); // 这是另一种转换 NodeList 到 Array 的方法
JavaScript 判断一个变量是对象还是数组 ?
typeof 都返回 object
在 JavaScript 中所有数据类型严格意义上都是对象,但实际使用中我们还是有类型之分,如果要判断一个变量是数组还是对象使用 typeof 搞不定,因为它全都返回 object。
第一,使用 typeof 加 length 属性
数组有 length 属性,object 没有,而 typeof 数组与对象都返回 object,所以我们可以这么判断
var getDataType = function(o){
if(typeof o == 'object'){
if( typeof o.length == 'number' ){
return 'Array';
} else {
return 'Object';
}
} else {
return 'param is no object type';
}
};
第二,使用 instanceof
利用 instanceof 判断数据类型是对象还是数组时应该优先判断 array,最后判断 object。
var getDataType = function(o){
if(o instanceof Array){
return 'Array'
} else if ( o instanceof Object ){
return 'Object';
} else {
return 'param is no object type';
}
};
如何将一个数组打乱
方法1:arr.sort(() => Math.random() - 0.5)
;
sort方法使用了插入排序(目标长度小于10)和快排,元素之间的比较远小于n(n-1)/2,因此有些元素间没有随机交换的可能,使得该方法不够随机。
方法2:Fisher-Yates Shuffle,复杂度为O(n)。从后向前遍历,不断将当前元素与随机位置的元素(除去已遍历的部分)进行交换。
function shuffle(arr) {
let m = arr.length;
while (m > 1){
let index = Math.floor(Math.random() * m--);
[arr[m] , arr[index]] = [arr[index] , arr[m]]
}
return arr;
}
var list = [1, 2, 3];
console.log(list.sort(function() { Math.random() - 0.5 })); // [2, 1, 3]
MVVM
MVVM是Model-View-ViewModel的缩写,Model代表数据模型,View代表用户操作界面,ViewModel则是视图数据层。ViewModel通过双向数据绑定将View和Model层连接了起来,开发人员不用手动操作Dom元素,View和Mode会自动双向同步,开发者只需要关注业务逻辑即可。
图片懒加载
先将img标签的src链接设为同一张图片(比如某空白图片),然后给img标签设置自定义属性(比如 data-src),并将真正的图片地址存储在其中。当js监听到该图片元素进入可视窗口时(获取img节点距离浏览器顶部的距离,如果小于或等于浏览器窗口的可视高度即进入),再将自定义属性中的地址存储到src属性中,达到懒加载的效果。这样不仅可以减轻服务器压力,也可以提高用户体验。
把 Script放body前后有什么区别?浏览器会如何解析它们?
html标签只包含head 和body两个标签,解析时,所有标签都会解析进这两个标签里边。body之前的任何位置都会解析进head里边,之后的都会解析进body里边。
js延迟加载的方式有哪些?
共有:defer和async、动态创建DOM方式(用得最多)、使用jQuery的getscript方法、使用settimeout延迟方法、让js最后加载
defer属性:(页面load后执行)
HTML 4.01 为 <script>
标签定义了 defer
属性。
用途:表明脚本在执行时不会影响页面的构造。也就是说,脚本会被延迟到整个页面都解析完毕之后再执行。
在<script>
元素中设置 defer
属性,等于告诉浏览器立即下载,但延迟执行。
<html>
<head>
<script src="test1.js" defer="defer"></script>
<script src="test2.js" defer="defer"></script>
</head>
<body>
<!-- 这里放内容 -->
</body>
</html>
说明:虽然<script> 元素放在了<head>元素中,但包含的脚本将延迟浏览器遇到</html>标签后再执行。
HTML5规范要求脚本按照它们出现的先后顺序执行。在现实当中,延迟脚本并不一定会按照顺序执行。
defer属性只适用于外部脚本文件。支持 HTML5 的实现会忽略嵌入脚本设置的 defer属性。
- async 属性
HTML5 为 <script>标签定义了 async属性。与defer属性类似,都用于改变处理脚本的行为。同样,只适用于外部脚本文件。
目的:不让页面等待脚本下载和执行,从而异步加载页面其他内容。
异步脚本一定会在页面 load 事件前执行。
不能保证脚本会按顺序执行。
<!DOCTYPE html>
<html>
<head>
<script src="test1.js" async></script>
<script src="test2.js" async></script>
</head>
<body>
<!-- 这里放内容 -->
</body>
</html>
async和defer一样,都不会阻塞其他资源下载,所以不会影响页面的加载。
缺点:不能控制加载的顺序
3.动态创建DOM方式
//这些代码应被放置在</body>标签前(接近HTML文件底部)
<script type="text/javascript">
function downloadJSAtOnload() {
varelement = document.createElement("script");
element.src = "defer.js";
document.body.appendChild(element);
}
if (window.addEventListener)
window.addEventListener("load",downloadJSAtOnload, false);
else if (window.attachEvent)
window.attachEvent("onload",downloadJSAtOnload);
else
window.onload =downloadJSAtOnload;
</script>
4.使用jQuery的getScript()方法
$.getScript("outer.js",function(){//回调函数,成功获取文件后执行的函数
console.log("脚本加载完成")
});
5.使用setTimeout延迟方法
6.让JS最后加载
把js外部引入的文件放到页面底部,来让js最后引入,从而加快页面加载速度
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。