js中的this的情况
自执行函数/setTimeout/setIntrval
自执行函数/setTimeout/setIntrval中的this在非严格模式下一般指向window,严格模式下指向undefined。
自执行函数
(function(){
console.log(this);
})()
setTimeout/setInterval
function Fn(){
setTimeout(function(){
console.log(this);
},0)
}
Fn();
事件绑定
给元素的某个事件绑定方法,事件触发,方法执行,此时方法中的this一般指向元素本身.
<div id="box"></div>
<!-- 使用DOM0级事件绑定 -->
<script>
// 情况1
box.onclick = function(){
console.log(this); // box
}
// 情况2
function click2(){
console.log(this); // box
}
box.onclick = click;
// 情况3
function click3(){
console.log(this); // this=>window;
return function(){
console.log(this) // this=>box;
}
}
box.onclick = click3();
</script>
<!-- 使用DOM2级事件绑定 -->
<script>
// 标准浏览器下:
box.addEventListener('click',function(){
console.log(this); // this=> box
})
// 在ie6,7,8下,绑定事件需要attachEvent,使用attachEvent绑定元素,在ie6,7,8下,this不执行当前元素,指向window.
box.attachEvent('click',function(){
console.log(this); // this=> window
})
</script>
普通函数this指向
普通函数执行
- this是谁和普通函数在哪定义或者在哪执行都没有关系.
- 普通函数执行,他的this指向谁,取决于方法前面是否有"点".
- 有"点"的话,点前面是谁,一般就指向谁
- 没有"点"的话,一般都指向window(严格模式下指向undefined)
- 自执行函数,一般都指向window.
function fn(){
console.log(this);
}
let obj = {
a: 10,
fn: fn
}
fn(); // this->window
obj.fn(); // this->obj
// 在setTimeout中
setTimeout(obj.fn,1000); // this->window
// 这个时候相当于把obj.fn地址值拿过来,并没有执行,this:window
setTimeout(obj.fn(),1000); // this->obj
// 这个时候相当于把obj.fn直接执行,方法执行: this: obj
构造函数执行
构造函数中的this一般指向当前类的实例
function Fn(){
console.log(this); // fn
}
let fn = new Fn();
箭头函数中的this
- 箭头函数没有this执行,箭头函数中所用到的this都是指向其上下文
- 箭头函数用call,apply时,this被忽略掉了,因为箭头函数没有this
- 箭头函数还没有arguments实参集合和prototype(也就是没有构造器,所以不能被new执行)
let obj = {
fn: ()=>{
/*
* 这种是箭头函数执行,箭头函数没有this,this都是其上下文中的this;
* */
// 不管怎么执行: this: window
console.log(this)
},
fn1(){
/*
* obj = { fn(){} } 相当于 obj = {fn: function(){}}
* 省略方法的function
* */
console.log(this);
}
}
obj.fn(); // this->window;
obj.fn1(); // this->obj
call、apply、bind分析
都是为了强制改变函数中的this执行,对箭头函数没有效果
call、apply、bind的区别
let obj = {};
function Fn(){};
// call语法
obj.call([context],[参数1],[参数2],[...]);
// apply语法
obj.apply([context],[[参数1,参数2,...]]);
// bind语法
obj.bind([context],[[参数1,参数2,...]])();
- [context]: 就是改变this的指向,传谁就是谁(特殊: 非严格模式下,传递null/undefined指向的也是window)
- call/apply唯一的区别就是参数不同
call是一个一个传
apply是把需要传递的参数以数组的形式传递
- call/apply都是改变this的同时把函数执行了
- bind不是立即执行,而是预先改变this,在传递一些内容(柯理化函数)
call/apply/bind源码解析
(function(proto){
/*
call
*/
function call(context){
if(context == undefined) {
context = window;
}
context.fn = this;
var arr = [];
for(var i = 1;i<arguments.length;i++){
arr.push(arguments[i]);
}
let result = context.fn(...arr);
delete context.fn;
return result;
}
/*
apply
*/
function apply(context,...args){
if(context == undefined) {context = window;}
context.fn = this;
var result = context.fn(...args);
delete context.fn;
return result;
}
/*
bind
*/
function bind(context){
if(context == undefined) {context = window;}
var that = this;
var outArgs = Array.prototype.slice.call(arguments,1);
return function anonymous(){
var innerArgs = Array.prototype.slice.call(arguments,0);
params = outArgs.concat(innerArgs);
that.apply(context,params);
}
}
function bind(context,...outArgs){
var that = this;
return function anonymous(...innerArgs){
that.apply(context,[...outArgs,...innerArgs])
}
}
proto.bind = bind;
proto.apply = apply;
proto.call = call;
})(Function.prototype)
阿里面试题
function fn1(){ console.log(this,1) }
function fn2(){ console.log(this,2) }
fn1.call(fn2);
fn1.call.call(fn2);
Function.prototype.call(fn2)
Function.prototype.call.call(fn2)