参考
【第1318期】深入浅出 JavaScript 关键词 -- this
https://juejin.cn/post/684490...
写这篇文章原因
因为总结面经中遇到了this的指向问题,这也是面试官常问的基础问题。所以单独列出来供参考学习
this指向几点判断规则
js的函数除了声明定义的形参之外,每个函数还接受两个附加参数:this和arguments。this
的值并不是由函数定义放在哪个对象里面决定,而是函数执行时由谁来唤起决定。
- 函数调用模式:strict情况下,指向undefined,否则指向全局变量
- 方法调用模式:指向方法所在的对象
- 构造函数模式调用,用
new
时,this指向新构建的对象 - apply,call明确绑定: 或者
bind
绑定,this指向被绑定的对象 箭头函数内部的
this
就是外层代码块的this
,包裹在函数中时this指向函数调用时所在的对象,若放在全局中则是指向全局对象window,且不会改变// Q1 规则1:如果一个函数中有this,但是它没有被上一级的对象所调用,那么this指向的就是window var a = 1; function print () { console.log(this.a) } print() //a=1 // Q2 规则2:如果一个函数中有this,这个函数有被上一级的对象所调用,那么this指向的就是上一级的对象。 const obj = { a: 2, print: function () { console.log(this.a) } } obj.print(); //2 // Q3 const obj = { a: 3, print: function () { console.log(this.a) } } obj.print() //3 与下面的foo()区别在于是全局环境还是obj环境 const foo = obj.print; foo() //undefined 全局情况下调用的,没有全局变量a // Q3.1 如果一个函数中有this,这个函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象 const obj = { a: 3, printOut:{ a:4, printIn: function(){ console.log(this.a)}, }, } obj.printOut.printIn() //4 const foo = obj.printOut.printIn; foo() //undefined 全局情况下调用的,没有全局变量a // Q4 Q4-Q9参见规则5 const obj = { a: 4, print: () => { console.log(this.a) } } obj.print(); //undefined 有箭头函数,对象不构成单独的作用域,导致`print`箭头函数定义时的作用域就是全局作用域。 // Q5 var a = 5 const obj = { a: 6, print: () => { console.log(this.a) } } obj.print.call({a: 7}); //5 理由同上 // Q6 function Person () { this.a = 8 this.print = function () {console.log(this.a)} return {a: 9} } const p = new Person() console.log(p.a) //9 此时p为构造函数返回的{a:9} console.log(p.print()) // undefined p是没有print函数的 // Q7 'use strict'; var a = 1; function print () { console.log(this.a) } print() //undefined 严格模式下,this指向undefined // Q8 普通函数 function foo() { setTimeout(function() { console.log('id:', this.id); }); } var id = 21; foo.call({ id: 42 }); //21 setTimeout是延迟函数,在foo被调用后才执行,这时候this指向window //Q9 箭头函数,匿名函数定义时所在的执行环境就是foo函数,所以匿名函数内部的this执向始终会和foo函数的this执向保持一致,指向call的对象。 为什么指向call的对象呢?参见call的用法:函数名.call(对象,arg1,arg2,...argn),功能是调用函数,并把函数内部的this指向第一个参数的对象,然后将第二个及之后的是所有的参数,作为实参传给函数。 function foo() { setTimeout(() => { console.log('id:', this.id); }, 100); } var id = 21; foo.call({ id: 42 }); //42 function foo() { setTimeout(() => { console.log('id:', this.id); }, 100); } var id = 21; foo(); //21(没有用call) // Q10 var A = function( name ){ this.name = name; }; var B = function(){ A.apply(this,arguments); }; B.prototype.getName = function(){ return this.name; }; var b=new B('sven'); console.log( b.getName() ); // 输出: 'sven'
---更新,今天看了闭包,有了新的认识
//1
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
};
}
};
var a = object.getNameFunc;
a()();//这里的调用者一直是window,因此输出"The Window";
object.getNameFunc()();//这里object.getNameFunc()时调用者是object,但是将object.getNameFunc()作为一个整体,他的调用者是window,是window来调用object.getNameFunc()(),此时调用者是window,因为输出"The Window";
//2
var name = "The Window";
var object1 = {
name : "My Object",
getNameFunc : function(){
var that = this;
return function(){
return that.name;
};
}
};
object1.getNameFunc()();//这里类似上面object.getNameFunc()时调用者是object的,但是在object1.getNameFunc()的返回函数中,将this赋值给that,因此object1.getNameFunc()()中,this仍然是object,所以输出"My Object",
var e = object1.getNameFunc;
e()();//这里this一直是window,因此不管如何赋值,都输出"The Window"
//3
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return this.name;
}
};
object.getNameFunc()
//"My Object"
(object.getNameFunc)()
//"My Object"
(object.getNameFunc = object.getNameFunc)()
//"The Window"
//最后一个object.getNameFunc的值是函数本身。function (){return this.name;}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。