JS中this指向绑定规则可以分为以下几种:
- 默认绑定
- 隐式绑定
- 显示绑定
- new绑定
1.默认绑定
当无法应用前面说的其它三种规则的时候,就会应用默认绑定,此时的this会绑定全局对象(注:在严格模式下this无法绑定全局对象而是绑定到underfind)
var a = 1
function fn1() {
console.log(this)
console.log(this.a)
}
function fn2() {
"use strict"
console.log(this)
console.log(this.a)
}
fn1()
fn2()
/*打印结果
Window
1
undefined
Cannot read property 'a' of undefined
*/
2.隐式绑定
当调用的位置含有执行上下文时,this会绑定这个上下文对象
function fn() {
console.log(this)
console.log(this.a)
}
var obj = {
a: 1,
fn: fn
}
obj.fn()
/*打印结果
{a: 1, fn: ƒ} //obj这个对象
1
*/
此外对象属性引用链中只有最顶层或者说最后一层会影响调用位置
function fn() {
console.log(this)
console.log(this.a)
}
var obj2 = {
a: 2,
fn: fn
}
var obj1 = {
a: 1,
obj2: obj2,
}
obj1.obj2.fn()
/*打印结果
{a: 2, fn: ƒ} //obj2这个对象
2
*/
隐式绑定有时也会带来隐式丢失的问题,最常见的一种就是被隐式绑定的函数丢失绑定对象,换句话说就是采用默认绑定,把this绑定到全局对象上
function fn() {
console.log(this)
console.log(this.a)
}
var obj = {
a: 1,
fn: fn
}
var a = 'global'
var b = obj.fn
b()
/*打印结果
Window
global
虽然b是obj.fn的一个引用,但是b()实际是调用了fn本身,所以此时的b函数是一个没有修饰的函数,即
采用了默认绑定
*/
此外参数的传递其实也是一种隐式的赋值,下面例子的结果与上述例子的结果是一样的
function fn() {
console.log(this)
console.log(this.a)
}
function Fn(f) {
f() //这里的f其实也是就是函数fn的一个引用
}
var obj = {
a: 1,
fn: fn
}
var a = 'global'
Fn(obj.fn)
/*打印结果
Window
global
*/
3.显式绑定
通过apply、call、bind方法来指定this绑定的对象(apply、call、bind的用法自行了解)
function fn() {
console.log(this)
console.log(this.a)
}
var obj = {
a: 1,
}
fn.call(obj)
/*打印结果
{a: 1} //obj这个对象
1
*/
其次显示绑定可以通过硬绑定这种变种的方式来解决隐式绑定丢失的问题
function fn() {
console.log(this)
console.log(this.a)
}
var obj = {
a: 1,
}
var b = function () {
fn.call(obj)
}
b()
b.call(window)
/*打印结果
{a: 1} //obj这个对象
1
{a: 1} //obj这个对象
1
首先我们创建了一个b函数并在内部强制将fn的this绑定到obj对象上,所以后面无论如何调用fn函数,
它的this都会绑定到obj上,根据打印结果可知,硬绑定后在对其this修改是无效的
*/
4.new绑定
JS中使用new来调用函数时,会进行以下操作:
1.创建一个空对象。(var obj = new Object())
2.将空对象的原型赋值给构造函数的原型。(Person.prototype = obj.proto)
3.执行构造函数的代码,为空对象添加属性(Person.call(obj)),也可以理解为将构造函数内部的this指针指向新建的空对象。
4.如果函数没有返回其他对象,那么 new 表达式中的函数调用会自动返回这个新对象。
function fn(a) {
this.a = a
}
var b = new fn(1)
console.log(b.a) // 1
/*
使用 new 来调用 fno(..) 时,我们会构造一个新对象并把它绑定到 foo(..) 调用中的 this上,
具体原因看上面new的过程做了什么
*/
总结(根据你不知道的js中的总结)
1.由 new 调用?绑定到新创建的对象
2.由 call 或者 apply(或者 bind )调用?绑定到指定对象
3.由上下文对象调用?绑定到那个上下文对象
4.默认:在严格模式下绑定到 undefined,否则绑定到全局对象