this
作为js中的常用引用,区别与词法作用域,有自己一套的规则
this的绑定规则
函数在执行过程中的调用位置决定了this的绑定对象,因此需要确定调用的位置,才能准确判断this绑定的对象是谁。
-
默认绑定
当函数独立调用的时候默认绑定的this 指向为全局对象,当在函数内部使用严格模式
use strict
时,this为undefine
。function foo() { console.log(this.a) } function bar() { 'use strict'; console.log(this.a) } const a = 1 foo() // -> 1 注意:在node环境中为 undefined bar() // -> TypeError: this is undefined
-
在node环境中
this
的 在默认绑定情况下 为Object [global]
, 无法向上查询到在全局下赋值的属性。// node 环境中 function foo() { console.log(this.a) } const a = 1 foo() // -> undefined this.a = 1 console.log(this.a) // -> 1
-
隐式绑定
-
通过将函数引用进一个对象的属性,通过对象调用函数的形式实现
function foo() { console.log(this.a) } const obj = { a: 1, foo: foo } const a = 'global a' obj.foo() // -> 1 // 可能会存在this 丢失,转而进行默认绑定(同默认绑定) // 1. 当进行再次引用的时候 var bar = obj.foo // 定义bar 指向foo函数 bar() // -> global a // 2. 当将函数作为参数传递的时候 setTimeout(obj.foo, 1000) // -> global a
-
-
显示绑定
-
通过
apply, call , bind
进行显示的绑定this
对象function foo(){ console.log(this.a) } const obj = { a : 1 } // foo.call(obj, 可变参数) foo.call(obj) // -> 1 // foo.apply(obj, 数组) foo.apply(obj) // => 1 const bar = foo.bind(obj) bar() // 1
-
-
new绑定
-
JavaScript 中构造函数知识一些使用
new
操作符时被调用的函数,并不属于某个类,也不会实例化一个类。new
调用某个函数的时候做了以下事情:- 创建一个全新的对象
- 这个新的对象会被执行
[[Proptype]]
连接 - 这个新的对象会绑定到函数调用的
this
- 如果该函数没有返回对象,那么new 表达式中的函数调用会自动返回这个新的对象
function foo(a) { this.a = a } var bar = foo(1) console.log(bar.a) // -> 1
-
this绑定中的优先级
- 函数中如果存在
new
绑定,如果是的话,this
绑定的就是新创建的对象。 - 函数中如果存在
call, apply,bind
的绑定,this
绑定的是指定的对象。 - 函数中如果存在某个对象中的引用,并被该对象调用(隐式绑定),this绑定的是那个对象。
- 如果以上都不是的话,则使用默认绑定,如果在严格模式下,则绑定到
undefined
- 需要注意的是,在node环境中,默认绑定总是不尽人意的。
特殊场景下的this
-
当使用显示绑定的时候,如果传入的绑定对象为
null
或者undefined
, 那么函数中的this
会作为默认绑定指向全局foo() { console.log(this.a) } const obj = { a:1 } const a = 'global a' foo.call(null) // -> global a
-
当使用
new
包裹 显示绑定的时候,显示绑定的对象会失效, 这时候的this
会绑定到新创建的对象上,一般用这种写法来:- 创建柯里化函数。
- 展开一个数组,当参数传入函数。
function foo(p1, p2) { this.a = p1 + p2 } var obj = { a : 'a' } // 函数的柯里化 //const bar = foo.bind(obj, 'p1') const bar = foo.bind(null, 'p1') const baz = new bar('p2') // new 后 上一行代码中的obj 会被新的baz上下文所替代,所以可以直接写null console.log(baz.a) // -> 'p1p2' // 展开数组 foo.apply(null, ['p1', 'p2'])
函数的柯里化就是通过
bind
预先设置一些参数,然后在通过函数调用传递另外一些参数,这里模拟一下函数的原理:function curry(fn) { const outArgs = Array.prototype.slice.call(arguments, 1) return function() { const innerArgs = Array.prototype.slice.call(arguments) const finalArgs = outArgs.concat(innerArgs) return fn.apply(null, finalArgs) } }
当使用
fn.apply(null, args)
的时候,因为null
的存在会是的函数中的this
指向全局变量,可能会出现不可估计的后果(比如对全局进行操作修改之类的)。这个时候建议 使用空对象替换null
,因此上面的代码修改如下:
function foo(p1, p2) {
console.log('p1:' + p1 + '; p2:' + p2)
}
// 创建空对象 同{} 相比, 不包含Object.prototype
const ø = Object.create(null)
// 函数的柯里化
const bar = foo.bind(ø, 'p1')
bar('p2')
// 展开数组
foo.apply(ø, ['p1', 'p2'])
当然,也可以重写
Prototype
中的bind
方法进行定制this
, 当使用的是全局或者undefined的时候,可以让this
指向传递进来的对象-
当使用箭头函数的时候,不会遵循上面的使用规则,而是根据 词法作用域来决定this, 准确的说法是 箭头函数会继承外层函数调用的
this
绑定function foo() { setTimeout(()=> { console.log(this.a) // 这里的this是foo作用域下的this }, 1000) // => 等同于 const self = this setTimeout(function() { console.log(this.a) }, 1000) } var obj = { a : 1 } foo.call(obj) // 1
以上是我对JavaScript中的this用法的理解与总结,希望能帮到大家,如果能够帮到您,希望不吝点个赞哦;如果哪里写的不对或者缺失,还望告知~~