-
call,apply,bind
主要用于改变this指向的 1.call格式:函数名.call(上下文环境,参数)
说明:
上下文环境:就是应用函数的作用域范围
参数:是以逗号分隔的参数列表
例如:getMsg.call(obj,'微信小程序','Angular');
特点:1.改变this指向,2.函数被执行了
2. apply格式:函数名.apply(上下文环境,参数)
说明:
上下文环境:就是应用函数的作用域范围
参数:是用数组形式传递的参数列表
例如:getMsg.apply(obj,['微信小程序111','Angular222']);
特点:同call的特点
3. bind格式:函数名.bind(上下文环境,参数)
bind传参调用:
getMsg.bind(obj,'微信小程序','Angular')()
getMsg.bind(obj)('微信小程序','Angular')
特点:1.改变this指向,2.返回调用函数本身,函数没有被执行
回顾一下React中的事件绑定:<div onClick={this.play.bind(this)}>
二、说一下call和apply的实现原理?
> 记住:函数由Function构造器实例化
> 平时创建一个函数:
>
> 1.函数声明
>
> function Fn() {
>
> }
>
> 2. 函数表达式
>
> var Fn=function() {
>
>
> }
>
> 3. 用new的方式创建一个函数
>
> var Fn=new Function('函数参数','函数执行体'')
eval:可以将内部的字符串解析成代码或表达式去执行
例如:
eval('1+2')
3
eval('alert("1906A")')
参考官方文档:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/eval
call实现原理,模拟call的实现:
//用JS原生模拟call
Function.prototype.call2=function(context) {
var ctx=context || window;
//将函数临时添加到对象上
ctx.fn=this; //其中this代码要调用的函数
//处理参数接收问题,arguments
var args=[];
for(var i=1,len=arguments.length;i<len;i++) {
//将获取的每个参数压入数组中
args.push('arguments['+i+']');
}
//最后得到: args[arguments[0],arguments[1],arguments[2]]
//执行对象上的函数,eval,用于执行字符串代码的
var result=eval('ctx.fn('+args+')') //ctx.fn(args)
//最后删除掉这个函数
delete ctx.fn
return result;
}
apply实现原理,模拟apply实现:
Function.prototype.apply2=function(context,arr) {
var ctx=context || window;
//将函数临时添加到对象上
ctx.fn=this; //其中this代码要调用的函数
//对是否有arr进行处理
if(!arr) {
ctx.fn();
}else {
//处理参数接收问题,arguments
var args=[];
for(var i=1,len=arr.length;i<len;i++) {
//将获取的每个参数压入数组中
args.push('arguments['+i+']');
}
//最后得到: args[arguments[0],arguments[1],arguments[2]]
//执行对象上的函数,eval,用于执行字符串代码的
var result=eval('ctx.fn('+args+')') //ctx.fn(args)
}
//最后删除掉这个函数
delete ctx.fn
return result;
}
三、防抖和节流实现原理?
1. 防抖和节流解决什么问题?
解决页面高频触发或向后端连续请求的优化逻辑问题 例如:搜索,滚动加载
键盘:onkeydown(键盘按下),onkeyup(键盘抬起)
鼠标:onmousemove(鼠标移动)
浏览器事件:onresize(改变窗口尺寸),onscroll(滚动事件)
2. 防抖:
生活比喻:比如电脑屏保,电梯的开关
防抖:即在固定n秒间隔内,不会执行代码逻辑,除非n秒内有事件触发,则会再延长n秒,直到n秒没有触发的事件,则在n秒后执行代码逻辑
代码实现思路:
1.主要利用定时器实现
2.考虑this指向问题
3.考虑事件对象是否使用 事件对象属于事件处理函数的参数
//防抖函数具体实现
/*
* { function }func:代表对哪个高频函数进行防抖
* { number } wait:代表防抖的时间间隔
*/
function debounce(func,wait) {
var timeout;
return function() {
var _this=this;
var args=arguments;
clearTimeout(timeout)
timeout=setTimeout(function() {
func.apply(_this,args)
},wait)
}
}
3. 节流
生活比喻:每天有规律的时间学习,吃饭,跑步,不会因为杂事儿所打乱,类似闹钟是有规律的
节流:固定的时间节点,执行固定的代码逻辑
> **时间戳实现节流**
//节流函数
/*
* { function }func:代表对哪个高频函数进行节流
* { number } wait:代表节流的时间间隔
* 节流有两种实现方式:时间戳方式,定时器方式
*/
function throttle(func,wait) {
var _this;
var args;
var previous=0; //记录历史时间戳
return function() {
var now=+new Date(); //生成一个当前的时间戳
args=arguments;
_this=this;
//用当前时间now减去历史时间previous大于wait,就会执行事件处理函数,并且更新历史时间
if(now-previous>wait) {
//执行事件处理函数
func.apply(_this,args)
//更新历史时间戳
previous=now;
}
}
}
> **定时器实现节流**
//节流函数
/*
* { function }func:代表对哪个高频函数进行节流
* { number } wait:代表节流的时间间隔
* 节流有两种实现方式:时间戳方式,定时器方式
*/
function throttle(func,wait) {
var timeout;
var args;
var _this;
return function() {
_this=this;
args=arguments;
if(!timeout) {
timeout=setTimeout(function() {
func.apply(_this,args)
timeout=null;
},wait)
}
}
}
语言组织:
功能:就是代表能用!
性能:就是代表好用!
四、new的实例原理:
面试官可能会这样问:
1.new一个构造函数时,中间发生了什么?
2.或者new一个构造函数,中间执行了哪些步骤?
答:
第一步:创建一个临时对象obj
第二步:获取构造函数赋值给Constructor
第三步:将obj的原型指向Constructor的原型,目的可以让实例化对象找到构造器原型上的方法
第四步:让Constructor属性作用于obj上,从而可以操作this.xxx的实例属性
第五步:返回临时对象obj
封装的new代码如下:
function new1() {
// 创建一个临时对象
var obj={};
//获取构造函数赋值给Constructor
var Constructor=[].shift.apply(arguments)
//然后arguments中的值只能除第一个值之外的参数了
//将obj的原型指向Constructor的原型,目的可以让实例化对象找到构造器原型上的方法
obj.__proto__=Constructor.prototype
//让Constructor属性作用于obj上,从而可以操作this.xxx的实例属性
Constructor.apply(obj,arguments)
//返回obj
return obj;
}