资讯专栏INFORMATION COLUMN

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

jay_tian / 1983人阅读

摘要:构造函数例子例子中,因为构造函数的指向构造出来的实例,所以是用构造出来的对象,那么就是指向。构造函数中要注意的一点是默认情况下,构造函数是没有,但是非要加一个的话。

this

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

先来说下判断this结论

this是函数调用时call的第一个参数

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的话。

如果return的是引用类型值,那么构造函数的this就指向return的对象

如果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就马上改写,不改写就做,肯定错。

分析

首先把x.f1(options)改写object.f1.call(object,options)

x.f1(options)调用object对象内部f1方法,把options函数作为参数传入,所以 object内部f1(x)中的xoptions函数

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)

分析

首先把x.f1(options)改写object.f1.call(object,options)

f1内部的this指向object

x.f2.call(this)改写options.f2.call(object),这里的.call(this)是显示指定

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)

分析

首先把x.f1(options) 改写object.f1.call(object,options)

f1内this指向objectoptions作为参数传进来

this.options = x改写object.options = options,同时也把this.f2()改写称object.f2()

this.options.f2.call(this) 改写object.options.f2.call(object),.call(this)是显示绑定

f2内部的this就是object

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/107912.html

相关文章

  • JS 中的闭包是什么?

    摘要:大名鼎鼎的闭包面试必问。闭包的作用是什么。看到闭包在哪了吗闭包到底是什么五年前,我也被这个问题困扰,于是去搜了并总结下来。关于闭包的谣言闭包会造成内存泄露错。闭包里面的变量明明就是我们需要的变量,凭什么说是内存泄露这个谣言是如何来的因为。 本文为饥人谷讲师方方原创文章,首发于 前端学习指南。 大名鼎鼎的闭包!面试必问。请用自己的话简述 什么是「闭包」。 「闭包」的作用是什么。 首先...

    Enlightenment 评论0 收藏0
  • 简单说 一道JS闭包面试题

    摘要:说明最近看到这样一段代码问三行的输出分别是什么觉得有点意思,和大家一起来聊聊。说到这里,这道题基本上可以解决了,希望大家能听明白我上面说的话,下面的就简单了。 说明 最近看到这样一段代码 function fun(n,o){ console.log(o); return { fun:function(m){ return fun...

    mushang 评论0 收藏0
  • 简单说 一道JS闭包面试题

    摘要:说明最近看到这样一段代码问三行的输出分别是什么觉得有点意思,和大家一起来聊聊。说到这里,这道题基本上可以解决了,希望大家能听明白我上面说的话,下面的就简单了。 说明 最近看到这样一段代码 function fun(n,o){ console.log(o); return { fun:function(m){ return fun...

    Lin_YT 评论0 收藏0
  • 简单说 一道JS闭包面试题

    摘要:说明最近看到这样一段代码问三行的输出分别是什么觉得有点意思,和大家一起来聊聊。说到这里,这道题基本上可以解决了,希望大家能听明白我上面说的话,下面的就简单了。 说明 最近看到这样一段代码 function fun(n,o){ console.log(o); return { fun:function(m){ return fun...

    banana_pi 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<