JavaScript 中 this 对象是在运行时基于函数的执行环境绑定的, 在全局函数中, this 等于 Windows, 而当函数被作为某个对象的方法调用时, this 等于那个对象.
但在实际中, 代码环境复杂, this 的指向并非那么直接判断出来. 下面来做一下总结.
1, 全局执行环境下的普通函数
- function f1 () {
- console.log(this)
- }
- function f2 () {
- 'use strict'
- console.log(this)
- }
- f1() // Windows
- f2() // undefined
分为严格模式和非严格模式. 非严格模式下等于 Windows, 严格模式下为 undefined.
2, 事件对象中的 this
this 指的是事件对象本身, 是指 event.target
- <!DOCTYPE html>
- <HTML lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <meta http-equiv="X-UA-Compatible" content="ie=edge">
- <title>
- Document
- </title>
- </head>
- <body>
- <div id="div1">
- 我是一个 div
- </div>
- <script>
- Windows.id = 'window'document.getElementById('div1').onclick = function() {
- alert(this.id) // 输出 div1
- }
- </script>
- </body>
- </HTML>
3, 对象中的方法引用
- const foo = {
- bar: 10,
- fn: function() {
- console.log(this)
- console.log(this.bar)
- }
- }
- foo.fn() // this 指的是 foo
- var fn1 = foo.fn
- fn1() // this 指的是 Windows
4, 构造函数中的 this
- // this 指 instance
- function Foo() {
- this.bar = "ceshi"
- }
- const instance = new Foo()
- console.log(instance.bar)
- // this 指的是 {}
- function Foo(){
- this.user = "ceshi"
- const o = {}
- return o
- }
- const instance = new Foo()
- console.log(instance.user)
这里的 this 之所以不同是由构造返回值是否是对象导致的
5, 丢失的 this
- <!DOCTYPE HTML>
- <HTML lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <meta http-equiv="X-UA-Compatible" content="ie=edge">
- <title>
- Document
- </title>
- </head>
- <body>
- <div id="div1">
- 我是一个 div
- </div>
- <script>
- let getId = document.getElementById console.log(getId('div1')) // 报错, 报错这是因为 document.getElementById 方法内的 this 指向 Windows 导致的
- // 修复
- document.getElementById = (function(func) {
- return function() {
- return func.apply(document, arguments)
- }
- })(document.getElementById) let getId = document.getElementById console.log(getId('div1'))
- </script>
- </body>
- </HTML>
6, 借助 bind,Object.prototype.call 和 Object.prototype.apply 改变 this 的指向
Object.prototype.call 和 Object.prototype.apply 的是后者参数为数组, 前者为多个参数.
用代码来总结:
- const target = {
- }
- fn.call(target, 'arg1', 'arg2')
相当于:
- const target = {
- }
- fn.apply(target, ['arg1', 'arg2'])
相当于:
- const target = {
- }
- fn.bind(target, 'arg1', 'arg2')()
借助 call 改变
- const foo = {
- name: 'ceshi',
- logName: function() {
- console.log(this.name)
- }
- }
- const bar = {
- name: 'mike'
- }
- console.log(foo.logName.call(bar)) // mike
7, 其他一些复杂的场景
- const foo = {
- fn: function () {
- setTimeout(function () {
- console.log(this)
- })
- }
- }
- foo.fn() // this===Windows
let,const 不会挂在 Windows 上面, 而 var 可以
- const a = 999
- let aa = 1000
- var b =1001
- function too(){
- console.log(this.a)
- console.log(this.aa)
- console.log(this.b)
- }
- too()
对象嵌套中的 this
- const person = {
- name: 'ceshi',
- brother: {
- name: 'zhen',
- fn: function() {
- return this.name
- }
- }
- }
- console.log(person.brother.fn()) // zhen
更复杂的情景
- const o1 = {
- text: 'o1',
- fn: function () {
- return this.text
- }
- }
- const o2 = {
- text: 'o2',
- fn: function () {
- return o1.fn()
- }
- }
- const o3 = {
- text: 'o3',
- fn: function () {
- var fn = o1.fn
- return fn()
- }
- }
- console.log(o1.fn()) // o1
- console.log(o2.fn()) // o1
- console.log(o3.fn()) // undefined
箭头函数的 this 提前绑定好
- const foo = {
- fn: function () {
- setTimeout(() => {
- console.log(this)
- })
- }
- }
- console.log(foo.fn()) // {fn: ƒ}
8, 通过 call,apply,bind 绑定的情况称为显式绑定; 根据调用关系确定的 this 指向称为隐式绑定. 那么哪一个优先级更高呢?
- function foo (a) {
- console.log(this.a)
- }
- const obj1 = {
- a: 1,
- foo: foo
- }
- const obj2 = {
- a: 2,
- foo: foo
- }
- obj1.foo.call(obj2) // 2
- obj2.foo.call(obj1) // 1
显式绑定的优先级高于隐式绑定.
来源: http://www.bubuko.com/infodetail-3438583.html