1、this为何而生?
函数可复用、代码简洁易维护
例:function speak(){
console.log("hello "+this.name)
}
let p1 = {
name:"Mike"
}
let p2 ={
name:"David"
}
speak.call(p1) // hello Mike
speak.call(p2) // hello David
解释:正如例子所示,speak函数内部的name变量并不会写死,而是利用this来绑定,根据不同的对象,
调用对应的name值。如果不采用this,而是采用给speak函数传递name参数,当参数多且复杂的情况下,
代码会变得乱糟糟。
2、对于this的理解误区:
2-1、this指向函数本身 (x)
2-2、this指向函数作用域 (x)
例:functon doSomething(){
this.count ++
}
解释:doSomething.count和this.count并不是相等,this指向函数被调用的上下文对象。
例:function father(){
var age = 50;
this.son();
}
function son(){
console.log(this.age)
}
father() // 结果报错not defined,this并没有指向father的作用域
解释:就是son函数的this并不指向father函数作用域对象,因此不能获取father内的age属性。
3、正确概念:
正确的解释是:this是在运行时绑定,和函数的申明位置没有关系,而取决于函数的调用方式。
4、this绑定规则:
既然,this的指向不明,那么就有一套规则去判断,当函数被调用时this应该指向哪个对象。this绑定规则按照优先级的高低,从低到高依次为:
默认绑定 < 隐式绑定 < 显示绑定 < new绑定
4-1、默认绑定:函数独立调用
例:上述的doSomething函数,直接调用doSomething(),由于没有为该函数指定明确的调用对象,默认
会寻找全局对象(非严格模式下),或者结果为undefined(严格模式下)
4-2、隐式绑定:为函数找个宿主(即找个对象),将函数包裹在内。 此时,this指向宿主对象。
例:var obj = {
age:18,
son:son
}
调用方法:obj.son() //18
不足之处:隐式绑定并不能严格保证this指向宿主对象。
例:let son = obj.son
son() //找到全局对象的age属性,或者undefined
因为let son = obj.son将函数从obj宿主对象中取出,然后在全局环境中调用,由于son函数调用时
并没有宿主对象包裹,隐式绑定规则失效,采用了默认绑定规则。真好印证了this是在运行时绑定的,
没记住,请再次默念三遍。
4-3:显示绑定:javascript函数自带的call和apply方法,可以将this绑定到指定的对象上。
例:let obj = {age:18}
son.apply(obj,arguments)或者son.call(obj,argument)
由显示绑定衍生出更安全的this绑定(硬绑定)
利用函数实现上述显示绑定
例:
function bind(){
son.apply(obj,arguments)
}
bind() //18
解释:es5内置的Function.proptotype.bind方法正是利用了硬绑定的原理。(后续有空可以写一篇
关于bind的实现细节)
4-4:new绑定:通过new关键字被调用的函数。
例:let son = new Son(20);
son.age //20
通过new创建Son构造函数的一个新对象son, 这个new过程中,实现了this指向新对象son。
下面我们看一下new的过程,到底this是怎么被绑定的。
1、创建新的对象
2、新对象执行[[prototype]]链接(继承构造函数的属性和方法)
3、this绑定到新对象上面
4、如果构造函数没有返回其他对象,则直接返回新对象
5、特殊情况:
es6中的箭头函数并不遵循以上四条规则。箭头函数的this是根据当前的词法作用域来决定。具体说,箭头函数绑定为申明时的作用域对象上。
续: this的知识体系非常强大,后续将带来更多的分享,谢谢你的支持哦~