JS中的执行上下文「EC」:供代码执行的环境,进栈执行,执行完可能释放也可能不释放
- 全局执行上下文 EC(G)
- 块级私有上下文:除函数/对象之外的大括号中,但凡出现基于let/const/function声明变量的,都会产生块级上下文
- 函数私有上下文:函数执行产生的
THIS:执行主体,谁把它执行的「THIS是谁,和函数在哪创建以及在哪执行都没有半毛钱的关系」
- 全局执行上下文中的THIS是:window
- 块级私有上下文中的THIS是:它没有THIS,用到的THIS都是所处环境中的THIS
- 我们都是研究函数私有上下文中的THIS是谁
JS函数中,THIS可能出现的五种情况:
-
给当前元素的某个事件行为绑定方法,当事件行为触发,绑定的方法会执行,此时函数中的THIS是当前操作元素本身!
box.οnclick=function(){
//点击box后:this->box
}; -
方法执行,看方法名前面是否有“点”;有“点”,“点”前面是谁THIS就是谁;没有“点”,THIS是window/undefined;
// Array.prototype.slice 想把这个slice方法执行?
let arr=[];
arr.slice(); //arr基于原型链机制,找到数组原型上的slice方法执行 slice中的this->arr
arr.proto.slice(); //slice中的this->arr.proto / Array.prototype
Array.prototype.slice(); //slice中的this->Array.prototype
const slice=Array.prototype.slice;
slice(); //slice中的this->window/undefinedconst slice=Array.prototype.slice;
let arr=[10,20,30,40];
arr.slice(2); //->[30,40] 找到slice把其执行,方法中的this是arr,所以查找的是arr中索引2及后内容
slice.call(arr,2); //->[30,40]arguments函数的实参集合「类数组,不是Array的实例」
arguments.slice(0); //报错:arguments.slice is not a function
slice.call(arguments,0); //这样就好了:把数组原型上的slice执行,让其this变为arguments,实现类数组借用数组的方法,以此达到类数组转换为数组的效果匿名函数中THIS的分析
- 自执行函数
(function(){
//this:window/undefined
})(); -
回调函数:一般this都是window,除非特殊处理了
const func=function(callback){
callback();
};
func(function(){
//this:window/undefined
});const func=function(callback){
let arr=[10,20,30];
callback.call(obj); //特殊处理
};
func(function(){
//this:obj
});
arr.forEach(function(item,index){
// 执行数组原型上的forEach: this->arr callback->传递的回调函数 迭代数组中的每一项,每迭代一次就把回调函数执行一次
// item:当前迭代这一项
// index:当前迭代这一项的索引
// 回调函数中的this->window
});
arr.forEach(function(item,index){
// this->obj
},obj); //forEach中传递的第二个参数,就是改变回调函数中this指向的
- 自执行函数
-
构造函数执行「new 执行」,构造函数体中的this是当前实例本身
function Fn(x,y){
let num=10;
this.x=x;
this.y=y;
}
Fn.prototype.sum=function sum(){
console.log(this.x+this.y);
};
let res1=Fn(10,20);
let res2=new Fn(10,20); -
箭头函数中没有自己的THIS,所用到的THIS都是其所处上下文中的THIS
let obj={
name:‘刘兴华’,
age:18,
fn(){
//this->objlet self=this; setTimeout(function(){ //this->window //console.log(this.name); console.log(self.name); },1000); setTimeout(()=>{ console.log(this.name); //obj.name },1000); }
};
obj.fn(); -
基于call/apply/bind可以强制改变THIS指向
obj.fn(); //fn中的this->obj
obj.fn.call(arr); //fn中的this->arrFunction.prototype.call/apply/bind 所有函数都可以调用这三个方法
- call/apply是把函数立即执行,并且改变其中的this指向
- bind是预处理的思想,只是预先改变函数中的this,但是此时函数不执行…