【JavaScript】this指向机制

this指向问题

this机制:this绑定只取决于函数调用的方式,大的来说有三种:

  1. 函数调用:window/undefined
  2. 方法调用:调用对象
  3. 构造函数:返回的实例对象

此外,注意两点:

  1. 利用call、apply、bind可以改变this指向
  2. 箭头函数的this继承外层函数

1. this机制

  • 全局作用域中,window
  • 函数调用(普通调用、IIFE),window
  • 方法调用,绑定到调用对象
  • 隐式丢失(被传递给变量或者参数)
var a = 0;
function foo(){
	console.log(this.a);
};
var obj = {
	a: 1,
	foo: foo
};
obj.foo(); // 1
var bar = obj.foo; // 隐式丢失
bar(); // 0
(obj.foo)(); // 1
(obj.foo = obj.foo)(); // 0
  • 显式绑定 : bind、apply、call (作业帮面试)
  • 硬绑定:绑定后无法修改this
var a = 0;
var obj = {a: 1};
function foo(){
	console.log(this.a);
};
function bar(){
	foo.call(obj);
};
bar(); // 1
var baz = foo.bind(obj);
baz(); // 1
  • 数组内置函数显示绑定:map forEach filter some every
  • new绑定:构造函数
    • 构造函数一般不使用return语句,通常初始化新对象,当构造函数的函数体执行完毕时,会显示返回。this指向新返回的实例对象
    • 构造函数使用了return语句,但没指定返回值,或者返回一个原始值,那么这时将忽略返回值。返回构造出来的实例对象。
    • 构造函数显示地使用return语句返回一个对象,this指向这个对象
// 1
function Car(){
	this.counts = 1200;
}
var c = new Car(); // {counts: 1200}

// 2
function Car(){
	this.counts = 1200;
	return;
}
var c = new Car(); // {counts: 1200}

// 3
function Car(){
	this.counts = 1200;
	return {noCounts: 0};
}
var c = new Car(); // {noCounts: 0}
  • 严格模式下,独立调用的函数的this指向undefined
  • 非严格模式下,call、apply中的null、undefined会被转化成window
function Foo(v){
	this.a = v;
};
var obj = {};
var bar = Foo.bind(obj);
bar(0);
console.log(obj.a); // 0
var baz = new bar(1);
console.log(obj.a); // 0
console.log(baz.a); // 1

2. this指向优先级

优先级:new > call/apply/bind > 方法调用 > 函数调用

// 1.
var a = 0;
function foo(){
	function test(){
		console.log(this.a);
	};
	return test;
};
var obj = {
	a: 1,
	foo: foo
}
obj.foo()(); // 0

// 2.
var a = 0;
function foo(){
	var that = this;
	function test(){
		console.log(that.a);
	};
	return test;
};
var obj = {
	a: 1,
	foo: foo
}
obj.foo()(); // 1

3. 箭头函数

  • 箭头函数:改变this机制,不再只是根据函数调用方式决定;箭头函数会继承外层this指向 —> 这直接解决了var that = this;的写法
  • call/apply/bind 无法改变箭头函数的this指向(流利说面试)
var a = 0;
function foo(){
	var test = () => this.a;
	return test;
};
var obj1 = {
	a: 1,
	foo: foo
};
var obj2 = {
	a: 2,
	foo: foo
};
obj1.foo().call(obj2); // 1

4. 手写bind(度小满面试)

一、bind和柯里化是分不开的。手写bind就是利用柯里化绑定部分参数实现的。

// 注意内外两层参数
Function.prototype._bind = function(thisArg, ...args){
    let fun = this;
    return function(){
        fun.call(thisArg, ...args, ...arguments);
    }
}

二、手动实现一个apply

// 利用方法调用,绑定this指向
Function.prototype._apply = function(thisArg, ...args){
    // 注意这里只考虑了thisArg为对象的情况,才能添加方法
    thisArg['_fun'] = this; // 添加方法
    let result = thisArg._fun(...args);
    delete thisArg._fun; // 删除方法
    return result;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值