⤴Top⤴

this 指针

博客分类: 前端

this 指针

this 指针

this 指针指向

this 存在于执行上下文(executation context),指向属性或方法当前所在的对象。

this 指针案例

// 实际执行的是 window.getName(),window 对象并没有 name 属性
// 严格模式中指向的是 undefined
this === window; // true
function getName(){
  var name = "Tate";
  console.log(this.name); // undefined
  console.log(this); // Window
}
getName();
// this 只是指向当前一层的对象,而不会向上继承
// 调用的是 person.spouse 对象,但 spouse 无 name 属性
var person = {
  name: 'Tate',
  spouse:{
    fn: function(){
      console.log(this.name); // undefined
    }
  }
}
person.spouse.fn();
// 赋值但并未执行函数,相当于执行的是 window.fn()
var person = {
  name: 'Tate',
  spouse:{
    name: 'Snow',
    fn: function(){
      console.log(this.name); // undefined
      console.log(this); // Window
    }
  }
}
var fn = person.spouse.fn;
fn();

this 指针案例-多层嵌套

// 内层的 this 不指向外部,而指向顶层对象 Window
var person = {
  name: 'Tate',
  spouse: function () {
    console.log(this.name); // Tate

    var f2 = function () {
      console.log(this); // Window
    }();
  }
}
person.spouse();

可以用变量来保存当前所引用的对象,如下面例子的 that:

var person = {
  name: 'Tate',
  spouse: function () {
    console.log(this.name); // Tate
    var that = this;
    var f2 = function () {
      console.log(that.name); // Tate
    }();
  }
}
person.spouse();

ES6 箭头函数(=>)实际上实现方式与上例类似,它本身是没有 this 属性的,所以也就不能用作构造函数,它会捕获其所在(即定义的位置)上下文的 this 值:

var name = 'Tate';
sayName.call({ name: 'Snow' });

// ES6
function sayName() {
  setTimeout(() => {
    console.log('name:', this.name); // snow
  }, 100);
}

// ES5
function sayName() {
  var _this = this;

  setTimeout(function () {
    console.log('name:', _this.name);
  }, 100);
}

再看个箭头函数的栗子:

var x = 10;
var obj = {
  x: 20,
  say: function() {
    console.log(this.x)
  }
}
obj.say(); // 20
var x = 10;
var obj = {
  x: 22,
  say: () => {
    console.log(this.x); // this 此时指向的是 window
  }
}
obj.say(); // 10

this 指针案例-return

一般情况下若返回的是引用类型,则返回该引用类型;若返回的是基本类型,则无影响。

setTimeout(() => {
  console.log('name:', this.name);
}, 100);

// ES5
function Person() {
  this.name = 'Tate';
  // return undefined; // Tate
  // return null; // Tate
  // return 'Snow'; // Tate
  // return [1, 2]; // undefined
  // return {name: 'Snow'}; // Snow
  return function(){ console.log('Snow'); }; // undefined
}
var p = new Person;
console.log(p.name);

call / apply / bind

function foo(p1, p2) {
  console.log(this.name); // Tate
  console.log(p1 + p2); // 3
}
var person = {
  name: 'Tate'
};
foo.call(person, 1, 2);
foo.apply(person, [1, 2]); // apply 和 call 类似,只是参数不同,立即执行
var bar = foo.bind(person, 1);
bar(2); // bind 绑定指针后并没有立即执行,参数按顺序注入,相当于 bind(person,1,2)

构造函数实例化本质

function Person() {
  this.name = 'Tate';
}
var p = new Person();

// new 操作符的操作实际是
var p = {}; // 申明一个空对象
p.__proto__ =  Person.prototype; // 将 __proto__ 指针指向 Person 的 prototype,即其原型对象
// Object.setPrototypeOf(p, Person.prototype);
Person.call(p); // 改变 Person 内部 this 指针,指向 p 对象

参考链接

  1. 彻底理解 js 中 this 的指向,不必硬背 By 追梦子
  2. this 关键字 By 阮一峰