Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JavaScript 里的 this 关键字 #10

Open
bouquetrender opened this issue May 9, 2018 · 0 comments
Open

JavaScript 里的 this 关键字 #10

bouquetrender opened this issue May 9, 2018 · 0 comments

Comments

@bouquetrender
Copy link
Owner

由 new 调用?绑定到新创建的对象。
由 call、apply 或 bind 调用?绑定到指定的对象。
由上下文对象调用?绑定到那个上下文对象。
默认:在严格模式下绑定到 undefined,否则绑定到全局对象。

刚入门 JavaScript 的时候被 this 指向弄懵的我算一个。由于其运行期绑定的特性,JavaScript 中的 this 含义要丰富得多,它可以是全局对象、当前对象或者任意对象,这完全取决于函数的调用方式。JavaScript 函数调用方式有以下几种:作为对象方法调用,作为函数调用,作为构造函数调用,使用 apply 或 call 调用。本文章根据所有不同调用方式列出 this 的含义。

全局上下文

在浏览器运行环境中,this指代全局对象,无论是否在严格模式下

window === this // true
const _ = 'val'
console.log(this._) // val

函数上下文

this指向取决于函数是如何调用的。直接调用的情况下,this指向全局。

function fn () {
  return this 
}
 
fn() === window // true

在对象中调用方法时,this指向该函数的对象。

const color = 'red'
const obj = {
  color: 'blue',
  result () {
    console.log(this.color) 
  }
}

obj.result() // 结果为blue

原型链与构造函数中的this。当一个函数被作为一个构造函数来使用(使用new关键字),它的this与即将被创建的新对象绑定。

const x = 1
const y = 1
 
function example (x, y) {
  this.x = x
  this.y = y
}
 
example.prototype.count = function () {
  return this.x + this.y
}
 
const a = new example(2, 2)
console.log(a.count()) // 4

call与apply

三种方法用于改变函数上下文,即改变函数运行时this的指向,举个例子

function info (name) {
  this.name = name
}
info.prototype.show = function () {
  console.log('my name is ' + this.name)
}
 
const myObj = new info('sakuya')
myObj.show() // my name is sakuya 
 
const anthorObj = { name: 'maho' }
myObj.show.call(anthorObj) // my name is maho  
myObj.show.apply(anthorObj) // my name is maho  
myObj.show.bind(anthorObj)() // my name is maho

call与apply区别在于传入的参数,第一个参数都是要改变上下文的对象。而call从第二个参数开始以参数列表的形式展现,apply则是把除了改变上下文对象的参数放在一个数组里面作为它的第二个参数。

fn.call(obj, arg1, arg2, arg3...);
fn.apply(obj, [arg1, arg2, arg3...]);

使用场景

数组,借助其他对象的方法实现目的

Math.max.apply(null, [14, 3, 77]) // 77
 
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
Array.prototype.push.apply(arr1, arr2); // [0, 1, 2, 3, 4, 5]
 
// 可利用es6扩展运算符(spread)代替
Math.max(...[14, 3, 77])
 
arr1.push(...arr2)
[...arr1, ...arr2]

数组,作为参数传入方法

function example(x, y, z){
  console.log(x,y,z)
}
example.apply(null, [1, 2, 3]) // 1 2 3
 
// 可利用es6扩展运算符(spread)代替
function example(x, y, z){
  console.log(x,y,z)
}
example(...[1, 2, 3]) // 1 2 3

也可利用call实现继承

function Superfn(){
     this.colors = ["red", "blue", "green"];
}
function Subfn(){
    //继承了Superfn
    Superfn.call(this);
}

bind

与call, apply 相同之处在于改变函数上下文
不同之处在与call, apply是调用,而bind会完全创建一个具有相同函数体和作用域的函数,称为绑定函数

window.color = 'red'
var o = { color: 'blue' }
function sayColor() {
  alert(this.color)
}
var objectSayColor = sayColor.bind(o)
objectSayColor() //blue

事件

当函数被用作事件处理函数时,它的this指向触发事件的元素。

箭头函数中的this

箭头函数里的this是引用上一级的this。以下是几个需要注意的地方

  • 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
  • 不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
  • 不可以使用arguments对象,该对象在函数体内不存在。如果需要可以用Rest参数代替。
  • 不可以使用yield命令,因此箭头函数不能用作Generator函数。

如果是普通函数,执行时this应该指向全局对象window,这时应该输出21。但是,箭头函数导致this总是指向函数定义生效时所在的对象(本例是{id: 42}),所以输出的是42。

const id = 21
function foo() {
  setTimeout(() => {
    console.log('id:', this.id)
  }, 100);
}
 
foo.call({ id: 42 }) 
// id: 42

封装回调函数。以下代码的init方法中,使用了箭头函数,这导致这个箭头函数里面的this,总是指向handler对象。否则,回调函数运行时,this.doSomething这一行会报错,因为此时this指向document对象。

var handler = {
  id: '123456',
  init: function() {
    document.addEventListener('click',
      event => this.doSomething(event.type), false);
  },
  doSomething: function(type) {
    console.log('Handling ' + type  + ' for ' + this.id);
  }
}

优先级

new绑定 > 显式绑定 > 隐式绑定

@bouquetrender bouquetrender changed the title JavaScript The this keyword JavaScript 里的 this 关键字 May 9, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant