特性
优点
缺点
在js中,作用域分为全局作用域和函数作用域,ES6新增块级作用域
作用域链
一般情况下,变量取值到创建这个变量的函数的作用域中取值。
但是如果在当前作用域中取不到值,就会向上级作用域去查,直到查到全局作用域,这么一个查找过程形成的链条就叫做作用域链。
作用域链这么形成
作用域和执行上下文:许多人误认为作用域和执行上下文的概念,误认为他们是相同的概念,事实并非如此。
我们知道js属于解释性语言,js的执行分为:解释和执行两个阶段 。这两个阶段所做的事情并不一样。
解释阶段
执行阶段
JavaScript 解释阶段便会确定作用域规则,因此作用域在函数定义时就已经确定了,而不是在函数调用时确定,但是执行上下文是函数执行之前创建的。执行上下文最明显的就是 this 的指向是执行时确定的。而作用域访问的变量是编写代码的结构确定的。
作用域和执行上下文之间最大的区别是: 执行上下文在运行时确定,随时可能改变;作用域在定义时就确定,并且不会改变。
一个作用域下可能包含若干个上下文环境。有可能从来没有过上下文环境(函数从来就没有被调用过);有可能有过,现在函数被调用完毕后,上下文环境被销毁了;有可能同时存在一个或多个(闭包)。同一个作用域下,不同的调用会产生不同的执行上下文环境,继而产生不同的变量的值。
EC:函数的执行环境AO:(Actived Object)活动对象: 保存函数调用时的局部变量 其实AO对象就是函数作用域对象
变量提升
var 声明的变量会提升到当前作用域的最顶端
function 声明的函数也会提升到当前作用域的最顶端
不同
什么是暂时性死区
如果区块(花括号)中存在let命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域,凡是在声明之前就使用这些变量,就会报错,所以在代码块内,使用let命令声明变量之前,该变量都是不可用的
这被称为暂时性死区
数组
会改变原有数组
会改变原有数组,不会返回新的数组或值:
pop()—删除数组的最后一个元素并返回删除的元素。
push()—向数组的末尾添加一个或更多元素,并返回新的长度。
shift()—删除并返回数组的第一个元素。
unshift()—向数组的开头添加一个或更多元素,并返回新的长度。
reverse()—反转数组的元素顺序。
sort()—对数组的元素进行排序。
splice()—用于插入、删除或替换数组的元素。
不会改变数组,并会返回新的数组
concat()—连接两个或更多的数组,并返回结果。
every()—检测数组元素的每个元素是否都符合条件。
some()—检测数组元素中是否有元素符合指定条件。
filter()—检测数组元素,并返回符合条件所有元素的数组。
indexOf()—搜索数组中的元素,并返回它所在的位置。
join()—把数组的所有元素放入一个字符串。
toString()—把数组转换为字符串,并返回结果。
lastIndexOf()—返回一个指定的字符串值最后出现的位置,在一个字符串中的指定位置从后向前搜索。
map()—通过指定函数处理数组的每个元素,并返回处理后的数组。
slice()—选取数组的的一部分,并返回一个新数组。
valueOf()—返回数组对象的原始值。
其他
reduce 对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。
reducer 函数接收4个参数:
Accumulator (acc) (累计器)
Current Value (cur) (当前值)
Current Index (idx) (当前索引)
Source Array (src) (源数组)
您的 reducer 函数的返回值分配给累计器,该返回值在数组的每个迭代中被记住,并最后成为最终的单个结果值。
字符串
split、slice、substr、indexOf、charAt、trim、toLocalUpperCase、toLocaleLowerCase
foreach没有返回值,map会返回数组
js事件循环机制推文
js异步任务安装准确的划分,应该将任务分为:
宏任务:setTimeout、setInterval( 按照指定的周期(以毫秒计)来调用函数或计算表达式。)
微任务:列如promise.then方法。注意new Promise()的时候是同步,立即执行。
所以针对这种机制,js的事件循环机制应该是这样的
注意:现在有三个队列:同步队列(也称执行栈)、宏任务队列、微任务队列
setTimeout(function(){
console.log(1)
},0)
new Promise(function(resolve,reject){
console.log(2)
resolve()
}).then((res)=>{
console.log(3)
})
console.log(4)
//执行结果是 2 4 3 1
async
当我们在函数前使用async的时候,使得该函数返回的是一个Promise对象
async function test(){
return 1 //async的函数会帮我们隐式的使用Promise。resolve(1)
}
//等价于下面的代码
function test(){
return new Promise(function(resolve,reject){
resolve(1)
})
}
可见async只是帮助我们返回一个Promise而已
await
await表示等待,是右侧【表达式】的结果,这个表达式的结果结算可以是Promise对象的值或者一个函数的值。并且只能在带有async的内部使用
使用await时,会从右往左执行,当遇到await时候,会阻塞函数内部处于他后面的代码。去执行该函数外部的同步代码,当外部同步代码执行完毕,再回到该函数内部执行剩余代码,并且当await执行完毕之后,会先处理微任务队列的代码。
async function async1() {
console.log( 'async1 start' )
await async2()
console.log( 'async1 end' )
}
async function async2() {
console.log( 'async2' )
}
console.log( 'script start' )
setTimeout( function () {
console.log( 'setTimeout' )
}, 0 )
async1();
new Promise( function ( resolve ) {
console.log( 'promise1' )
resolve();
} ).then( function () {
console.log( 'promise2' )
} )
console.log( 'script end' )
原型:每一个对象都与另一个对象相关联,那个关联的对象就称为原型
原型链:每一个对象,都有一个原型对象与之关联,这个原型对象它也是一个普通对象,这个普通对象也有自己的原型对象,这样层层递进,就形成了一个链条,这个链条就是原型链。通过原型链可以实现JS的继承,把父类的原型对象赋值给子类的原型,这样子类实例就可以访问父类原型上的方法了
36个手写问题
function Animal() {
this.colors = ['black', 'white']
}
Animal.prototype.getColor = function() {
return this.colors
}
function Dog() {}
Dog.prototype = new Animal()
let dog1 = new Dog()
dog1.colors.push('brown')
let dog2 = new Dog()
console.log(dog2.colors) // ['black', 'white', 'brown']
原型链继承存在的问题:
问题1:原型中包含的引用类型属性将被所有实例共享;
问题2:子类在实例化的时候不能给父类构造函数传参;
function Animal(name) {
this.name = name
this.getName = function() {
return this.name
}
}
function Dog(name) {
Animal.call(this, name)
}
Dog.prototype = new Animal()
借用构造函数实现继承解决了原型链继承的 2 个问题:引用类型共享问题以及传参问题。但是由于方法必须定义在构造函数中,所以会导致每次创建子类实例都会创建一遍方法。
class Animal {
constructor(name) {
this.name = name
}
getName() {
return this.name
}
}
class Dog extends Animal {
constructor(name, age) {
super(name)
this.age = age
}
}
组合继承结合了原型链和盗用构造函数,将两者的优点集中了起来。基本的思路是使用原型链继承原型上的属性和方法,而通过盗用构造函数继承实例属性。这样既可以把方法定义在原型上以实现重用,又可以让每个实例都有自己的属性。
function Animal(name) {
this.name = name
this.colors = ['black', 'white']
}
Animal.prototype.getName = function() {
return this.name
}
function Dog(name, age) {
Animal.call(this, name)
this.age = age
}
Dog.prototype = new Animal()
Dog.prototype.constructor = Dog
let dog1 = new Dog('奶昔', 2)
dog1.colors.push('brown')
let dog2 = new Dog('哈赤', 1)
console.log(dog2)
// { name: "哈赤", colors: ["black", "white"], age: 1 }
缺点:两次调用父类构造函数,数据冗余
寄生式组合继承
function Animal(name) {
this.name = name
this.colors = ['black', 'white']
}
Animal.prototype.getName = function() {
return this.name
}
function Dog(name, age) {
Animal.call(this, name)
this.age = age
}
Dog.prototype = Object.create(Animal.prototype)
Dog.prototype.constructor = Dog
let dog1 = new Dog('奶昔', 2)
dog1.colors.push('brown')
let dog2 = new Dog('哈赤', 1)
console.log(dog2)
// { name: "哈赤", colors: ["black", "white"], age: 1 }
function create(Con,...args){
//1.创建一个空的对象
let obj = {}; //let obj = Object.create({});
//2.将空对象的原型prototype指向构造函数的原型
Object.setPrototypeOf(obj,Con.prototype); //obj._proto_ = Con.prototype
//3.改变构造函数的上下文(this),并将剩余的参数传入
let result = Con.apply(obj,args);
//4.在构造函数有返回值的情况进行判断
return result instanceof Object?result:obj;
}
XMLHttpRequest—必知必会
readyState 属性表示Ajax请求的当前状态。它的值用数字代表。
0 代表未初始化。 还没有调用 open 方法
1 代表正在加载。 open 方法已被调用,但 send 方法还没有被调用
2 代表已加载完毕。send 已被调用。请求已经开始
3 代表交互中。服务器正在发送响应
4 代表完成。响应发送完毕
步骤
创建XMLHttpRequest对象,即创建一个异步调用对象.
创建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息.
设置响应HTTP请求状态变化的函数.
发送HTTP请求.
获取异步调用返回的数据.
使用JavaScript和DOM实现局部刷新.
this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象。
同步的概念
同步,我的理解是一种线性执行的方式,执行的流程不能跨越。一般用于流程性比较强的程序,我们做的用户登录功能也是同步处理的,必须用户通过用户名和密码验证后才能进入系统的操作。
异步的概念
异步,是一种并行处理的方式,不必等待一个程序执行完,可以执行其它的任务。在程序中异步处理的结果通常使用回调函数来处理结果。在JavaScript中实现异步的方式主要有Ajax和H5新增的Web Worker。
promiseA+规范
promise代表了一个异步操作的最终结果,主要是通过then方法来注册成功以及失败的情况
1.术语
“promise”是一个对象或函数,其then方法的行为符合此规范。
“thenable”是定义then方法的对象或函数。
“value”是任何合法的JavaScript值(包括undefined,一个卑鄙的或一个承诺)。
“exception”是使用该throw语句抛出的值。
“原因”是一个值,表明承诺被拒绝的原因。
2.要求
Promise 对象存在以下三种状态:
Pending(进行中)
Fulfilled(已成功)
Rejected(已失败)
状态只能由 Pending 变为 Fulfilled 或由 Pending 变为 Rejected ,且状态改变之后不会在发生变化,会一直保持这个状态。
3.如何实现一个promise
如何实现一个promise
因为 promise 调用 then 方法时,当前的 promise 并没有成功,一直处于 pending 状态。所以如果当调用 then 方法时,当前状态是 pending,我们需要先将成功和失败的回调分别存放起来,在executor()的异步任务被执行时,触发 resolve 或 reject,依次调用成功或失败的回调。
手撕promise.all
Promise.myAll = function(promises) {
return new Promise((resolve, reject) => {
if(!(promises instanceof Array)) {
reject('TypeError: paras is not a array')
}
let count = 0
let arr = []
for(let i=0; i < promises.length; i++) {
promises[i].then(res => {
count++
arr[i] = res
if(count === promises.length) {
resolve(arr)
}
}, err => {
reject(err)
})
}
})
}
手撕promise.race
Promise.myRace = function(promises) {
return new Promise((resolve, reject) => {
if(!(promises instanceof Array)) {
reject('TypeError: arguments is not a Array')
}
for(let i=0; i < promises.length; i++) {
promises[i].then(res => {
resolve(res)
}, err => {
reject(err)
})
}
})
}
手撕promise.myResolve
Promise.myResolve = function(value) {
return new Promise((resolve, reject) => {
if(value instanceof Promise) {
value.then(res => {
resolve(res)
}, err => {
reject(err)
})
} else {
resolve(value)
}
})
}
手撕promise.myReject
Promise.reject = function(value) {
return new Promise((resolve, reject) => {
reject(value)
})
}
Promise的缺点
1、无法取消Promise,一旦新建它就会立即执行,无法中途取消。
2、如果不设置回调函数,promise内部抛出的错误,不会反应到外部。
3、当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
new Promise((resolve,reject) => {
reject()
resolve() // 这个 promise 最终状态? 失败态/rejected
console.log(3) // 这个会输出吗? 会
})
.catch(() => {})
.then(() => {}) // 这个会执行吗? 会
Promise值穿透
Promise.resolve('foo')
.then(Promise.resolve('bar'))
.then(function(result){
console.log(result)
})
当然,输出的结果为foo。问其原因,答案如题——Promise值穿透
Promise.resolve(1)
.then(function(){return 2})
.then(Promise.resolve(3))
.then(console.log)
输出结果: 2
解释:.then 或者 .catch 的参数期望是函数,传入非函数则会发生值穿透。
回收规则
值类型(基本类型):
字符串(String)、数字(Number)、布尔(Boolean)、对空(Null)、未定义(Undefined)、Symbol(每个从Symbol()返回的symbol值都是唯一的。一个symbol值能作为对象属性的标识符)。
引用数据类型:
对象(Object)、数组(Array)、函数(Function)。
类型装换
任何对象转为布尔值,都会都到true。在JS中,只有0,-0,NaN,“”,null,undefined这留个值转为布尔值时候,结果为false。
区别
普通数据类型:内存中存储的是数据本身,作为形参引入到函数中,则给函数分配的内存空间将会有一个形参空间存储该数据(可以理解为其替身)。函数执行过程中对该数据进行操作使之发生的改变只发生在“替身”上面,故函数执行完,给函数分配的空间被销毁,“替身”也被销毁,源数据不会发生改变。
引用数据类型:以数组为例,内存中存储的是数组的地址,实际内容存储在 堆段 中。【堆段:堆段中存储的特点是想要多少内存就可以分配多少存储空间。】 故在函数中以参数引入数组,给函数分配的内存空间中,形参空间存储的也是数组的地址。在函数执行过程中,对数组进行操作使之发生改变,是真实地发生在原数组身上的,故执行完函数,函数内存空间释放后,数组仍有改变。
== 没有类型比较,===会比较类型
instanceof操作符判断
用arr instancecof Array
instanceof主要用于某个实例是否属于某个对象
let arr = [];
console.log(arr instanceof Array);
Object.prototype.toString
用法:Object.prototype.toString.call(arr) === ‘[Object Array]’
虽然Array也继承自Object,但是Array.prototype上重写了toString,而我们通过toString.call(arr)实际上是通过原型链调用了
let arr = []
console.log(Object.prototype.toString.call(arr) === '[object Array]');
Array.isArray
用法:Array.isArray(arr)ES5中新增了Array.isArray方法,IE8以下不支持
Array.isArray(arg)
isArray函数需要一个参数arg,如果参数是个对象并且class内部属性是“Array”,返回布尔值true,否则它返回false
let arr = [];
console.log(Array.isArray(arr));
dom0的事件只会触发一次,后面定义的会把前面定义的覆盖掉
dom2级的事件会依次执行,IE6-IE8的执行顺序不一定
DOM0:不是W3C规范。
DOM1:开始是W3C规范。专注于html文档和xml文档
DOM2:对DOM1增加了样式表对象模型
DOM3:对DOM2增加了内容模型(DTD\SCHEMAS)和文档验证
on事件会被后面的on的事件覆盖,addEventListener则不会覆盖。
1.onclick事件在同一时间只能指向唯一对象
2.addEventListener对任何DOM都是有效的,而onclick仅限于HTML
3.addEventListener给一个事件注册多个listener
4.addEventListener可以控制listner的触发阶段,(捕获、冒泡)。对于多个相同的事件处理器,不会重复触发,不需要手动使用removeEventListener清除
三个 :事件名 函数 捕获还是冒泡阶段
attachEvent
防抖概述
在事件被触发n秒后再执行回调函数,如果在这n秒内又被触发,则重新计时。
基于上述场景,首先提出第一种思路:在第一次触发事件时,不立即执行函数,而是给出一个期限值比如200ms,然后:
如果在200ms内没有再次触发滚动事件,那么就执行函数 如果在200ms内再次触发滚动事件,那么当前的计时取消,重新开始计时 效果:如果短时间内大量触发同一事件,只会执行一次函数。
应用场景
(1) 用户在输入框中连续输入一串字符后,只会在输入完后去执行最后一次的查询ajax请求,这样可以有效减少请求次数,节约请求资源;
(2) window的resize、scroll事件,不断地调整浏览器的窗口大小、或者滚动时会触发对应事件,防抖让其只触发一次;
简单版:函数内部支持使用 this 和 event 对象;
function debounce(func, wait) {
var timeout;
return function () {
var context = this;
var args = arguments;
clearTimeout(timeout)
timeout = setTimeout(function(){
func.apply(context, args)
}, wait);
}
}
使用:
var node = document.getElementById('layout')
function getUserAction(e) {
console.log(this, e) // 分别打印:node 这个节点 和 MouseEvent
node.innerHTML = count++;
};
node.onmousemove = debounce(getUserAction, 1000)
节流
概述
规定一个单位时间,在这个单位时间内,只能有一次触发事件的回调函数执行,如果在同一个单位时间内某事件被触发多次,只有一次能生效。
应用场景
(1)鼠标连续不断地触发某事件(如点击),只在单位时间内只触发一次;
(2)在页面的无限加载场景下,需要用户在滚动页面时,每隔一段时间发一次 ajax 请求,而不是在用户停下滚动页面操作时才去请求数据;
(3)监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断;
简单版:使用时间戳来实现,立即执行一次,然后每 N 秒执行一次。
function throttle(func, wait) {
var context, args;
var previous = 0;
return function() {
var now = +new Date();
context = this;
args = arguments;
if (now - previous > wait) {
func.apply(context, args);
previous = now;
}
}
}
概述
js大致分成两种数据类型:基本数据类型和引用数据类型。
基本数据类型保存在栈内存,而引用类型则保存在堆内存中。对于基本数据类型的拷贝,并没有深浅拷贝的区别,我们所说的深浅拷贝都是对于引用数据类型而言的。
浅拷贝:浅拷贝是复制引用,复制后的引用都是指向同一个对象的实例,彼此之间的操作会互相影响。
深拷贝:深拷贝不是简单的复制引用,而是在堆中重新分配内存,并且把源对象实例的所有属性都进行新建复制,以保证深拷贝的对象的引用图不包含任何原有对象或对象图上的任何对象,复制后的对象与原来的对象是完全隔离的。
事件流描述的就是从页面中接收事件的顺序。
DOM2级事件规定的事件流包括三个阶段: (1)事件捕获阶段 (2)处于目标阶段 (3)事件冒泡阶段
事件冒泡:
从事件源朝父级一直到根元素(HTML)。当某个元素的某类型事件被触发时,那么它的父元素同类型的事件也会被触发,一直触发到根源上;
从具体的元素到不确定的元素。
事件捕获:
从根元素(HTML)到事件源,当某个元素的某类型事件被触发时,先触发根元素的同类型事件,朝子一级触发,一直触发到事件源。
从不确定的元素到具体的元素;
在一些标准的浏览器中如Chrome、Firefox是支持这两种冒泡的
在IE以及老版本opra不支持
IE、Opera的事件绑定函数是attachEvent,而Chrome等浏览器则是addEventListener
阻止冒泡
div.addEventListener("click',function(e){
e.stopPropagation();
},true)
// 这样div的父元素就接收不到事件了
stopPropagation()方法既可以阻止事件冒泡,也可以阻止事件捕获,也可以阻止处于目标阶段。
阻止默认事件:e.preventDefault();
typeof
typeof 是判断参数是什么类型的实例,返回值为说明运算数类型的字符串。
返回值结果:“number”、“string”、“boolean”、“object”、“function”、“undefined”
若参数为引用类型,始终返回“object”,对于Array、null始终返回“object”,所以用typeof来判断参数类型有很大的局限性。
instaceof
instanceof是用来判断一个对象在其原型链中是否存在一个构造函数的prototype属性,返回一个布尔值
a instanceof b:判断a是否为b的实例,可以用于继承关系中
b是c的父对象,a是c的实例,a instanceof b 与 a instanceof c 结果均为true
对于所有的引用类型,均为Object的实例
undefined和null比较特殊,虽然null的类型是object,但是null不具有任何对象的特性
通过Object下的toString.call()方法来判断
let arr = []
console.log(Object.prototype.toString.call(arr) === '[object Array]');
根据对象的contructor判断
console.log('数据类型判断' - constructor);
console.log(arr.constructor === Array); //true
console.log(date.constructor === Date); //true
console.log(fn.constructor === Function); //true
jq中判断数据类型的方法
jQuery.isArray();是否为数组
jQuery.isEmptyObject();是否为空对象 (不含可枚举属性)。
jQuery.isFunction():是否为函数
jQuery.isNumberic():是否为数字
jQuery.isPlainObject():是否为使用“{}”或“new Object”生成对象,而不是浏览器原生提供的对象。
jQuery.isWindow(): 是否为window对象;
jQuery.isXMLDoc(): 判断一个DOM节点是否处于XML文档中。
js引擎的工作方式是,先预解析代码, 获取所有被声明的变量和函数声明,然后再一行一行地运行,这就使所有变量声明的语句,都会被提升到代码的头部,这就是变量提升
ESM (es6 模块)
ES6 模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。
因为ESM是静态化的,所以在运行前的编译阶段就可以确定模块关系,从而进行一些模块之间的操作,比如treeshaking等等
ES6 模块不是对象,而是通过export命令显式指定输出的代码,再通过import命令输入
一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量。
export语句输出的接口,与其对应的值是动态绑定关系,即通过该接口,可以取到模块内部实时的值。js引擎对脚本静态分析的时候,遇到模块加载命令import,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值
CommonJS
CommonJS 只能在运行时确定这些东西。CommonJS 加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成
CommonJS 模块输出的是值的拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值
比如const a = ‘func’; const func = require(’./test/’+a+’.js’), 这个括号里面是可以放表达式的!!表达式 只能在运行时才能确定值啊,所以cmd只能在运行时确定模块关系 ,这就注定了在编译阶段不能做一些事。
getOwnPropertyNames
只要两个对象的名和键值都相同。那么两个对象的内容就相同了
1.用Object.getOwnPropertyNames拿到对象的所以键名数组
2.比对键名数组的长度是否相等。否=>false。真=>3
3.比对键名对应的键值是否相等
怎么判断两个对象是否相等
function isObjectValueEqual(a, b) {
var aProps = Object.getOwnPropertyNames(a);
var bProps = Object.getOwnPropertyNames(b);
if (aProps.length != bProps.length) {
return false;
}
for (var i = 0; i < aProps.length; i++) {
var propName = aProps[i];
var propA = a[propName];
var propB = b[propName];
if ( propA !== propB) {
return false;
}
}
return true;
}
var url = '/请求的路径';
var params = {
id: 'id=123',
limit: 'limit=10'
};
// 封装一个get请求的方法
function getJSON(url) {
return new Promise(function(resolve, reject) {
var XHR = XMLHttpRequest ? new XMLHttpRequest() : new window.ActiveXObject('Microsoft.XMLHTTP');
XHR.onreadystatechange = function() {
//readyState属性表示请求/响应过程的当前活动阶段。
if (XHR.readyState == 4) {
if ((XHR.status >= 200 && XHR.status < 300) || XHR.status == 304) {
try {
//获取数据
var response = JSON.parse(XHR.responseText);
resolve(response);
} catch (e) {
reject(e);
}
} else {
reject(new Error("Request was unsuccessful: " + XHR.statusText));
}
}
}
XHR.open('GET', url + '?' + params.join('&'), true);
XHR.send(null);
})
}
getJSON(url).then(resp => console.log(resp));
思路是使用递归函数,不断地去执行setTimeout从而达到setInterval的效果,看代码
function mySetInterval(fn, millisec){
function interval(){
setTimeout(interval, millisec);
fn();
}
setTimeout(interval, millisec)
}
这个mySetInterval函数有一个叫做interval的内部函数,它通过setTimeout来自动被调用,在interval中有一个闭包,调用了回调函数并通过setTimeout再次调用了interval。
分为请求拦截器和响应拦截器两种。我一般把拦截器写在main.js里。
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么,例如加入token
.......
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
axios.interceptors.response.use(function (response) {
// 在接收响应做些什么,例如跳转到登录页
......
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
var myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);
4.为axios实例添加拦截器
var instance = axios.create();
instance.interceptors.request.use(function () {/*...*/});
jQuery面试题总结
链式调用完方法后,return this返回当前调用方法的对象。
Ajax的本质是使用XMLHttpRequest对象来请求数据
Fetch 是全局量 window 的一个方法,它的主要特点有:
1、第一个参数是URL:
2、第二个是可选参数,可以控制不同配置的 init 对象
3、使用了 JavaScript Promises 来处理结果/回调:
fetch规范与jQuery.ajax()主要有两种方式的不同
1、从 fetch()返回的 Promise 将不会拒绝HTTP错误状态, 即使响应是一个 HTTP 404 或 500。相反,它会正常解决 (其中ok状态设置为false), 并且仅在网络故障时或任何阻止请求完成时,它才会拒绝
2、默认情况下, fetch在服务端不会发送或接收任何 cookies, 如果站点依赖于维护一个用户会话,则导致未经认证的请求(要发送 cookies,必须发送凭据头).
这一点也可以做一些处理:
如果想要在同域中自动发送cookie,加上 credentials 的 same-origin 选项
fetch(url, {
credentials: ’same-origin'
})
same-origin值使得fetch处理Cookie与XMLHttpRequest类似。 否则,Cookie将不会被发送,导致这些请求不保留认证会话。对于CORS请求,使用include值允许将凭据发送到其他域:
fetch(url, {
credentials: 'include'
})
最后fetch采用了Promise的异步处理机制,使用比ajax更加简单,有可能会逐渐代替ajax
原因
因为js使用的双精度浮点,所以在计算机内部存储数据的编码会出现误差,导致0.1+0.2=0.30000000000000004。和0.3相比较结果为false。
解决方案
let x=(0.1*10+0.2*10)/10;
console.log(x===0.3)
//let x=(0.1+0.2).toFixed(1)
//因为使用toFixed方法将number类型转换成了字符串类型
//,所以使用parseFloat将字符串转回number类型
let x=parseFloat((0.1+0.2).toFixed(1));
console.log(x===0.3);
推荐在循环对象属性的时候,使用for…in,在遍历数组的时候的时候使用for…of。
好处:单线程的特点能更好的提高运行效率
JS用法层面:JS的主要用途是与用户互动和dom操作。这决定了它只能是单线程,否则会带来很复杂的同步问题。如:若JS有多个线程,一个操作一个节点,另一个删除那个节点,要先走哪一步?
总结js常用的dom操作(js的dom操作API)
前端如何捕获错误
js实现一个轮播图
1、首先要有个盛放图片的容器,设置为单幅图片的宽高,且overflow:hidden,这样保证每次可以只显示一个图片
2、container内有个放图片的list进行position的定位 ,其中的图片采用float的方式,同时当图片进行轮播时,改变list的Left值使得其显示的图片发生变化。
3、图片的轮播使用定时器,通过定时器改变list的Left值是的图片循环展示
4、当鼠标滑动到图片上时,清除定时器,图片停止轮播,当鼠标移出时继续进行轮播
5、图片上有一组小圆点用于与当前显示的图片相对应,同时可以通过点击的方式查看对应的图片
6、图片可以通过点击pre,next进行左右滑动显示
显式原型:prototype
隐式原型:proto
二者的关系
隐式原型指向创建这个对象的函数的prototype
实现准确搜索的方法
思路:
原理:
当浏览器有非直接的文字输入时,compositionstart事件就会同步触发,记住,是同步
当浏览器是直接的文字输入时,compositionend事件就会触发
Boolean类型转换:
1.对于String:只有非空字符串为真
2.对于Number:除了0和NaN之外都为真
3.对于Boolean:true为真
4.对于Object:除了null之外都为真
5.undefined为false;
下面几个都会转化为0:
Number()
Number(0)
Number(’’)
Number(‘0’)
Number(false)
Number(null)
Number([])
1.export与export default均可用于导出常量、函数、文件、模块等
2.你可以在其它文件或模块中通过import+(常量 | 函数 | 文件 | 模块)名的方式,将其导入,以便能够对其进行使用
3.在一个文件或模块中,export、import可以有多个,export default仅有一个
4.通过export方式导出,在导入时要加{ },export default则不需要
Generator 函数是将函数分步骤阻塞 ,只有主动调用 next() 才能进行下一步
事件委托就是利用事件冒泡机制指定一个事件处理程序,来管理某一类型的所有事件。即:利用冒泡的原理,把事件加到父级上,触发执行效果。
好处:
事件委托
ev.target || ev.srcElement