个人笔记
全局上下文this是window
全局上下文中的this是window(JS严格模式下是undefined);块级上下文中没有自己的this,所用到的this都是所处上级上下文中的this
console.log(this); //window
{
let n = 12;
console.log(this); //window 上级上下文是全局上下文
}
this是函数的执行主体
区分:函数执行主体:谁把函数执行的;函数执行上下文:在哪执行的
注意:只有函数执行的时候才知道函数中的this是什么,根据不同的情况来不同判断,在创建函数的时候不知道this是什么
规律:
- 事件绑定:给当前元素的某个事件行为绑定方法,当事件触发、方法执行,方法中的
this是当前元素本身的DOM对象注意:document.body.onclick = function () { console.log(this); //body }; document.body.addEventListener('click', function () { console.log(this); //body }); // IE6~8 DOM2事件绑定 document.body.attachEvent('onclick', function () { console.log(this); //window });- IE6~8 DOM2事件绑定
this还是window - vue中事件绑定,
v-on:click='fn',fn方法中的this是vue实例,因为vue在内部做了特殊处理
- IE6~8 DOM2事件绑定
- 普通函数执行
-
函数执行前面是否有“点”,没有“点”,
this就是window(JS严格模式下是undefined) -
有“点”,“点”前面是谁
this就是谁,几个例子如下:function fn() { console.log(this); } let obj = { name: 'ttt', fn: fn }; fn(); //this->window obj.fn(); //this->obj// 开启JS严格模式 =>注意严格模式和非严格模式的区别 "use strict"; function fn() { console.log(this); } let obj = { name: 'ttt', fn: fn }; fn(); //this->undefined obj.fn(); //this->obj -
匿名函数(自执行函数/回调函数)如果没有经过特殊的处理,则
this一般都是window/undefined,但是如果经过一些特殊处理,一切都以处理后的结果为主个人理解:函数在没执行之前,只是存在一块内存里的一段字符串,等执行的时候才变为可执行的代码,到那时候其中的
this再根据当时调用的情况再来判断到底是什么,然后看函数执行时的私有上下文的作用域链,看私有变量,等等。例如,同样内存地址的函数,调用时是在全局调用this就是window,对象调用this就是对象function fn(callback) { callback(); //callback()中的this->window/undefined } let obj = { sum() { console.log(this); } }; obj.sum(); //this->obj // 回调函数:把一个函数作为实参值,传递给另外一个函数 // => fn(function () {}); fn(obj.sum); //this->window/undefinedsetTimeout(function () { console.log(this); //window或者undefined }, 1000);let obj = { name: 'xxx' }; let arr = [10, 20]; arr.forEach(function (item, index) { console.log(this); //window或者undefined });经过特殊处理的例子:
let obj = { name: 'xxx' }; let arr = [10, 20]; arr.forEach(function (item, index) { console.log(this); //obj 因为触发回调函数执行的时候,forEach内部会把回调函数中的this改变为传递的第二个参数值obj “特殊处理” }, obj);document.body.addEventListener('click',function(){console.log(this)})//body 经过特殊处理特殊:
let obj = { sum() { console.log(this); } }; obj.sum(); //this->obj (obj.sum)(); //this->obj // 括号表达式:小括号中包含“多项”(如果只有一项,和不加括号没啥本质区别),其结果是只取最后一项;但是这样处理后,this会发生改变,变为window/undefined (10, obj.sum)(); //this->window
关于this的基本情况的面试题
var x = 3,
obj = {x: 5};
obj.fn = (function () {
this.x *= ++x;
return function (y) {
this.x *= (++x)+y;
console.log(x);
}
})();
var fn = obj.fn;
obj.fn(6);
fn(4);
console.log(obj.x, x);
/*
13
234
95 234
*/
简单分析
-
前两行声明变量,执行到第三行
obj.fn = (function () {...})();会立即执行这个函数,这里this.x *= ++x;=>this.x *= this.x *(++x);,也就是全局的x = x*(++x)=>x=3*4=12,所以全局x现在值为12 -
接着
return一个函数,把这个函数记录一下,所以obj.fn是这个函数。function (y) { this.x *= (++x)+y; console.log(x); } -
因为
var fn = obj.fn;,所以全局的fn也是这个函数,这个函数中,x就是全局的x因为立即执行函数和这个函数没有私有变量,根据作用域链往上寻找,就到了全局的x,但是this.x还不清楚这个this是什么,需要根据执行场景环境的不同,来确定这个this是什么。 -
接着执行
obj.fn(6),将6带入,作为函数私有上下文中的私有变量y.this。x *= (++x)+y;=>this.x *=this.x * ((++x)+y)这句代码,因为是obj.fn,所以其中this.x就是obj.x,既5,所以obj.x = 5*((12+1)+6)=95,现在obj.x值为95,全局x值为13。所以首先打印13 -
接着执行
fn(4),还是上面记录下来的函数,此时函数中的this是window,所以this.x *= (++x)+y;=>window.x =window.x * ((++window.x)+y)即window。x=13*(13+1+4)=234,此时全局x值为234,所以打印234 -
最后
console.log(obj.x, x)分别打印95234
var num = 10;
var obj = {
num: 20
};
obj.fn = (function (num) {
this.num = num * 3;
num++;
return function (n) {
this.num += n;
num++;
console.log(num);
}
})(obj.num);
var fn = obj.fn;
fn(5);
obj.fn(10);
console.log(num, obj.num);
/*
22
23
65 30
*/
和上面一样的分析思路
全局上下文基于var/function声明的变量,会给GO(window)设置对应的属性,这样有时候this指向window,就会改变window的对应属性,同样改变声明的变量
初始化this,初始化auguments,形参赋值,变量提升
/*
* EC(G)
* 变量提升:--
* ----VO(G)
* obj = 0x000
* fn = 0x001
*/
let obj = {
// fn:0x001
fn: (function () {
/*
* EC(AN)
* 作用域链:<EC(AN),EC(G)>
* 初始THIS:window
* 形参赋值:--
* 变量提升:--
*/
return function () {
console.log(this);
}; //return 0x001; [[scope]]:EC(AN)
})()
};
obj.fn(); //this->obj
let fn = obj.fn;
fn(); //this->window
var fullName = 'language'; //window.fullName='language'
var obj = { //window.obj=0x000
fullName: 'javascript',
prop: {
getFullName: function () {
return this.fullName;
}
}
};
console.log(obj.prop.getFullName()); //this->obj.prop ->obj.prop.fullName ->undefined
var test = obj.prop.getFullName;
console.log(test()); //this->window ->window.fullName ->'language'
var name = 'window';
var Tom = {
name: "Tom",
show: function () {
// this->window
console.log(this.name); //->'window'
},
wait: function () {
// this->Tom
var fun = this.show; //fun=Tom.show
fun();
}
};
Tom.wait();
this的指向跟在哪定义的,在哪执行的都没有关系,fun()直接执行,前面没有.,所以this就是window,有.就是.前面的
window.val = 1; //val是GO的属性,“也可以说”是全局变量「val=100 / window.val=100」
var json = {
// val是json对象的一个属性「json.val」
val: 10,
dbl: function () {
this.val *= 2;
}
}
json.dbl();
// this->json
// json.val *= 2 => json.val=json.val*2 => json.val=20
var dbl = json.dbl;
dbl();
// this->window
// window.val *= 2 => window.val=2
json.dbl.call(window);
// this->window 基于call方法强制改变方法中的this是window
// window.val *= 2 => window.val=4
alert(window.val + json.val); //=>“24”
(function () {
// this->window
var val = 1;
var json = {
val: 10,
dbl: function () {
// this->json
// val不是json.val,是其上级上下文中的val变量
val *= 2;
}
};
json.dbl();
alert(json.val + val); //=>“12”
})();