this: 这给我指哪来了?
前言:为什么要有this?
在 JavaScript 中,this
的指向是一个较为复杂但又非常重要的概念。this
的具体指向并非固定不变,而是根据函数调用的方式和上下文来动态确定。
那么,为什么要有this
?答案是为了让对象中的函数有能力访问对象自己的属性,this
可以显著的提升代码质量,减少上下文参数的传递。
疑问
奇怪,当同一段代码分别在Node上和浏览器上分别输出了不同的答案,你到底该相信谁呢?
function foo(){
console.log(this.a);
}
var a = 1;
foo();
如图可见,在Node上和浏览器上的输出分别是undefined
和1
。
实际上它们都没有错,只是因为这两种环境下this
的词法作用域不同,在Node中this
指向的是一个空对象,而在浏览器环境中 this
指向的是全局对象 window
。
this的绑定规则
1. 默认绑定:
当一个函数独立调用,不带任何修饰符的时候 :函数在哪个词法作用下生效,函数中的this就指向哪里 -- (只要是默认绑定,this一定指向window)
function foo(){
console.log(this); // 指向window
}
foo(); // 此时的foo就为独立调用
那么如果在此情况下,函数嵌套调用呢?
function foo(){
console.log(this); // 指向window
}
function bar(){
foo();
}
function baz(){
bar();
}
bar(); // 此时的bar为独立调用
答案依旧不变,只要你遵守默认绑定规则,this
就一定指向window
。
2. 隐式绑定:
当函数的引用有上下文对象时(当函数被某个对象所拥有时),函数的this指向引用它的对象。
var obj = {
a:1,
foo: foo // obj隐式绑定了foo
}
function foo(){
console.log(this.a); //指向obj
}
obj.foo(); //输出为1
3.隐式丢失
当一个函数被多个对象链式调用时,函数的this指向就近的那个对象。
var obj = {
a:1,
foo:foo // obj隐式绑定foo
}
var obj2 = {
a:2,
obj:obj
}
function foo(){
console.log(this.a); //指向obj,因为就近对象为obj
}
obj2.obj.foo(); //输出为1
可能你会看到obj2嵌套了obj,便误以为this
指向的就为obj2,但实际上this
的指向采取的是就近原则,先被哪个对象绑定,就指向哪个对象。
4.显示绑定
除去以上的绑定规则外,还有一种更为蛮横的绑定方法,那就是用call
,apply
,bind
去强制规定this
的指向。
call
var obj = {
a:1
}
function foo(){
console.log(this.a);
}
foo.call(obj); //输出为1 因为通过call指定了this值
需要注意的是此时的执行过程是把foo函数当成对象,然后去调用call来使用。
另外此时的call
也具备传参功能:
var obj = {
a:1
}
function foo(x,y){
console.log(this.a,x+y);
}
foo.call(obj,1,2); // 输出为1 3
apply
apply
的用法与call
基本相同,唯一不同之处在于apply
在接受参数时是以数组形式整体的接受,在传参时要加上[]
将参数包括起来:
var obj = {
a:1
}
function foo(x,y){
console.log(this.a,x+y);
}
foo.apply(obj,[1,2]); // 输出为1 3
bind
bind
的特殊之处在于它会创建一个新的函数,并将这个函数与指定的上下文绑定在一起,需要注意的是:它在接收参数时为零散的接收,可以由bind接收,也可以由返回的函数体接收,或者两个人同时接收。
var obj = {
a:1
}
function foo(x,y){
console.log(this.a,x+y);
}
var A = foo.bind(obj,1,2);
A(); // 输出1 3

new绑定
new
绑定是一种构造函数创建实例对象时自然进行的绑定,简单来说就是构造函数内的this统一都指向构造函数自己创建的实例对象。
function Person(){
this.name = '香蕉'
}
let p = new Person();
console.log(p.name); // 输出为 '香蕉'
function Person(){
name = '香蕉'
}
let p = new Person();
console.log(p.name); // 输出为undefined
正常代码输出为香蕉,但是一旦去除去除Person
中的this
,输出则变为undefined
,这是因为函数Person
中的this
指向实例对象p
,此处的this
为什么会指向实例对象P呢?
以下是 let p = new Person()
的执行过程:
由此可见,在执行过程中浏览器会将构造函数Person
中的this
的指向指到对象p
上去。
特殊:箭头函数
箭头函数不绑定自己的this,它会捕获其所在上下文的this值作为自己的this值。这意味着在箭头函数中,this的值是在定义函数时确定的,而非调用时。
var obj = {
a:1,
foo:function(){
//this
const fn =()=>{
console.log(this.a); // 输出1
}
fn()
}}
obj.foo()
结束
看完这篇文章,相信无论以后this
被指到哪里去,我们都能找到它。
转载自:https://juejin.cn/post/7397639310721630242