几乎是JS独创的允许独立函数里出现this,使的大量的JS开发工作者,徒增大量的烦恼,但是这是js中必须要掌握的东西,所以不得不学习,为了避免忘记,现将此时此刻思路记录于此。核心思想:this始终指向的是调用它的对象。(本文章不讨论严格模式)
注意: const 和 let 声明的变量不是window对象,参考链接。
毫无疑问this指向全局对象,例如window
var variable = 1;
console.log(window.variable);// 输出 1
console.log(this.variable);// 输出 1
console.log(this === window);// 输出 true
console.log(this);// 输出 Window
指向全局对象,例如window
function func(){
var temp = 2;
console.log(this);// 输出 Window
console.log(temp);// 输出 2
console.log(window.temp)// 输出 undefined PS:由于temp在函数内声明,属于局部变量,所以全局对象找不到temp
console.log(this.temp);// 输出 undefined PS:由于temp在函数内声明,属于局部变量,所以全局对象找不到temp
}
func();
console.log(this.temp);// 输出 undefined PS:由于temp在函数内声明,属于局部变量,所以全局对象找不到temp
这里的this指向的是对象obj,因为那个函数调用,this指向哪里,即this始终指向的是调用他的对象。
var a = 111;
var obj = {
b:222,
fc:function(){
console.log(this);// 输出 {b: 222, fc: ƒ}
console.log(this.b);// 输出 222
console.log(this.a);// 输出 undefined
}
}
obj.fc();
虽然obj2.fc是从obj1.fc赋值而来的,但是在obj2调用fc()时,obj2作为调用函数,this指向obj1。
var obj1 = {
b:222,
fc:function(){
console.log(this.b);// 输出 222
}
}
var obj2 = {
b:333
}
obj2.fc = obj1.fc;
obj1.fc();// 输出 222
obj2.fc();// 输出 333
尽管函数fc()被最外层对象outerObj调用,但是this指向的仍是它的上级对象innerObj。
var outerObj = {
a:111,
innerObj:{
b:222,
fc:function(){
console.log(this.a);// 输出 undefined
console.log(this.b);// 输出 222
}
}
}
outerObj.innerObj.fc();
指向构造函数内部,主要是因为是用new操作符调用构造函数的四个步骤:
(1) 创建一个新对象
(2) 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象 )
(3) 执行构造函数中的代码
(4) 返回新对象
var tempClass = function() {
this.a = 111;
};
var tempClass = new tempClass();
console.log(tempClass.a);// 输出 111
tempClass.a = 222;
console.log(tempClass.a);// 输出 222
箭头函数中的this是在定义函数的时候绑定,而不是在执行函数的时候绑定,即this是继承自父执行上下文。
var a = 111;
var obj = {
a: 222,
fc: () => {
console.log(this.a);
}
};
obj.fc();// 输出 111
var a = 111;
function tempClass() {
this.a = 222;
var fc = () => {
console.log(this.a);
};
fc();
}
var tempClass = new tempClass();
// 输出 222
call()、apply()、bind() 都是用来重定义 this 这个对象的。
可以通过设置call方法的第一个参数改变this的指向对象。第一个参数之后的所有参数随便传。
var obj = {
a: 111,
fc: function(e1, e2) {
console.log(this.a, e1, e2);
}
};
var obj2 = obj.fc;
obj2.call(obj, 1, 2);// 输出 111 1 2
可以通过设置apply方法的第一个参数改变this的指向对象。其余期望传入参数都必须放进一个数组,作为apply的第二个参数传入。
var obj = {
a: 111,
fc: function(e1, e2) {
console.log(this.a, e1, e2);
}
};
var obj2 = obj.fc;
obj2.apply(obj, [1,2]);// 输出 111 1 2
bind会返回一个函数,函数体内的this对象的值会被绑定到传入bind()第一个参数的值,而不是立即执行。
var obj = {
a: 111,
fc: function(e1, e2) {
console.log(this.a, e1, e2);
}
};
var obj2 = obj.fc.bind(obj, 1, 2);
console.log(obj2);// 输出 ƒ (e1, e2) { console.log(this.a, e1, e2);}
obj2(3, 4);// 输出 111 3 4
// 目的 :改变this指向,让fn的this指向object
// 怎么能改变this指向?
// 谁调用指向谁
// 让object调用fn
// 给object添加一个fn(func)属性,让object调用fn,这样fn的this就指向object了
Function.prototype.myCall = function (ctx, ...agrs) {
// 如果函数的最后一个命名参数以...为前缀,则它将成为一个由剩余参数组成的真数组,其中从0(包括)到theArgs.length(排除)的元素由传递给函数的实际参数提供。
ctx = (ctx === null || ctx === undefined) ? globalThis : ctx;
// this就是fn
const key = Symbol('key');
ctx[key] = this;
Object.defineProperty(ctx, key, {
enumerable: false,
value: this
})
const result = ctx[key](...agrs);
delete ctx[key];
return result;
}
Function.prototype.myApply = function (ctx, agrs) {
return Function.prototype.myCall(ctx, ...agrs)
}
Function.prototype.myBind = function (ctx, ...external) {
const that = this;
return function (...internal) {
// new.target 属性允许你检测函数或构造方法是否是通过new运算符被调用的。在通过new运算符被初始化的函数或构造方法中,new.target返回一个指向构造方法或函数的引用。在普通的函数调用中,new.target 的值是undefined。
if (new.target) {
return new that(...allArgs)
} else {
return that.myCall(ctx, ...external, ...internal)
}
}
}
const object = {
name: '这是我的名字'
}
function fn(a, b) {
console.log(this.name, a, b)
}
fn.myCall(object, 1, 2)
如果返回值是一个对象,那么this指向的就是那个返回的对象,如果返回值不是一个对象那么this还是指向函数的实例。参考链接
// 返回Number
function func1() {
this.a = 111;
return 1;
}
var temp1 = new func1;
console.log(temp1.a);// 输出 111
// 返回String
function func2() {
this.a = 111;
return '';
}
var temp2 = new func2;
console.log(temp2.a);// 输出 111
// 返回对象
function func3() {
this.a = 111;
return {};
}
var temp3 = new func3;
console.log(temp3.a);// 输出 undefined
// 返回Array
function func4() {
this.a = 111;
return [];
}
var temp4 = new func4;
console.log(temp4.a);// 输出 undefined
// 返回undefined
function func5() {
this.a = 111;
return undefined;
}
var temp5 = new func5;
console.log(temp5.a);// 输出 111
// 返回null。
function func6() {
this.a = 111;
return null;
}
var temp6= new func6;
console.log(temp6.a);// 输出 111