前端学习笔记之this——懂不懂由你,反正我是懂了

2018-10-20  本文已影响0人  astak3

this

this对于初学 JS 的新人来说,是一道坎,看到this就晕头晕脑,脑容量一下不够用了。

先来说下判断this结论

  1. this是函数调用时call的第一个参数
  2. this只有在函数执行的时候才能被确定,实际指向调用它那个对象(上一级)

先来看下函数常用的几种调用方式

fn(a,b)
fn.name(a,b)
var f = fn.name; f(a,b)
fn.call(undefined,a,b)
fn.apply(undefined,[a,b])

上面三种调用方法对于新人很熟悉,而对后面两种方法比较陌生,自然也就弄不明白this含义了。

改写下函数的调用方式就会发现这两种是等价的,回到上面说的结论,call的第一个参数是thisab才是传进去的参数。

fn(a,b) === fn.call(undefined,a,b) === window.fn.apply(window,[a,b])

明白了这点,大部分的this就不难判断了,新人在判断this时只需改写函数调用方式就能知道this指向了。

this例子

下面方法中暂且不讨论严格模式,this的指向
例子1:

var user = 'window'
function fn(){
    var user = 'object';
    console.log(this.user); //windwow
}
fn();    //改写 window.fn.call(window)

fn是全局对象window的方法

例子2:

var user = 'window'
var obj = {
    user:'object',
    fn:function(){
        console.log(this.user);  //object
    }
}
obj.fn();    //改写 obj.fn.call(obj)

这里的fn是被obj调用的,所以fn内部的this指向obj内部的user

你可能会有疑惑了,这里是不是可以改写成window.obj.fn.call(window),往下看

例子3:

var user = 'window'
var obj = {
    user:'object',
    fn:function(){
        console.log(this.user);  //object
    }
}
window.obj.fn();    //改写 window.obj.fn.call(window.obj)

先看下面例子

例子4:

var user = 'window'
var obj = {
    user:'object',
    fn1:{
        user:'function',
        fn2:function(){
            console.log(this.user)    //function
        }
    }
}
obj.fn1.fn2();    //改写 obj.fn1.call(obj.fn1)

例子3中正常情况下都是把window给省略的,这里写出来是为了和例子4做对比。

假设例子4中obj对象是不是window下的方法,而是和window平级(实际不存在这种假设,容易理解)。

这里是链式调用,this的最终指向是调用它的上一层对象fn1,但是不能改写成obj.fn1.call(fn1),只有window可以省略。

例子5:

var user = 'window'
var obj = {
    user:'object',
    fn1:{
        user:'function',
        fn2:function(){
            console.log(this.user)    //window
        }
    }
}
var a = obj.fn1.fn2;
a()        //改写 window.a.call(window)

先看下面例子

例子6:

var a = {user:'window'}
var obj = {
    user:'object',
    fn1:{
        user:'function',
        fn2:function(){
            console.log(this.user)    //window
        }
    }
}

obj.fn1.fn2.call(a);

看到例子5和例子6是不是已经晕了。

例子5中,var a = obj.fn1.fn2只是赋值,并没用执行,而真正执行的时候,awindow下的方法,所以fn2内部的this指向window下的user

例子6中,call的第一个参数是a,那this肯定指向auser,因为显示绑定优先级高于隐示绑定。

那你可能要问什么是显示绑定,什么是隐示绑定呢?

obj.fn()    //隐示绑定
obj.fn.call(obj)    //显示绑定

也就是说你改写后的调用就是显示绑定。

new构造函数

例子7:

function Fn(){
    this.user = 'object';
}
var a = new Fn();
console.log(a.user); //object

例子7中,因为构造函数的this指向构造出来的实例,所以a是用new构造出来的对象,那么this就是指向a

构造函数中要注意的一点是:默认情况下,构造函数是没有return,但是非要加一个return的话。

  1. 如果return的是引用类型值,那么构造函数的this就指向return的对象
  2. 如果return的是基本类型值,那么构造函数的this就指向构造出来的实例化函数

this基本应用就是这些,做一些实操练习巩固一下

this实操

实操1:

function X(){
    return object = {
        name:'object',
        f1(x){
            x.f2()        //② 改写 options.f2.call(options)
        },
        f2(){
            console.log(this)
        }
    }
}

var options = {
    name:'options',
    f1(){},
    f2(){
        console.log(this)   //③ 运行这个this,打印 options 函数
    }
}

var x = X();
x.f1(options);    //① 改写 object.f1.call(object,options)

看到this就马上改写,不改写就做,肯定错。

分析

  1. 首先把x.f1(options)改写object.f1.call(object,options)
  2. x.f1(options)调用object对象内部f1方法,把options函数作为参数传入,所以 object内部f1(x)中的xoptions函数
  3. f2内部的this指向options

实操2:

function X(){
    return object = {
        name:'object',
        f1(x){
            x.f2.call(this)     //② 这里是显示绑定,改写 options.f2.call(object)
        },
        f2(){
            console.log(this)
        }
    }
}

var options = {
    name:'options',
    f1(){},
    f2(){
        console.log(this)   //③ 运行这个 this 打印 object
    }
}

var x = X()
x.f1(options)   //① 改写 object.f1.call(object,options)

分析

  1. 首先把x.f1(options)改写object.f1.call(object,options)
  2. f1内部的this指向object
  3. x.f2.call(this)改写options.f2.call(object),这里的.call(this)是显示指定
  4. f2内部的this就是object

实操3:

function X(){
    return object = {
        name:'object',
        options:null,        //③ options = options
        f1(x){
            this.options = x    //② 改写 object.options = options
            this.f2()            //③ 改写 object.f2.call(object)
        },
        f2(){
            this.options.f2.call(this)    //④ 显示绑定,改写
 object.options.f2.call(object)
        }
    }
}

var options = {
    name:'options',
    f1(){},
    f2(){
        console.log(this)    //⑤运行这个 this,打印 object
    }
}

var x = X()
x.f1(options)   //① 改写 object.f1.call(object,options)

分析

  1. 首先把x.f1(options) 改写object.f1.call(object,options)
  2. f1内this指向objectoptions作为参数传进来
  3. this.options = x改写object.options = options,同时也把this.f2()改写称object.f2()
  4. this.options.f2.call(this) 改写object.options.f2.call(object),.call(this)是显示绑定
  5. f2内部的this就是object
上一篇下一篇

猜你喜欢

热点阅读