this的绑定规则及优先级
在 Javascript 中,this指向的绑定规则有以下四种:
- 默认绑定(非严格模式下,this指向window,严格模式下,this指向undefined)
- 隐式绑定(如果函数调用时,前面存在调养它的对象,那么this就会隐式绑定到这个对象上)
- 显示绑定(函数通过 call()、apply()、bind()调用,this指向被绑定的对象)
- new 绑定(函数被new 调用,this指向由new新构造出来的这个对象)
绑定规则的优先级:new 绑定 > 显式绑定 > 隐式绑定 > 默认绑定
function test(){this.a = '111'}let obj = {a:'bbb',fn(){console.log(this)}}function scope(){test() // 默认绑定obj.fn() // 隐式绑定test.call(obj) // 显示绑定new test() // new绑定}const Bar = test.bind(obj);console.log(obj.a,'---',bar.a) // 'bbb --- 111'// new绑定改变了显式绑定中指定的this(obj)// 显示绑定 > new 绑定
this的几种情况
全局作用域下的this指向window,严格模式下为undefined
function windowScope(){console.log(this) // window or undefined}
如果给元素的事件行为绑定函数,那么函数中的this指向当前被绑定的那个元素
document.body.onclick = function(){console.log(this) // body}
函数中的this,要看函数执行前有没有(调用者),如果有的话,调用者是谁,this就指向谁,如果没有调用者,指向window。自执行函数中的this永远指向window
let fn = function() {console.log(this.name)}let obj = {name:'amy',fn};fn(); // window.nameobj.fn(); //obj.name
定时器中函数的this指向window
setTimeout(function(){console.log(this) // window},0)
构造函数中的this指向当前当前的实例
- call、apply、bind 可以改变函数的this指向
- 箭头函数中没有this,如果输出this,就会输出箭头函数定义时所在的作用域中的this
- 括号表达式也有可能改变this,括号内只有一个项不会,两个或多个的话this指向window
this相关面试题
题1:
var num = 10const obj = {num: 20}obj.fn = (function (num) {this.num = num * 3num++return function (n) {this.num += nnum++console.log(num)}})(obj.num)var fn = obj.fnfn(5)obj.fn(10)console.log(num, obj.num)
题2:
var a = {name:"zhang",sayName:function(){console.log("this.name="+this.name);}};var name = "ling";function sayName(){var sss = a.sayName;sss(); //this.name = ?a.sayName(); //this.name = ?(a.sayName)(); //this.name = ?(b = a.sayName)();//this.name = ?}sayName();
题3:
var obj = {a: 1,foo: function (b) {b = b || this.areturn function (c) {console.log(this.a + b + c)}}}var a = 2var obj2 = { a: 3 }obj.foo(a).call(obj2, 1)obj.foo.call(obj2)(1)
题4:
var name = 'window'function Person (name) {this.name = namethis.obj = {name: 'obj',foo1: function () {return function () {console.log(this.name)}},foo2: function () {return () => {console.log(this.name)}}}}var person1 = new Person('person1')var person2 = new Person('person2')person1.obj.foo1()()person1.obj.foo1.call(person2)()person1.obj.foo1().call(person2)person1.obj.foo2()()person1.obj.foo2.call(person2)()person1.obj.foo2().call(person2)
