关于this

this是在运行时进行绑定的,并不是在编写时绑定,它的上下文取决于函数调用时的各种条件。this的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式

当一个函数被调用时,会创建一个活动记录(有时候又称为执行上下文)。这个记录会包含函数在哪里被调用(调用栈)、函数的调用方法、传入的参数等信息。this就是记录的其中一个属性,会在函数执行的过程中用到。

默认绑定

独立函数调用,无法应用其他规则时的默认规则。

function foo() {
    var a = 'one';
    console.log(this.a)
}
var a = 'day';
foo(); // day

严格模式下上面的代码会绑定到undefined:

function foo() {
    'use strict'
    var a = 'one';
    console.log(this.a)
}
var a = 'day';
foo(); // Uncaught TypeError: Cannot read property 'a' of undefined

上面的foo()是直接使用不带任何修饰的函数引用进行调用的,因此只能使用默认绑定,无法应用其他规则。

隐式绑定

看是否有上下文对象。

function foo() {
    console.log(this.a);
}
var obj = {
    a: 'oneday',
    foo: foo
}
obj.foo(); // oneday

此时foo()是作为引用属性添加到obj中的。会使用obj上下文来引用函数。对象属性引用链中只有最顶层或者说最后一层会影响调用位置。

function foo() {
    console.log(this.a);
}
var obj2 = {
    a: 'one',
    foo: foo
}
var obj1 = {
    a: 'day',
    obj2: obj2
}
obj1.obj2.foo(); // one

但是有的时候被隐式绑定的函数会丢失绑定对象,然后就会应用默认绑定规则。

function foo() {
    console.log(this.a);
}
var obj = {
    a: 'one',
    foo: foo
}
var bar = obj.foo;
var a = 'day';
bar(); // day

显式绑定

使用call(...)apply(...)

function foo() {
    console.log(this.a);
}
var obj = {
    a: 'one'
}
foo.call(obj); // one

然后this强制绑定在了obj上面。

硬绑定

function foo() {
    console.log(this.a);
}
var obj = {
    a: 'one'
}
var bar = function() {
    foo.call(obj);
}
bar(); // one
bar.call(window); // one

就不能改变foo的this指向了。ES5提供了内置方法Functon.prototype.bind方法,会返回一个硬绑定的新函数,然后就不能改变this指向了。

function foo() {
    console.log(this.a);
}
var obj = {
    a: 'one'
}
var bar = foo.bind(obj)
bar() // one
bar.call(window) // one

new绑定

在JavaScript中,构造函数只是一些使用new操作符时被调用的函数。

使用new来调用函数,或者说发生构造函数调用时,会自动执行下面的操作:

  • 创建一个新对象
  • 新对象会连接原型链
  • 新对象会绑定this
  • 返回该对象
f = new Object()
f.__proto__ = F.prototype
F.call(f)
return f

四个绑定的优先级:

new绑定 > call、apply显式绑定 > 隐式绑定 > 默认绑定

箭头函数

this绑定了外层(函数或全局)作用域

function foo() {
    setTimeout(() => {
        console.log(this.a) // 这里的this的是foo的
    }, 100)
}

var obj = {
    a: 'oneday'
}

foo.call(obj) // oneday

还有一个粗暴的方法

function foo() {
    var a = 'one';
    console.log(this.a)
}
var a = 'day';
foo(); // day
// 等价于
foo.call(window)
// 严格模式相当于
foo.call(undefined)
function foo() {
    console.log(this.a);
}
var obj = {
    a: 'oneday',
    foo: foo
}
obj.foo(); // oneday
// 等价于
foo.call(obj)
function foo() {
    console.log(this.a);
}
var obj2 = {
    a: 'one',
    foo: foo
}
var obj1 = {
    a: 'day',
    obj2: obj2
}
obj1.obj2.foo(); // one
// 等价于
foo.call(obj1.obj2)
function foo() {
    console.log(this.a);
}
var obj = {
    a: 'one',
    foo: foo
}
var bar = obj.foo;
var a = 'day';
bar(); // day
// 等价于
bar.call(window)

.前面是什么,就是call什么...

results matching ""

    No results matching ""