面试整理 -- this、apply、call、bind

原文链接: 掘金-this、apply、call、bind

一、有关this绑定的案例

this永远指向最后调用它的那个对象

Demo1:

var name = "windowName";
function a(){
	var name = "innerName";

	console.log(this.name); // 在非严格模式下(浏览器环境下)结果为windowName,在严格模式下(Node环境下)结果为undefined

	console.log(this); // 在非严格模式下(浏览器环境下)结果为window对象,在严格模式下(Node环境下)报错
}
a();
console.log(this.name); // 在非严格模式下(浏览器环境下)结果为windowName,在严格模式下(Node环境下)结果为{}

Demo2:

var name = "windowName";
var obj = {
	name: 'innerName',
	fn: function () { 
		console.log(this.name); // 在非严格和严格模式下结果都是innerName
	}
}

obj.fn(); // 注: 这次调用函数的是obj对象


// 补充一点,假如把obj中的name换成name1:
var obj1 = {
	name: 'innerName',
	fn: function () { 
		console.log(this.name); //结果就是undefined
	}
}

 

 Demo3: 调用时将obj换成window.obj,  由于最后调用的对象依然是obj,所以打印的结果仍然是innerName 

 Demo4:

// 把obj中的name注释掉

var name = "windowName";
var obj = {
	// name: 'innerName',
	fn: function () { 
		console.log(this.name);  // undefined
	}
}

obj.fn();

fn的最后一个调用对象是obj,而obj中此时并没有name属性,也不会向上一个对象中查找,所以输出结果为undefined

 Demo5:

var name = "windowName";
var obj = {
	name: null,
	fn: function () { 
		console.log(this.name); // 非严格模式下结果为windowName
	}
}

var f = obj.fn;
f();

本例中最关键的一处在于obj.fn的指向给了f,所以此时调用fn函数的对象并不是obj,而是window,所以输出结果为windowName

 Demo6:

var name = "windowName";
function fn(){
	var name = "innerName";
	function innerFn(){
		console.log(this.name); // windowName
				
	}
	innerFn();
}
fn();

我们会以为innerFn在fn里面调用this会指向fn, 但是最先执行的函数fn它的指向对象是window,所以innerFn中this的指向也是window,所以打印结果为innerName

 

二、如何修改this指向

  • 使用ES6箭头函数
  • 在函数内部使用 var that = this;
  • 使用apply、call、bind
  • new实例化一个对象

思考下面的代码: 

var name = "windowName";
var obj = {
	name: "innerName",
	func1: function(){
		console.log(this.name);
	},
	func2: function(){
		setTimeout(function(){
			this.func1();				
		},100)
	}
}

obj.func2();

答案是:     

解释:  虽然func2的调用对象是obj没错,但是func2中的setTimeout函数的调用对象其实是window对象,this指向的也就是window对象。 window对象中并没有func1函数,所以就报错了。。

2.1 箭头函数改造

箭头函数谨记: 箭头函数的this始终指向函数定义时的this,而非函数执行时。箭头函数中没有this绑定,必须通过查找作用域链来决定其值。如果箭头函数被非箭头函数包含,this绑定的时最近一层非箭头函数的this,否则this为undefined

改造后的代码:

var name = "windowName";
var obj = {
	name: "innerName",
	func1: function(){
		console.log(this.name);
	},
	func2: function(){
		setTimeout( ()=> {
			this.fun1(); // innerName
        },100)
    }
}

obj.func2();

2.2 使用var that = this;保存this指向

var name = "windowName";
var obj = {
	name: "innerName",
	func1: function(){
		console.log(this.name);
	},
	func2: function(){
        var that = this;
		setTimeout(function(){
			that.fun1(); // innerName
        },100)
    }
}

obj.func2();

func2中this的指向时调用func2方法的obj, 在调用setTimeout函数之前,我们先将this赋值给that,那么that就指向了obj,在setTimeout函数中that也是指向obj。

2.3 使用apply、call、bind修改this指向

2.3.1 使用apply 原先setTimeout函数中的this是指向window,我们需要将其指向obj,在其函数后面使用.apply(obj)即可改变this指向

面试整理 -- this、apply、call、bind_第1张图片

2.3.2 call 和 bind 用法与上面相同。

面试考点1: apply和call有什么区别

答: apply和call的区别仅在与传递参数的不同,除绑定对象外,apply传递的是一个数组,而call传递的是参数列表。

例:

var name = "windowName";
var obj = {
	name: 'innerName',
	fn: function(a,b){
		console.log(this.name);
		console.log(a+b);
	}
}
var a = obj.fn;

a.apply(obj,[1,2]) // apply写法
 
a.call(obj,1,2) // call写法

面试考点2: apply,call和bind有什么区别?

调用bind时,会创建一个新的函数,必须要我们手动执行

面试整理 -- this、apply、call、bind_第2张图片

三、函数的调用方式

  • 作为一个函数调用
  • 函数作为方法调用
  • 使用构造函数调用函数
  • 作为函数方法调用函数

new 的过程:

面试整理 -- this、apply、call、bind_第3张图片

你可能感兴趣的:(面试整理 -- this、apply、call、bind)