this 学习笔记及拓展知识

119 阅读2分钟

一、this 学习笔记

this 指在调用的时候,属性或方法“当前”所在的对象;或者说点之前的对象

const app = {
  init() {
		this.$btn = document.querySelector('button')
    this.bind()
  },
  bind() {
    this.$btn.onclick = function() {
      console.log(this)
      this.getData()    //这样写对吗,如果不对该如何修改?
    }
  },
  getData() {
    console.log('get data...')
  }
}
app.init()

2. 如何修改?有哪些写法?

  • 第一种修改方法:使用 self
const app = {
  init() {
		this.$btn = document.querySelector('button')
    this.bind()
  },
  bind() {
    let self = this
    this.$btn.onclick = function() {
      console.log(this)  // 这个this 还是 btn 对象
      self.getData()    //self 代表外面的this,也就是app
    }
  },
  getData() {
    console.log('get data...')
  }
}
app.init()
  • 第二种修改方法:使用箭头函数
const app = {
  init() {
		this.$btn = document.querySelector('button')
    this.bind()
  },
  bind() {
    this.$btn.onclick = () => {
      console.log(this)  // 在确定this直属的函数时,不考虑箭头函数
      this.getData()     // 所以当前this直属的函数是bind
    }
  },
  getData() {
    console.log('get data...')
  }
}
app.init()

3. 通过一些例子加深对 this 的理解

  • 例子1: 调用对象中的方法,方法本质是函数
window.name = '网页'
let people = {
  name: '掘金',
  sayName() {
    console.log(this.name)
  }
}
let sayAgain = people.sayName   // 地址;等价于函数表达式;全局对象
function sayName(){
  console.log(this.name)
}
 
 
people.sayName()
sayAgain()
sayName()
  • 例子2:数组
let arr = []
for(let i=0; i<3; i++){
   arr[i] = function() { console.log(this) }
}
 
arr[0]()   // 所属的对象是数组 arr,即 this
let fn = arr[0]  // 等价于 let fn = function() { console.log(this) }
fn()
  • 例子3:函数嵌套函数
let people = {
  name: '掘金',
  sayName() {
    setTimeout(function(){
      console.log(this.name)  // this 指向 setTimeout
    }, 0)
  }
}
people.sayName()
let people = {
  name: '掘金',
  sayName() {
    setTimeout(() => {
      console.log(this.name)  // this 指向 people,这也是定时器一般用箭头函数的原因。
    }, 0)
  }
}
people.sayName()
  • 例子4:call/apply/bind
let obj = {
  fn(a, b) {
    console.log(this)
  }
}
obj.fn(1, 2)   // this 是 obj
//等价于
obj.fn.call(obj, 1, 2)        
obj.fn.apply(obj, [1, 2])
obj.fn.bind(obj,1, 2)  // bind 方法返回一个新函数,this 指向 bind() 的第一个参数,其余参数作为新函数的参数。
  • 例子5:DOM 事件处理函数
let app = {
  container: document.querySelector('body'),
  init: function(){
    //点击的时候会执行 sayHello,sayHello 里面的 this 代表 body 对象
    this.container.addEventListener('click', this.sayHello)                  
 
    // 点击的时候会执行 sayHello,sayHello 里面的 this 代表 app 对象
    // bind 方法第一个参数的 this 指向的就是 app
    this.container.addEventListener('click', this.sayHello.bind(this)) 
  }, 
  sayHello: function(){
    console.log(this)
  }
}
app.init()
  • 例子6:原型链与构造函数
function Wife(name) {
  this.name = name
}  // 构造函数,它自身在一个 prototype 属性
 
Wife.prototype.showSkill = function() {
  console.log('我是' + this.name + ', 我的技能是唱歌、跳舞、打游戏')
}  // 在构造函数的原型上添加新属性

let wife = new Wife('新桓结衣')  // 构造函数是实例的原型,this 指向实例
wife.showSkill() // 会到构造函数的原型中寻找(原型的原型)
  • 例子7:严格模式
function f1(){
  return this;
}
//在浏览器中:
f1() === window;   //在浏览器中,全局对象是window

//在Node中:
f1() === globalThis;
function f2(){
  "use strict"; // 这里是严格模式
  return this;
}

f2() === undefined; // true

二、拓展知识

1. 方法的定义

从ECMAScript 2015开始,在对象初始器中引入了一种更简短定义方法的语法,这是一种把方法名直接赋给函数的简写方式。

  • ECMAScript 2015 之前方法的定义
var obj = {
  foo: function() {
    /* code */
  },
  bar: function() {
    /* code */
  }
};
  • ECMAScript 2015 之后方法的定义(简写)
var obj = {
  foo() {
    /* code */
  },
  bar() {
    /* code */
  }
};

2. 对象复习:使用变量作属性名及注意事项

let p = 'name'
let obj = { p: "frank"}  // 属性名为 "p1"
let obj = { [p]: "frank"}  // 属性名为 "name"

注意事项:obj.p 等价于 obj['p'],不等价于 obj[p],因为 obj.p 中的 p 是字符串,而不是变量。

参考文章