this关键字与箭头函数

一.this的值

this的值表示当前代码所在的执行环境
复制代码

二.this的本质

  • 当一进入函数上下文中,可是尚未开始执行函数体内的代码时,此时js引擎会找到该上文 中全部的function declarations(FD)、variableDeclaration、arguments、thisValue、scopeChain等进行初始化,在这个阶段(也就是说在函数调用阶段)this的值才肯定。注意不是函数定义的时候知道的。node

  • 事实上函数定义时的第一个参数就是this,只不过js将它隐藏了,咱们看不到,因此说this的值在调用阶段才能肯定,由于不知道你会以什么方式调用函数或者说不肯定你每次调用函数时传入的参数值是什么。浏览器

看下列代码:
    function fn() {
        console.log(this)
    }
    fn()    //window
    
    1.以上代码在函数被调用时并无传入相应的参数那么this值是怎么获取到的?
    以前已经说过js将它隐藏了而已。 
    2.那为何this的值是window呢?
    当你在全局环境中或者在全局环境下调用函数时,this的值默认为window(在非严格模式下)
    3.call、apply、bind能够修改this的值
    
    将上述代码当作下面这种形式就好理解了:
    function fn() {
        console.log(this)   //window
    }
    fn.call(window)  //实际上js给你传了一个参数window进去,故你打出的this为window
    fn.apply(window)
复制代码

好,到这里你又有疑问了,那我经过fn.call(window)将window传进去了,那么在函数定义 的时候并无一个变量接收这个window参数啊,那this怎么仍是可以打出来呢?bash

能够参考arguments对象。app

function fn() {
        console.log(arguments)   //[5, 10, callee: ƒ, Symbol(Symbol.iterator): ƒ]
    }
    fn.call(window, 5, 10)
    
    在这里函数fn定义的时候也没有形式参数,那么实参仍然能够经过arguments获取到,
    那么this的道理也是同样的,this其实是函数定义时候的第一个参数,js将它隐藏了。
    
    你能够将上面代码当作下面这种形式:
    function fn(/*this这是隐藏的变量*/) {
        console.log(arguments)   //[5, 10, callee: ƒ, Symbol(Symbol.iterator): ƒ]
    }
    fn.call(window, 5, 10)
复制代码

经过以上能够知道,在函数内部,this的值是取决于函数被调用的方式而不是定义的方式。函数

三.在function(运行内)环境中this的值

3.1 简单调用ui

function f() {
        return this        
    }
    f() //在浏览器中为window,在node中为global,至关于下面这种调用方式
    f.call(window/global)   //这里至关于将this的值指定为window或global
复制代码

在严格模式下,this将保持它进入执行环境时的值。若是this没有被执行环境定义,那它的默认值就为undefined。this

function f() {
        "use strict"
        return this        
    }
    f() //undefined,至关于下面这样
    f.call(undefined)
复制代码

3.2 做为对象的方法spa

当函数做为对象里的方法被调用时,它们的this指向的是调用该函数的那个对象。prototype

let obj = {
        age: 18,
        getAge: function () {
            return this.age
        }
    }
    obj.getAge()   //18,这里的this指向obj;至关于下面这种调用方式
    obj.getAge.call(obj)  //18
复制代码

3.3 做为构造函数code

当一个函数用做构造函数时(使用new关键字),它的this被绑定到正在构造的新对象(实例)。

function Fn() {
        this.age = 23
    }
    let fn = new Fn()
    console.log(fn.age)  //23
复制代码

3.4 bind方法

ECMAScript5 引入了Function.prototype.bind。调用fn.bind(obj)会建立一个与fn具备相同函数体和做用域的函数,可是在这个新函数中,this将永久地被绑定到了bind的第一个参数,不管这个函数是如何被调用的。

let obj = {
            name: 'jack',
            address: 'china'
    }
    let name = 'tom'
    function fn () {
        console.log(this.name)
    }
    let f = fn.bind(obj)
    f() //jack
    f.call()    //"jack"
    f.call(obj) //"jack"
    以上能够看到不管函数f被如何调用,this都是指向obj
复制代码

四.全局环境中this的值

  • 不管是否在严格模式下,在全局执行环境中(在任何函数体外部)this都指向全局对象
//在浏览器中window对象同时也是全局对象
this === window //true
a = 'l'
this.a === window.a //true
复制代码

五.箭头函数

箭头函数事实上根本没有this,其this值是箭头函数所在的那个最近环境中this的值。在全局环境中,它将被设置为全局对象:

let arrow = () => this
console.log(arrow())  //window
复制代码
var name = 'tony'
let obj = {
    name: 'jack',
    age: 25,
    getName () {
        return () => this.name
    }
}
console.log(obj.getName()())    //'jack'

复制代码

以上getName函数中返回的那个箭头函数中的this值是该箭头函数所在的那个最近环境中的this值,离该箭头函数最近的一个环境是函数getName,而getName中的this为obj,故箭头函数中的this也为obj,故打印出jack。

注意:在箭头函数中,若是将this传递给call、bind、或者apply,它将被忽略。不过你仍然能够为调用添加参数,不过第一个参数应该设置为null。看下列例子:

var name = 'tony'
        let obj = {
            name: 'jack',
            age: 25,
            getName() {
                return () => this.name
            }
        }
        let obj2 = {
            name: 'ma'
        }
        console.log(obj.getName()())    //'jack'
        console.log(obj.getName().call())   //'jack'
        console.log(obj.getName().call(obj2))   //'jack'
复制代码

注意如下一点要进行区分:

var name = 'tony'
        let obj = {
            name: 'jack',
            age: 25,
            getName() {
                return () => this.name
            }
        }
        let obj2 = {
            name: 'ma'
        }
       let temp = obj.getName()
       console.log(temp())  //'jack' 注意temp()的结果是'jack',不是'tony'。
            
        //可是若是你只是引用了obj的方法,而没有调用它,那么调用箭头函数后,this
        //指向window
        
        let temp2 = obj.getName
        console.log(temp2()())  //此时为'tony'
        //以上那句至关于,故结果为tony。由于在调用temp2()的时候,内部箭头函数的this
        就被永久的绑定成了temp2函数环境内部的this值,也即window。
        console.log(temp2.call(window)())   //'tony'
        
    当obj.getName()进行调用时,此时getName函数环境内的this值为obj。因为内部返回了一个箭头函
    数,而箭头函数自己并无this,它取得其实是离它最近的那个环境中this的值,this值被永久的置
    为了obj.getName函数的this,即为obj。当将obj.getName()的返回值赋值给了temp,因此即便被调用
    的方式一般将其设置为undefined或全局对象,它的this也仍然是 obj。
    
    综上:
       箭头函数自己没有this,它的this值其实是离它最近的那个环境中this的值,因为没有this值
       故没法做为构造函数而使用。
复制代码
相关文章
相关标签/搜索