this指向(一)

232 阅读3分钟

关于 This指向问题

1 定义

this 关键字是函数运行时自动生成的一个内部对象。
函数不执行,this没有意义。只能在函数内部使用,
总指向调用它的对象

2 绑定规则

  • 默认绑定: 默认指向window, 独立调用也指向window
  • new绑定
  • 显式绑定:call apply bind
  • 隐式绑定: 谁调用就指向谁(特例:隐式丢失,参数赋值)

例: 默认绑定

// 全局环境中定义person函数,内部使用this关键字
// **独立执行函数,this指向window**

var name = 'Jenny';
function person() {
    return this.name;
}
console.log(person());  //Jenny

例:new绑定

// 通过构建函数new关键字生成一个实例对象,此时this指向这个实例对象

function test() {
 this.x = 1;
}

var obj = new test();
obj.x // 1

特殊情况1:

// new过程遇到return一个对象,此时this指向为返回的对象

function fn() {  
  this.user = 'xxx';  
  return {};  
}
var a = new fn();  
console.log(a.user); //undefined

特殊情况2:

// 如果返回一个简单类型的时候,则this指向实例对象

function fn() {  
  this.user = 'xxx';  
  return 1;
}
var a = new fn;  
console.log(a.user); //xxx

特殊情况3:

// 注意的是null虽然也是对象,但是此时new仍然指向实例对象

function fn() {
  this.user = 'xxx';  
  return null;
}
var a = new fn;  
console.log(a.user); //xxx

例:显式绑定

apply()、call()、bind()是函数的一个方法,作用是改变函数的调用对象。它的第一个参数就表示改变后的调用这个函数的对象。因此,这时this指的就是这第一个参数

var x = 0;
function test() {
 console.log(this.x);
}

var obj = {};
obj.x = 1;
obj.m = test;
obj.m.apply(obj) // 1
function test(a,b,c,d) {
  console.log(a, b, c, d)
}

const obj = {
  a:2,
  foo: test
}

var bar = obj.foo
obj.foo(1, 2, 3, 4)
bar.call(obj, 1, 2, 3, 4)
bar.apply(obj, [1, 2, 3, 4])
bar.bind(obj)(1, 2, 3, 4)

例: 隐式绑定

// 函数还可以作为某个对象的方法使用,这时this指向这个上级对象

function test() {
  console.log(this.x)
  function inner() {
    console.log(this)
  }
  inner()
  // 注意 这里的inner属于独立执行  则指向window
}
const obj = {}
obj.x = 1
obj.m = test
obj.m() // 1 window
// 自执行函数在任何情况下无论怎么调用 this都指向window
// 如果在node 环境中  则指向对应的全局对象

(function foo() {
  console.log(this)  // window
})()
// 这里属于闭包, obj.foo() 相当于test函数
// 则 obj.foo()()则相当于test(), 独立调用则this指向window

const obj = {
  a: 'xxx',
  foo: function() {
    function test() {
      console.log(this)
    }
    return test()
  }
}
obj.foo()() // window
// 函数中包含多个对象,尽管这个函数被外层的对象所调用,this指向的也只是它的上一级对象

var o = {
  a: 10,
  b: {
    fn: function() {
      console.log(this.a)
    }
  }
}
o.b.fn()

// 上述内容中this的上一级对象是b,b没有a变量的定义,所以结构是undefined 

特殊情况1: 变量赋值(隐式丢失)

var o = {
    a:10,
    b:{
        a:12,
        fn:function(){
            console.log(this.a); //undefined
            console.log(this); //window
        }
    }
}
var j = o.b.fn;
j();

// 此时指向的是window, this永远指向最后调用它的对象。不调用则this没有意义。
// 虽然fn是b的方法,但是fn赋值给j并没有执行,所以最终指向window.
// 属于 函数的独立调用

特殊情况2:参数赋值

var a = 0
function foo() {
  console.log(this)
}
function bar(fn) {
  fn()
}
var obj = {
  a: 2,
  foo: foo
}
// 预编译的过程中,实参被赋值为形参(值的拷贝过程,浅拷贝)
bar(obj.foo)
// bar(obj.foo) 其实就是执行bar函数,fn就是代表 foo函数
// 执行fn() 则就是独立调用foo函数 所以执行的是window

3 优先级

默认绑定 < 隐式绑定 < 显示绑定 < new 绑定

function foo(b) {
  this.a = b
}
var obj1 = {}
var bar = foo.bind(obj1)
bar(2)

console.log(obj1.a) // 2
var baz = new bar(3)
console.log(obj1.a) // 2
console.log(baz) // 3