目录
this 是一个 关键字
是一个 使用在 作用域内的 关键字
=> 要么使用在全局
~> this 就是 Window
=> 要么使用在函数内部
~> this 表示的是该函数的 context (执行上下文)
// 0. 全局使用 this
console.log(this)
console.log(window)
console.log(window === this) // true
函数内使用 this 关键字 :
概念 : + **函数内的 this , 和函数的定义方式没有关系, 和函数在哪定义没有关系,
=> 只看函数怎么调用 (箭头函数除外) **
+ 几种调用方式, 决定不同的 this 指向 :
1. 普通调用(全局调用) :
=> 书写: 函数名( )
=> 该函数内的 this 指向 Window
// 1. 普通调用
function fn() {
console.log('我是全局 fn 函数')
console.log(this)
console.log('------fn 函数结束------')
}
// 标准的 普通调用
// fn 这个函数内的 this => Window
fn()
2. 对象调用 :
=> 书写 : 对象名.函数名( )
~> 对象名['函数名']( )
~> 数组[索引]( )
=> 书写: xxx.函数名( )
=> 该函数内的 this 指向 点 前面的内容
~> 也就是那个对象或者数组
// 2. 对象调用
var obj = {
name: '我是 obj 对象',
fn: function () {
console.log('obj 内的 fn 函数')
console.log(this) // Object
console.log('------fn 函数结束------')
}
}
// 标准的 对象调用
// 函数内的 this => obj
obj.fn()
// 同一个函数, 不同的调用方式, 决定了函数内的 this 指向不一样
function fn() {
console.log('fn 函数')
console.log(this)
console.log('------fn 函数结束------')
}
var obj = {
name: '我是 obj 函数',
// 把 fn 存储的函数地址, 赋值给了 obj 内的 f 成员
f: fn
}
// 从此以后, 全局 fn 变量和 obj 内的 f 成员调用的是一个函数
// 调用全局的 fn 函数, 调用方式: 普通调用
// fn() // this => Window
// 调用全局的 fn 函数, 调用方式: 对象调用
obj.f() // this => Object
3. 定时器处理函数 :
=> 书写 :
~> setTimeout(函数, 数字)
~> setInterval(函数, 时间)
=> 该函数内的 this 指向 Window
function fn() {
console.log('我是全局 fn 函数')
console.log(this) // this => Window
console.log('------fn 函数结束------')
}
// 3. 定时器处理函数
// 1000ms 以后执行的是 fn 函数
// 在这里把 fn 函数当做定时器处理函数来使用了
setTimeout(fn, 1000)
4. 事件处理函数 :
=> 书写 :
~> 事件源.on事件类型 = 事件处理函数
~> 事件源.addEventListener('事件类型', 事件处理函数)
=> 该函数内的 this 指向 事件源 (谁身上的事件)
function fn() {
console.log('我是全局 fn 函数')
console.log(this) // this => div
console.log('------fn 函数结束------')
}
// 4. 事件处理函数
var box = document.querySelector('div')
// 当你点击 box 元素的时候, 执行 fn 函数
// 此时, 把 fn 函数当做事件处理函数使用了
box.onclick = fn
5. 自执行函数 :
=> (function ( ) { })( )
~function ( ) { }( )
!function ( ) { }( )
=> 该函数内的 this 指向 window
// 5. 自执行函数
(function () {
console.log(this) // Window
})()
6. 箭头函数 :
=> this ~> 上下文 (外部函数的 this)
7. 构造函数 :
书写 :
=> new 函数名( )
=> this ~> 当前实例 (构造函数自动创造出来的那个对象)
构造函数内的 this 指向当前实例
强行改变 this 指向 :
+ 不管你本身指向什么位置, 我让你指向哪, 你就得指向哪
function fn(a, b) {
console.group('fn 函数内的 打印')
console.log('this : ', this)
console.log('a : ', a)
console.log('b : ', b)
console.groupEnd()
}
// 0. 普通调用
// 因为是 普通调用
// this => window
// a => 10
// b => 20
fn(10, 20)
1. call( )
+ 语法: 跟随在函数名后面调用
=> 函数名.call( )
=> 对象名.函数名.call( )
+ 意义: 修改 函数内 的 this 指向
+ 参数:
=> 第一个参数 : 要修改的函数内的 this 指向
=> 第二个参数开始 : 依次给函数内每一个形参传递实参
+ 特点: 立即调用函数
+ 用处:
=> 在立即执行的函数时才使用
=> 事件处理函数, 和 定时器处理函数, 一般不会使用这个方法
function fn(a, b) {
console.group('fn 函数内的 打印')
console.log('this : ', this)
console.log('a : ', a)
console.log('b : ', b)
console.groupEnd()
}
var obj = {
name: '我是 obj 对象'
}
// 因为是 利用 call 调用
// obj 就是 fn 函数内的 this 指向, fn 这个函数内的 this 就是 obj
// 100 就是给 fn 函数的第一个实参, 赋值给了形参 a
// 200 就是给 fn 函数的第二个实参, 赋值给了形参 b
fn.call(obj, 100, 200) // a : 100 b : 200
function fn(a, b) {
console.group('fn 函数内的 打印')
console.log('this : ', this)
console.log('a : ', a) // a: 1000
console.log('b : ', b) // b: 2000
console.groupEnd()
}
var arr = [ 100, 200, 300, 400, 500 ]
// 因为是 利用 call 调用 , 并且传递的第一个参数是 arr
// 就是在立即调用 fn 函数的同时, 把 fn 函数内的 this 指向了 arr
// 从第二个参数开始, 1000 赋值给了第一个形参 a
// 2000 赋值给了 第二个形参 b
fn.call(arr, 1000, 2000) // a = 1000 b = 2000
2. apply( )
+ 语法: 跟随在函数名后面调用
=> 函数名.apply( )
=> 对象名.函数名.apply( )
+ 意义: 修改 函数内 的 this 指向
+ 参数:
=> 第一个参数: 要修改的函数内的 this 指向
=> 第二个参数: 是一个数组或者伪数组都行
-> 数组或者伪数组内的每一项依次给函数传递实参
+ 特点 : 立即调用函数
+ 用处:
=> 在立即执行的函数时才使用
=> 事件处理函数, 和 定时器处理函数, 一般不会使用这个方法
+ 特殊作用: 改变给函数传递参数的方式
function fn(a, b) {
console.group('fn 函数内的 打印')
console.log('this : ', this)
console.log('a : ', a) // a: 100
console.log('b : ', b) // b: 200
console.groupEnd()
}
var obj = {
name: '我是 obj 对象'
}
// 因为是 利用 apply 调用函数 fn
// 所以 把函数内部的 this 改变成为 obj
// obj 就是 fn 函数内的 this 指向
// 第二个参数传递了一个数组
// 数组中的 [0] 是给 fn 函数的第一个实参, 赋值给了形参 a
// 数组中的 [1] 是给 fn 函数的第二个实参, 赋值给了形参 b
fn.apply(obj, [100, 200])
apply 的 特殊作用 :
var arr = [10, 20, 18, 32, -10, 21, 19]
// 我想求 arr 内的最大值
// 利用 apply 方法来改变 给函数传递参数的方式
// apply 第二个参数是一个 数组 或者 伪数组, 里面的内容依次给函数的实参
// null 就是 Math.max 函数内的 this 指向
// arr[0] 就是 Math.max 的第一个实参
// arr[1] 就是 Math.max 的第二个实参
// ...
var res = Math.max.apply(null, arr)
console.log(res) // 32
3. bind( )
+ 语法: 跟随在函数名后面调用
=> 函数名.bind( )
=> 对象名.函数名.bind( )
+ 意义: 修改 函数内 的 this 指向
+ 参数:
=> 第一个参数: 要修改的函数内的 this 指向
=> 第二个参数开始: 依次给函数内每一个形参传递实参
+ 特点:
=> 不会立即调用函数 , 而是返回一个新的函数给你
=> 一个被改变了 this 指向的新函数
+ 用处:
=> 在非立即调用的函数时使用
=> 因为他不会立即调用函数, 而是返回一个改变好 this 指向的函数
+ 特殊作用 : 改变一些不会立即执行的函数内的 this 指向
function fn(a, b) {
console.group('fn 函数内的 打印')
console.log('this : ', this)
console.log('a : ', a)
console.log('b : ', b)
console.groupEnd()
}
var obj = {
name: '我是 obj 对象'
}
// 利用 bind 调用了 fn 函数, 把函数内的 this 改变成为了 obj
// obj 就是 fn 函数内的 this 指向
// 100 赋值给形参 a
// 200 赋值给形参 b
// 注意: 因为是 bind, 不会把 fn 函数执行, 而是把 fn 函数复制了一份, 把内部的 this 锁定为 obj
// res 接受的就是 bind 方法复制出来的 fn 函数, 和 fn 函数一模一样, 但是 res 函数内的 this 是 obj
var res = fn.bind(obj, 100, 200)
console.log('fn : ', fn)
console.log('res : ', res)
res()
bind 的 特殊作用 :
需求: 想把定时器处理函数内的 this 指向 obj
function fn(a, b) {
console.group('fn 函数内的 打印')
console.log('this : ', this)
console.log('a : ', a)
console.log('b : ', b)
console.groupEnd()
}
// 1000ms 以后执行 fn 函数
// 因为 fn 函数被当做了 定时器处理函数 使用, 所以 fn 内的 this 指向 window
setTimeout(fn, 1000)
方案 1 : 利用 call / apply
function fn(a, b) {
console.group('fn 函数内的 打印')
console.log('this : ', this)
console.log('a : ', a)
console.log('b : ', b)
console.groupEnd()
}
var obj = {
name: '我是 obj 对象'
}
// 方案1: 利用 call/apply
// 因为 call 和 apply 会立即调用函数, 当你设置这个定时器的时候, 已经把 fn 函数调用了
// 等到 1000ms 以后, 就没有函数执行了
setTimeout(fn.call(obj, 100, 200), 1000)
方案2: 利用 bind
function fn(a, b) {
console.group('fn 函数内的 打印')
console.log('this : ', this)
console.log('a : ', a)
console.log('b : ', b)
console.groupEnd()
}
var obj = {
name: '我是 obj 对象'
}
// 方案2: 利用 bind
// 因为 bind 不会立即调用函数, 而是返回一个一模一样的函数, 只是被锁定了 this
// 你调用 res 和 调用 fn 是一模一样的代码, 只是 this 不一样
var res = fn.bind(obj, 1000, 2000)
// 把 res 当做定时器处理函数, 在 1000ms 后执行
// 1000ms 以后执行的是一个 和 fn 函数一模一样的函数, 只是 this 指向了 obj
setTimeout(res, 1000)