js中this的用法

版权声明:本文为个人知识整理,欢迎指正、交流、转载。 https://blog.csdn.net/u014711094/article/details/80422184

nodejs和browser中this的比较

nodejs的全局对象是global,一个js文件是一个模块(module),模块内部形成模块作用域(module scope),定义的变量只能在本模块使用。可以使用global对象或module.exports在多个模块间分享变量。

// 模块内部this默认指向module.exports
this === module.exports     // true
this === exports    // true
this    // {}

// x.js导出
this.a = 1
exports.b = 2
module.exports.c = 3

// y.js
const {a, b, c} = require('./x.js')

browser环境的全局对象是window,相当于nodejs的global。由于不存在模块作用域,会导致this的值在nodejs和browser中不同。

// 全局环境(global context)下this默认指向window
this === window     // true

变量声明

var a = 1
let b = 2
const c = 3
d = 4

// nodejs中,a b c都是模块内部变量
global.a    // undefined
global.b    // undefined
global.c    // undefined
global.d    // 4, d没有使用关键字声明,自动成为global的属性

// browser中,未声明的变量和使用var声明的变量,自动称为window的属性,属于遗留(legacy)问题
this.a  // 1
this.d  // 4

// es6引入let和const,声明的变量不再自动成为window的属性
this.b  // undefined
this.c  // undefined

nodejs和browser中都不允许直接对this赋值。

this = 1    // Invalid left-hand side in assignment

函数上下文(function context)中this的用法

函数上下文中,nodejs和browser中,this的指向的原理基本相同,以下在nodejs中测试。

  • this没有明确的指向时默认指向全局对象
function foo() {
  return this
}

// 非严格模式下,未设置this的值,默认返回全局对象
foo() === global    // true in node
foo() === window    // true in browser

function foo() {
  'use strict'
  return this
}

// 严格模式下,不允许this指向全局对象
foo()   // undefined
  • 箭头函数(arrow function)
    箭头函数中的this指向会参考函数定义时的上下文(context),形成闭包(closure)。
this.a = 1
let foo = (b) => this.a + b

foo(2)      // 3
foo.call({a: 2}, 2)     // 3,call并没有改变this的指向

let f1 = foo.bind({a: 3})
f1(2)       // 3,bind也没有改变this的指向

this.a = 2
foo()       // 4,跟随改变
  • 对象的方法
    函数作为对象的方法调用时,this指向调用该方法的对象。
let obj = {
  x: 1,
  f: getX,
  y: {
    x: 2,
    g: getX
  }
}

// getX可以在obj内部定义,也可以在外部定义
function getX() {
  return this.x
}

obj.f()     // 1
getX.call(obj)  // 1
obj.y.g()   // 2
getX.call(obj.y)    // 2
  • 构造函数

new关键字默认返回function中的this对象

function Foo() {
  this.a = 1
}

// new返回{a: 1}
let f = new Foo()

如果构造函数返回一个对象(object),则new返回该对象,不返回已定义的this对象

function Foo() {
  this.a = 1
  return {b: 2}    // 返回{b: 2}
  return [1, 2]    // 返回[1, 2]
  return new Number(2)    // 返回数值对象[Number 2]

  return null    // 返回{a: 1}
  return undefined    // 返回{a: 1}
  return    // 返回{a: 1}
  return 1    // 返回{a: 1}
  return 'abc'    // 返回{a: 1}
}
  • 对象的原型上(on the object’s prototype chain)

对象可以调用prototype上的方法,this指向当前对象,很像是对象自身的方法,这是js原型链继承的特性。

function Foo(a, b) {
  this.a = a
  this.b = b
}

Foo.prototype.add = function () {
  console.log(this.a + this.b)
}

Foo.prototype.delayAdd = function () {
  setTimeout(this.add, 500)
}

let foo = new Foo(1, 2)
foo.add()       // 3,是预期结果,this会绑定foo

增加一个方法

Foo.prototype.delayAdd = function () {
  setTimeout(this.add, 500)
}

let foo = new Foo(1, 2)
foo.delayAdd()  // undefined,非预期结果

// 分析:delayAdd相当于下面的写法
Foo.prototype.delayAdd = function () {
  // this指向foo
  setTimeout(function () {
    // 注意:这里nodejs指向Timeout对象,是setTimeout()的返回值
    // browse里this的指向window
    return this.a + this.b
  }, 500)
}

// 使用bind修改回调函数中this的指向
Foo.prototype.delayAdd = function () {
  setTimeout(this.add.bind(this), 500)
}

foo.delayAdd()  // 3,正确

实例分析

主要考虑对象方法、普通函数、箭头函数中this的指向。通过对象方法调用和赋值调用可能结果不同。

let o = {
  foo: () => this,
  bar: function () {
    return this
  },
  baz: function () {
    return () => this
  },
  qux: () => {
    return () => this
  },
  one: function () {
    return function () {
      return this
    }
  },
  two: () => {
    return function () {
      return this
    }
  }
}

foo是使用箭头函数定义的对象方法,上下文中this指向module.exports,形成闭包。

o.foo() === module.exports  // true
o.qux() === module.exports  // true

// 只有箭头函数嵌套
let foo = () => {
  return () => {
    return () => this
  }
}
foo()()() === exports   // true

bar是使用普通函数定义的对象方法,内部this指向当前对象o。箭头函数定义时形成闭包,this指向上下文的this。

o.bar() === o       // true
o.baz()() === o     // true

one和two中this没有直接位于对象方法中,也没有其他方法改变this的指向,指向global。

o.one()() === global    // true
o.two()() === global    // true

如果是先赋值再调用,结果可能不同,主要考虑上下文的改变。

let b = o.baz
b()() === global    // true
// 相当于
let b = function(){
  return () => this
}

参考:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this

猜你喜欢

转载自blog.csdn.net/u014711094/article/details/80422184