前端值得注意的重点(this指向问题、setTimeout、原型链、面试笔试注意点、axios二次封装、重绘重排)

如果被setTimeout推迟执行的回调函数是某个对象的方法,那么该方法中的this关键字将指向全局环境,而不是定义时所在的那个对象。

var x = 1;

var o = {
x: 2,
y: function(){
console.log(this.x);
}
};
setTimeout(o.y,1000);// 1

setTimeout(‘console.log(2)’,1000);
console.log(3);

上面代码的输出结果就是1,3,2,因为setTimeout指定第二行语句推迟1000毫秒再执行

this.login = login;
this.sayHi = function() {
console.log(this.login);
}
}
var user = new User(‘John’);
setTimeout(user.sayHi, 1000);

上面代码只会显示undefined,因为等到user.sayHi执行时,它是在全局对象中执行,所以this.login取不到值。

为了防止出现这个问题,一种解决方法是将user.sayHi放在匿名函数中执行。

setTimeout(function() {
user.sayHi();
}, 1000);

HTML 5标准规定,setTimeout的最短时间间隔是4毫秒。
为了节电,对于那些不处于当前窗口的页面,
浏览器会将时间间隔扩大到1000毫秒。
另外,如果笔记本电脑处于电池供电状态,
Chrome和IE 9以上的版本,会将时间间隔切换到系统定时器,大约是15.6毫秒。
这就是为什么打开标签页时会白一下

setTimeout(function () {
func1();
}, 0)
func2();
//func2先执行
setTimeout的作用是将代码推迟到指定时间执行,如果指定时间为0,即setTimeout(f,0)
作用是让f在现有的任务(脚本的同步任务和“任务队列”中已有的事件)
一结束就立刻执行。也就是说,setTimeout(f,0)的作用是,
尽可能早地执行指定的任务。setTimeout(f,0)指定的任务,最早也要到下一次Event Loop才会执行
setTimeout(function() {
console.log(“Timeout”);
}, 0);

function a(x) {
console.log(“a() 开始运行”);
b(x);
console.log(“a() 结束运行”);
}

function b(y) {
console.log(“b() 开始运行”);
console.log(“传入的值为” + y);
console.log(“b() 结束运行”);
}

console.log(“当前任务开始”);
a(42);
console.log(“当前任务结束”);

// 当前任务开始
// a() 开始运行
// b() 开始运行
// 传入的值为42
// b() 结束运行
// a() 结束运行
// 当前任务结束
// Timeout

理论上讲0做不到,规定settimeout最小是4毫秒
setTimeout(f,0)的含义代表尽可能快的执行指定的任务

1、以前在全局作用域函数中的this指向window对象
2、严格模式下全局作用域中的this是undefined

改变函数内this指向 js提供了三种方法 call() apply() bind()
都可以改变内部this的指向
区别点:
1、call和apply会调用函数,并且改变内部的this指向
2、call和apply传递参数不一样,call传递参数aru1,aru2形式apply必须数组形式[arg]
3、bind不会调用函数,可以改变函数内部this的指向
主要应用场景
1、call经常做继承
2、apply经常跟数组有关系,比如借助于数学对象实现数组最大值最小值
3、bind不调用函数,但是还想改变this的指向,比如改变定时器内部的this指向
call/apply

<script>
    window.number = 'one';
    document.number = 'two';

    var s1 = {number: 'three' };
    function changeColor(){
        console.log(this.number);
    }

    changeColor.apply();         //one (默认传参)
    changeColor.apply(window);   //one
    changeColor.apply(document); //two
    changeColor.apply(this);     //one
    changeColor.apply(s1);       //three

</script>

就是改变this指向

const obj = {
test() {
console.log(this === obj);
}
};

const t = obj.test;
t(); // false

t 就是 obj 的 test 方法,但是 t() 调用时,其中的 this 指向了全局。

而在 es5 中,用 new 调用一个构造函数,会创建一个新对象,而其中的 this 就指向这个新对象。这没有什么悬念,因为 new 本身就是设计来创建新对象的。

var data = “Hi”; // 全局变量

function AClass(data) {
this.data = data;
}

var a = new AClass(“Hello World”);
console.log(a.data); // Hello World
console.log(data); // Hi

var b = new AClass(“Hello World”);
console.log(a === b); // false

箭头函数没有自己的 this 绑定。箭头函数中使用的 this,其实是直接包含它的那个函数或函数表达式中的 this。比如
就箭头函数括号里是空的话this指向前面函数或里的this
const obj = {
test() {
const arrow = () => {
// 这里的 this 是 test() 中的 this,
// 由 test() 的调用方式决定
console.log(this === obj);
};
arrow();
},

getArrow() {
    return () => {
        // 这里的 this 是 getArrow() 中的 this,
        // 由 getArrow() 的调用方式决定
        console.log(this === obj);
    };
}

};

obj.test(); // true

const arrow = obj.getArrow(); //就算是调用里面的方法执行,也并不和之前一样指向全局
arrow(); // true

以下是关于promise的顺序

pending状态(过程中),不会触发then和catch
resolved状态,会触发后续的then回调函数
rejected状态,会触发后续的catch的回调函数
Promise对象的状态是pending,那么匿名回调函数的this指向window。

Promise对象的状态是resolved,那么匿名回调函数的this指向undefined

getA和getB并行执行,然后输出结果。如果有一个错误,就抛出错误

/**

  • 每一个promise都必须返回resolve结果才正确
  • 每一个promise都不处理错误
    */

const getA = new Promise((resolve, reject) => {
//模拟异步任务
setTimeout(function(){
resolve(2);
}, 1000)
})
.then(result => result)

const getB = new Promise((resolve, reject) => {
setTimeout(function(){
// resolve(3);
reject(‘Error in getB’);
}, 1000)
})
.then(result => result)

Promise.all([getA, getB]).then(data=>{
console.log(data)
})
.catch(e => console.log(e));

getA和getB并行执行,然后输出结果。总是返回resolve结果

Promise对象的状态是pending,那么匿名回调函数的this指向window。
Promise对象的状态是resolved,那么匿名回调函数的this指向undefined

Promise对象的回调函数是匿名函数时,this指向window,需要对回调函数bind(this)来改变其this指向。
Promise对象的回调函数是箭头函数时,this指向外层第一个普通函数的this。本例中指向Vue实例。
这就是为什么axios.get后面.then 里是箭头函数的原因

avascript是单线程的,所有的同步任务都会在主线程中执行。

当主线程中的任务,都执行完之后,系统会 “依次” 读取任务队列里的事件。与之相对应的异步任务进入主线程,开始执行。

异步任务之间,会存在差异,所以它们执行的优先级也会有区别。大致分为 微任务(micro task,如:Promise、MutaionObserver等)和宏任务(macro task,如:setTimeout、setInterval、I/O等)。

Promise 执行器中的代码会被同步调用,但是回调是基于微任务的。

微任务的优先级高于宏任务

每一个宏任务执行完毕都必须将当前的微任务队列清空

第一个 script 标签的代码是第一个宏任务

主线程会不断重复上面的步骤,直到执行完所有任务。
.then属于的是promise回调微任务是由,先执行then后面的,然后回过头来执行微任务


setTimeout(function(){console.log(1)},0);
new Promise(function(resolve){
console.log(2)
for( var i=0 ; i<10000 ; i++ ){
i==9999 && resolve()
}
console.log(3)
}).then(function(){
console.log(4)
});
console.log(5);
// 这的问题是,答案是 2 3 5 4 1


Promise.resolve().then(() => { //Promise.resolve()返回的 resolve状态的Promise
console.log(1) // resolved 触发then回调 : console.log(1);then正常返回resolved状态的Promise
}).catch(()=>{
console.log(2)
}).then(() => { //resolved 触发then回调: console.log(3)
console.log(3)
})
// 1 3

Promise.resolve().then(() => { // Promise.resolve()返回的 resolve状态的Promise
console.log(1) // resolved 触发then回调 : console.log(1)
throw new Error(‘error1’) // then里面有报错则返回rejected状态的Promise
}).catch(() => { // rejected 触发catch回调: console.log(2)
console.log(2) // catch正常返回resolved状态的Promise
}).then(() => { // resolved 触发then回调: console.log(3)
console.log(3)
})
// 1 2 3

Promise.resolve().then(() => { // Promise.resolve()返回的 resolve状态的Promise
console.log(1) // resolved 触发then回调 : console.log(1)
throw new Error(‘error1’) // then里面有报错则返回rejected状态的Promise
}).catch(() => { // rejected 触发catch回调: console.log(2)
console.log(2) // catch正常返回resolved状态的Promise
}).catch(() => { // resolved 触发then回调,无法触发catch回调
console.log(3)
})
// 1 2

js 原型链

Array、function、Object都属于function(es系列规定的)都有prototype
其他不是特殊情况都没有prototype,
比如 const a = Array()
const b = new Object()
const c = new function()
可以直接定义的
每一个属性都有_proto_,其实这个才是构成原型链的基础
变量等其他属性的_proto_一层一层指向其下一层直到
Object.prototype._proto_的值是null(就是object.prototype没有原型)就是一条完整的链

function.prototype的下一层指向内部属性的_proto_
const a = function(){}
a.testvalue.prototype = 2
conselo.log(a.testvalue) //undefined
const b = new a()
conselo.log(b.testvalue) //2
构建新实例可以使用prototype属性,–》印证了原型链指向新的实例。
属性自带构造函数constructor,此构造函数指向了属性的prototype


不定高div居中(能不使用position尽量不使用)
1、display: flex; justify-content: center;align-items: center
2、父盒子设置:display:relative
Div 设置: transform: translate(-50%,-50%);position: absolute;top: 50%;left: 50%;
3、父盒子设置:display:table-cell; text-align:center;vertical-align:middle;
Div 设置: display:inline-block;vertical-align:middle;
块状元素居中(块状元素没发用text-align)
1.宽度一定:margin:auto
2.宽度不定:块级变行内,然后在父上text-aligin

为什么要清除浮动?(解决父元素高度坍陷问题) 一个块级元素如果没有设置height,
其height由子元素撑开,对子元素使用了浮动之后,子元素就会脱离文档流也就是说,
父及元素中没有内容可以撑开其高度,这样父级元素height就会被忽略。这就是所谓的高度坍塌

优先级:
不同级别:总结排序:!important > 行内样式 > ID选择器 > 类选择器 > 标签 > 通配符 > 继承 > 浏览器默认属性

块元素会独占一行,默认情况下,其宽度自动填满父元素宽度 行元素不会占据一行,会一直排在一行,直到一行排不下 行元素没有宽度和高度属性,块级元素即使设置了宽度,还是会独占一行
块级元素: div p forn ul li h1-h6 行内元素:span img input a i

怎么改变this的指向呢?

1.使用es6的箭头函数;2.在函数内部使用that = this;
3.使用apply,call,bind; 4.new实例化一个对象
————————————————————————————————————
js垃圾回收机制

1.JS具有自动垃圾收集的机制
2.JS的内存生命周期(变量的生命)
1.分配你所需要的空间 var a = 20
2.使用分配带的内存(读写) alert(a + 10)
3.不适用的时候,释放内存空间 a = null
3.JS的垃圾收集器每隔固定的时间就执行一次释放操作,通用的是通过标记清除的算法
4.在局部作用域中,垃圾回收器很容易做出判断并回收,全局比较难,因此应避免全局变量

标记清除算法:js最常见的垃圾回收方式,当变量进入执行环境的时候,比如函数中声明一个变量,垃圾回收器将他标记为’进入环境’,
当变量离开(函数执行完后),就其标记为’离开环境’。垃圾回收器会在运行的时候给存储在内存中的所有变量加上标记,
然后去掉环境中的变量以及被环境中该变量所引用的变量(闭包)。在这些完成之后仍存在标记的就是要删除的变量了
————————————————————————————————————————————

typeOf()是判断基本类型的Boolean,Number,symbol, undefined, String。 对于引用类型:除function,都返回object null返回object。
installOf() 用来判断A是否是B的实例,installof检查的是原型。
toString() 是Object的原型方法,对于 Object 对象,直接调用 toString() 就能返回 [Object Object] 。而对于其他对象,则需要通过 call / apply 来调用才能返回正确的类型信息。
hasOwnProperty()方法返回一个布尔值,指示对象自身属性中是否具有指定的属性,该方法会忽略掉那些从原型链上继承到的属性。
isProperty()方法测试一个对象是否存在另一个对象的原型链上。
valueof:所有对象都有valueof,如果存在任意原始值,他就默认将对象转化为表示它的原始值。如果对象是复合值,而却大部分对象无法真正表示一个原始值,因此默认的valueof()方法简单的返回对象本身,而不是返回原始值

————————————————————————————————————————————————————

reduce(): 方法接收一个函数作为累加器,数组中的每一个值(从左到右)开始缩减,最终计算一个值,不会改变原数组的值
——————————————————————————————————————————————————————————

第一次握手:客服端发送一个请求连接,服务器端只能确认自己可以接受客服端发送的报文段
第二次握手: 服务端向客服端发送一个链接,确认客服端收到自己发送的报文段
第三次握手: 服务器端确认客服端收到了自己发送的报文段

————————————————————————————————————————————————————
1、cookie,sessionStorage,localStorage是存放在客户端,session对象数据是存放在服务器上
实际上浏览器和服务器之间仅需传递session id即可,服务器根据session-id找到对应的用户session对象
session存储数据更安全一些,一般存放用户信息,浏览器只适合存储一般的数据
2、cookie数据始终在同源的http请求中携带,在浏览器和服务器来回传递,里面存放着session-id
sessionStorage,localStorage仅在本地保存
3、大小限制区别,cookie数据不超过4kb,localStorage在谷歌浏览中2.6MB
4、数据有效期不同,cookie在设置的(服务器设置)有效期内有效,不管窗口和浏览器关闭
sessionStorage仅在当前浏览器窗口关闭前有效,关闭即销毁(临时存储)
localStorage始终有效
——————————————————————————————————————————————————
session与token区别

1、session认证只是把简单的User的信息存储Session里面,sessionID不可预测,一种认证手段。只存在服务端,不能共享到其他的网站和第三方App
2、token是oAuth Token,提供的是认证和授权,认证针对用户,授权是针对App,目的就是让某APP有权访问某用户的的信息。Token是唯一的,token不能转移到其他的App,也不能转到其他用户上。(适用app)
3、session的状态是存在服务器端的,客户端只存在session id, Token状态是存储在客户端的

————————————————————————————————————————————————————

关于页面重构、浏览器重绘和重排(回流)

页面任何的变化都可以称为页面重构:完全重构、细节调整。

重绘是一个 **元素外观 ** 的改变所触发的浏览器行为,例如改变visibility、outline、背景色等属性。
浏览器会根据元素的新属性重新绘制,使元素呈现新的外观。重绘不会带来重新布局,并不一定伴随重排。

重排是更明显的一种改变,可以理解为渲染树需要重新计算。下面是常见的触发重排的操作
1、dom元素的几何属性变化
2、dom树的结构变化(节点增减、移动)
3、获取某些属性(offsetTop、offsetLeft、 offsetWidth、offsetHeight、scrollTop、
scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、
clientHeight、getComputedStyle() (currentStyle in IE))
4、其他(改变浏览器窗口大小,改变一些元素样式)

解决重排的办法
合并多次改变样式的属性的操作;使需要多次改变的元素脱离文档流;在内存中多次操作节点,完成后再添加到文档中去(有动画效果时)
;在需要经常获取那些引起浏览器重排的属性值时,要缓存到变量。


基于axios的二次封装
虽然axios已经能够满足常规的get post put 等数据请求和发送数据,
但在涉及用户登陆和一些请求头的设置时就需要进行二次封装。
简化并统一设置发起请求的配置项,利于管理api接口。

import axios from ‘axios’
import qs from ‘qs’
//根据环境变量区分接口默认地址这里看自己需求配
switch(process.env.NODE_ENV){
case “production”:
axios.defaults.baseURL=“http://127.0.0.1:3000”
break;
case “test”:
axios.defaults.baseURL=“http://192.168.1.1”
break;
default:
axios.defaults.baseURL=“http://localhost:8080”
}
//设置超时时间和跨域是否携带凭证
axios.defaults.timeout=10000;
//设置CORS跨域允许携带凭证
axios.defaults.withCredentials=true;
axios.defaults.headers[‘Content-Type’]=‘application/x-www-form-urlencoded’
axios.defaults.transformRequest=data=>qs.stringify(data)
//设置请求拦截器
//客户端发送请求=》请求拦截器=》服务器
// TOKEN校验(JWT)接收服务器返回的token
// 存储到vuex/本地存储中,每一次发请求我们应该吧token带上
axios.interceptors.request.use((config)=>{
// 携带上token
let token=localStorage.getItem(‘token’)
token&&(config.headers.Authorization=token)
return config
},error=>{
return Promise.reject(error)
})

//响应拦截器
//服务器返回信息=》拦截的统一处理=》客户端js获取到信息
// axios.defaults.validatestatus=status=>{
//自定义响应成功的http状态码
// return /^(2|3)\d{2}$/.test(status)
// }
axios.interceptors.response.use(response=>{
return response.data;
//看项目实际情况,这样写返回的数据就只有主体内容
}
});

export default axios

相当于把用到的axios拿过来设置一番(封装好)再重新export出去 -即二次封装

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值