默认绑定:
var name = 'Tiboo' function sayHi(){ console.log(this) // Window对象 } sayHi(); // sayHi运行在全局环境
隐式绑定:
函数的调用是在某个对象上触发的,即调用位置上存在上下文对象
var name = 'yangfu' function sayHi() { console.log(this) // 指向testMan这个对象 console.log('hello', this.name) // hello, Tiboo } var testMan = { name: 'Tiboo', sayHi: sayHi } testMan.sayHi()
// 对象属性链中只有最后一层影响到调用位置
var name = 'yangfu' function sayHi() { console.log('hello', this.name) } var testMan1 = { name: 'Tiboo1', man: testMan2 } var testMan2 = { name: 'Tiboo2', sayHi: sayHi }
testMan1.man.sayHi()
console.log(testMan1.man) // hello, Tiboo2
绑定丢失:
function sayHi() { console.log(this) // 指向Window对象 console.log('hello,', this.name) // hello, yangfu } var testMan = { name: 'Tiboo', sayHi: sayHi } // 此时man直接指向了sayHi, 和testMan没啥关系 var man = testMan.sayHi var name = "yangfu" man()
显示绑定:
function sayHi(){ console.log('Hello,', this.name); // Hello, Tiboo } var testMan = { name: 'Tiboo', sayHi: sayHi } var name = 'yangfu' var man = testMan.sayHi // 通过apply, 设置函数体内this指向的值,此时指向了testMan man.apply(testMan)
将null或者是undefined作为this的绑定对象传入call、apply( 指向被忽略,实际应用的是默认绑定规则,默认绑定其实没研究透,待补充)
function sayHi(){
console.log('Hello,', this.name); // Hello, yangfu
}
var testMan = {
name: 'Tiboo',
sayHi: sayHi
}
var name = 'yangfu'
testMan.sayHi.call(null)
new绑定:
var name = 'Tiboo' function sayHi(name){ this.name = name; } var man = new sayHi('Tiboo2') console.log(man.name) // Tiboo2
箭头函数:
- 没有自己的this, 继承外层代码的this
- 无法用call()、apply()、bind()这些方法去改变this的指向
没有使用箭头函数: var obj = { hi: function(){ console.log(this); return function() { console.log(this) } } } let hi = obj.hi(); //输出obj对象 hi(); //window对象
使用箭头函数后:
var obj = {
hi: function(){
console.log(this);
return () => {
console.log(this)
}
}
}
let hi = obj.hi(); //输出obj对象
hi(); //输出obj对象
自执行函数:
- 自执行函数里面的this指向window
var obj = { hi: function(){ console.log(this); // 输出obj对象 (function() { console.log(this) // window对象 })() } } let hi = obj.hi();
基本上关于this的指向就那么多了,下面是我收集的一些关于this的面试题或者自认为比较有趣的题,孰能生巧,复杂的事情都是由最简单的事情拼接而来的,so,只要肯花心思,问题便不再是问题。
案例一:
var a = { name: 'A', fun: function() { console.log(this.name); } }; a.fun(); // 对象调用, this指向a, this.name = 'A' a.fun.call({ name: 'B' }); // 使用call改变作用域,this指向新创建对象, this.name = 'B' var fun1 = a.fun; // 将对象方法赋值给一个全局变量 fun1(); // this指向全局, 为空
案例二:
var number = 5; var obj = { number: 3, fn: (function () { var number; this.number *= 2; number = number * 2; number = 3; return function () { var num = this.number; this.number *= 2; console.log(num); number *= 3; console.log(number); } })() } var myFun = obj.fn; // 自执行, this.number(window) = 10 myFun.call(null); // this指向window, 传入null导致默认绑定,this.number(window) = 20; num = 10; number = 9; obj.fn(); // this指向obj, num = 3; 闭包导致上次number值为9存在于内存中, number = 27 console.log(window.number); // 20
案例三:
笔试题遇到的,当时只觉得头都绕大了,开始没看清,就想a都没定义,不会报错么
var fn = (function(a) { this.a = a; return function(a) { a += this.a; console.log(a) } }(function(a, b) { return a }(3, 4))) fn(7)
解题步骤:
// 简化: (function(a, b) { return a }(3, 4)) // 运行得到结果3 // 那么,上面function化简 var fn = (function(a) { this.a = a; return function(a) { a += this.a; console.log(a) } }(3)) // 自执行函数this指向window,传入参数3后, this.a(window) = 3; fn(7) // fn()运行是闭包,此时this指向window, a = a + this.a = 3 + 7 = 10
案例四:
题目来源:https://www.cnblogs.com/xxcanghai/p/4991870.html
function fun(n,o) { console.log(o) return { fun:function(m){ return fun(m,n); } }; } var a = fun(0); a.fun(1); a.fun(2); a.fun(3);//undefined,?,?,? var b = fun(0).fun(1).fun(2).fun(3);//undefined,?,?,? var c = fun(0).fun(1); c.fun(2); c.fun(3);//undefined,?,?,?
案例五: 待补充