关于this

最近在拜读《你不知道的js》,而此篇是对于《你不知道的js》中this部分的笔记整理,但愿能有效的梳理,而且巩固关于this的知识点bash

1、this是一种怎样的机制

一、this是在运行时进行绑定的,并不是在编写时绑定,它的上下文取决于函数调用时的各类条件,它指向什么彻底取决于函数的调用位置;ide

二、this的绑定与函数申明位置无关系,只取决于函数的调用方式;函数

三、当函数被调用时,会建立一个活动记录,即执行上下文。这包括函数在哪被调用、函数调用方式、传入的参数信息等。this则为其记录的一个属性,会在函数执行的过程当中用到;ui

2、this的做用

首先看一段代码:this

function identify() {
    return this.name.toUpperCase();
}
function speak() {
    var greeting = "Hello, I'm " + identify.call(this);
    console.log(greeting);
}
var me = {
    name: "Mike"
};
var you = {
  name: "Jenny"  
};
identify.call(me); // Mike
identify.call(you); // Jenny

speak.call(me); // Hello, I'm Mike speak.call(you); // Hello, I'm Jenny
复制代码

这段代码可在不一样的上下文对象中重复使用identify(),speak();spa

若不使用this,可将代码变换以下:code

function identify(con) {
    return con.name.toUpperCase();
}
function speak(con) {
    var greeting = "Hello, I'm " + identify.call(con);
    console.log(greeting);
}
var me = {
    name: "Mike"
};
var you = {
  name: "Jenny"  
};
identify(me); // Mike
speak(you); // Hello, I'm Jenny 复制代码

this能够以一种更优雅的方式来传递上下文对象,使代码变得简洁且易于复用对象

3、对于this的误解

误解1、this指向函数自身(仅从字面上理解this的含义)

先来看一段代码:作用域

function foo(num) {
    console.log("foo: " + num);
    // 记录foo被调用的次数
    this.count++;
}
foo.count = 0;
var i;
for(i = 0; i < 0; i++) {
    if(i > 5) {
        foo(i);
    }
}
// foo(6);
// foo(7);
// foo(8);
// foo(9);

// foo被调用了几回?
console.log(foo.count); // 0
复制代码

为何此处的foo.count值为0呢?string

执行foo.count时,的确向函数对象foo添加一个属性count,但函数内部代码的this并不是指向foo,而this.count是建立了一个全局变量,因此this指向了window

此时this.count的值为NaN

若要实现foo.count = 4 ,则将代码变化以下:

方法1、

function foo(num) {
    console.log("foo: " + num);
    // 记录foo被调用的次数
    data.count++;
}
var data = {
    count: 0
};
var i;
for(i = 0; i < 0; i++) {
    if(i > 5) {
        foo(i);
    }
}
// foo(6);
// foo(7);
// foo(8);
// foo(9);

// foo被调用了几回?
console.log(data.count); // 4
复制代码

此写法虽然达到了理想的状态,但却忽略了this

方法2、

function foo(num) {
    console.log("foo: " + num);
    // 记录foo被调用的次数
    foo.count++;
}
foo.count = 0;
var i;
for(i = 0; i < 0; i++) {
    if(i > 5) {
        foo(i);
    }
}
// foo(6);
// foo(7);
// foo(8);
// foo(9);

// foo被调用了几回?
console.log(data.count); // 4
复制代码

这种写法一样回避了this的问题

方法3、

function foo(num) {
    console.log("foo: " + num);
    // 记录foo被调用的次数
    this.count++;
}
foo.count = 0;
var i;
for(i = 0; i < 0; i++) {
    if(i > 5) {
        // 使用call(...)能够确保this指向函数对象foo自己
        foo.call(foo, i);
    }
}
// foo(6);
// foo(7);
// foo(8);
// foo(9);

// foo被调用了几回?
console.log(data.count); // 4
复制代码

此方法使用call,改变了上下文对象,强制将this指向foo函数对象

总结:经过以上例子说明,仅仅从字面意思来解释this是不许确的,而是要经过关注执行上下文,以及函数的调用位置来判断this的指向

误解2、this指向函数的做用域

这个问题在某些状况下是正确的,但也有错误的状况,例:

function foo() {
    var a = 2;
    this.bar();
}
function bar() {
    console.log(this.a);
}
foo(); // RefrenceError: a is not defined
复制代码

这段代码试图使用this联通foo()、bar()的词法做用域,从而让bar()能够访问foo()做用域中的变量。但this不可能在词法做用域中查到什么。由于this指向全局,而a属于foo做用域中的变量,因此没法查到

总结:this在任何状况下都不指向函数的词法做用域

词法做用域:定义在词法阶段的做用域,即由你在写代码时将变量和块做用域写在哪里来决定

相关文章
相关标签/搜索