【Web前端基础】js this使用场景是什么

2021-01-15 10:24发布

4条回答
等等同学
2楼 · 2021-01-15 15:54

js--this常见的使用场景


    • 构造函数中的this

    • 对象中的this

    • 普通函数中的this

    • call,apply,bind,箭头函数中的this


我是大脸猫
3楼 · 2021-01-15 20:40

Javascript 中的 this,有时候让人迷惑,所以总结了一下关于this指向的问题。

在函数中 this 到底取何值,是在函数真正被调用执行的时候确定下来的,函数定义的时候确定不了。

因为 this 的取值是函数执行上下文(context)的一部分,每次调用函数,都会产生一个新的执行上下文环境。当代码中使用了 this,这个 this 的值就直接从执行的上下文中获取了,而不会从作用域链中搜寻。

关于 this 的取值,大体上可以分为以下七种情况:

由于严格模式下,禁止this指向全局对象,所以以下示例均运行在非严格模式下

情况一:全局 & 调用普通函数

在全局环境中,this 永远指向 window。

console.log(this === window);     //true1

普通函数在调用时候(注意不是构造函数,前面不加 new),其中的 this 也是指向 window。

var x = 10;
function foo(){
    console.log(this);     //Window
    console.log(this.x);   //10
}
foo();123456

情况二:构造函数

所谓的构造函数就是由一个函数 new 出来的对象,一般构造函数的函数名首字母大写,例如像 Object,Function,Array 这些都属于构造函数。

function Foo(){
    this.x = 10;
    console.log(this);    //Foo {x:10}
}
var foo = new Foo();
console.log(foo.x);      //10123456

上述代码,如果函数作为构造函数使用,那么其中的 this 就代表它即将 new 出来的对象。

但是如果直接调用 Foo 函数,而不是 new Foo(),那就变成情况1,这时候 Foo() 就变成普通函数。

function Foo(){
    this.x = 10;
    console.log(this);    //Window
}
var foo = Foo();12345

情况三:对象方法

如果函数作为对象的方法时,方法中的 this 指向该对象。

var obj = {
    x: 10,
    foo: function () {
        console.log(this);        //Object
        console.log(this.x);      //10
    }
};
obj.foo();12345678

注意:若是在对象方法中定义函数,那么情况就不同了。

var obj = {
    x: 10,
    foo: function () {
        function f(){
            console.log(this);      //Window
            console.log(this.x);    //undefined
        }
        f();
    }
}
obj.foo();1234567891011

可以这么理解:函数 f 虽然是在 obj.foo 内部定义的,但它仍然属于一个普通函数,this 仍指向 window。

在这里,如果想要调用上层作用域中的变量 obj.x,可以使用 self 缓存外部 this 变量。

var obj = {
    x: 10,
    foo: function () {
        var self = this;
        function f(){
            console.log(self);      //{x: 10}
            console.log(self.x);    //10
        }
        f();
    }
}
obj.foo();123456789101112

如果 foo 函数不作为对象方法被调用:

var obj = {
    x: 10,
    foo: function () {
        console.log(this);       //Window
        console.log(this.x);     //undefined
    }
};
var fn = obj.foo;
fn();123456789

obj.foo 被赋值给一个全局变量,并没有作为 obj 的一个属性被调用,那么此时 this 的值是 window。

情况四:构造函数 prototype 属性

function Foo(){
    this.x = 10;
}
Foo.prototype.getX = function () {
    console.log(this);        //Foo {x: 10, getX: function}
    console.log(this.x);      //10
}
var foo = new Foo();
foo.getX();123456789

在 Foo.prototype.getX 函数中,this 指向的 foo 对象。不仅仅如此,即便是在整个原型链中,this 代表的也是当前对象的值。

情况五:函数用 call、apply或者 bind 调用。

var obj = {
    x: 10
}
function foo(){
    console.log(this);     //{x: 10}
    console.log(this.x);   //10
}
foo.call(obj);
foo.apply(obj);
foo.bind(obj)();12345678910

当一个函数被 call、apply 或者 bind 调用时,this 的值就取传入的对象的值。

情况六:DOM event this

在一个 HTML DOM 事件处理程序里,this 始终指向这个处理程序所绑定的 HTML DOM 节点:

function Listener(){   
    document.getElementById('foo').addEventListener('click', this.handleClick);     //这里的 this 指向 Listener 这个对象。不是强调的是这里的 this
}
Listener.prototype.handleClick = function (event) {
    console.log(this);    //
} var listener = new Listener(); document.getElementById('foo').click();12345678

这个很好理解,就相当于是给函数传参,使 handleClick 运行时上下文改变了,相当于下面这样的代码:

var obj = {
    x: 10,
    fn: function() {
        console.log(this);         //Window
        console.log(this.x);       //undefined
    }
};
function foo(fn) {
    fn();
} 
foo(obj.fn);1234567891011

你也可以用通过 bind 切换上下文:

function  Listener(){
    document.getElementById('foo').addEventListener('click',this.handleClick.bind(this));      
}
Listener.prototype.handleClick = function (event) {
    console.log(this);    //Listener {}
}
var listener = new Listener();
document.getElementById('foo').click();12345678

前六种情况其实可以总结为: this 指向调用该方法的对象。

情况七:箭头函数中的 this

当使用箭头函数的时候,情况就有所不同了:箭头函数内部的 this 是词法作用域,由上下文确定。

var obj = {
    x: 10,
    foo: function() {
        var fn = () => {
            return () => {
                return () => {
                    console.log(this);      //Object {x: 10}
                    console.log(this.x);    //10
                }
            }
        }
        fn()()();
    }
}
obj.foo();123456789101112131415

现在,箭头函数完全修复了 this 的指向,this 总是指向词法作用域,也就是外层调用者 obj。

如果使用箭头函数,以前的这种 hack 写法:

var self = this;1

就不再需要了。

var obj = {
    x: 10,
    foo: function() {
        var fn = () => {
            return () => {
                return () => {
                    console.log(this);    // Object {x: 10}
                    console.log(this.x);  //10
                }
            }
        }
        fn.bind({x: 14})()()();
        fn.call({x: 14})()();
    }
}
obj.foo();12345678910111213141516

由于 this 在箭头函数中已经按照词法作用域绑定了,所以,用 call()或者 apply()调用箭头函数时,无法对 this 进行绑定,即传入的第一个参数被忽略。



我自己打call
4楼 · 2021-01-19 09:50

1、函数有所属对象,则指向所属对象

var myObject={value:100};myObject.getValue=function(){console.log(this.value);console.log(this);return this.value;}console.log(myObject.getValue());

这里的getValue属于对象myObject,所以this就指向myObject,执行结果如下: 
clipboard.png

2、函数没有所属对象时,就指向全局对象(window或global)

var myObject={value:100};myObject.getValue=function(){var foo=function(){console.log(this.value);console.log(this);}foo();return this.value;}console.log(myObject.getValue());

在这里,foo属于全局对象,所以foo函数打印的this.value为undefined。
clipboard.png

写到这里,我又想起setTimeout和setInterval方法也是属于全局对象的,所以在这两个函数体内this是指向全局的,所以也是这种情况,如下:

var myObject={value:100};myObject.getValue=function(){setTimeout(function(){console.log(this.value);console.log(this);},0);return this.value;}console.log(myObject.getValue());

执行结果如下:
clipboard.png

所以,如果要得到想要的结果,就要这样写了吧:

myObject.getValue=function(){let self=this;//用一个self保存当前的实例对象,即myObjectsetTimeout(function(){console.log(self.value);console.log(self);},0);return this.value;}console.log(myObject.getValue());

结果如下:
clipboard.png

这又让我想起来了es6中箭头函数的妙用了(这个this绑定的是定义时所在的作用域,而不是运行时所在的作用域;箭头函数其实没有自己的this,所以箭头函数内部的this就是外部的this)(可详看es6教程:http://es6.ruanyifeng.com/#do...箭头函数),如下:

var myObject={value:100};myObject.getValue=function(){// let self=this;//因为用了箭头函数,所以这句不需要了setTimeout(()=>{console.log(this.value);console.log(this);},0);return this.value;}console.log(myObject.getValue());

执行结果同上:
clipboard.png

3、使用构造器new一个对象时,this就指向新对象:

var oneObject=function(){this.value=100;};var myObj=new oneObject();console.log(myObj.value);

这里的this就指向了new出来的新对象myObj,执行结果如下:
clipboard.png

4、apply,call,bind改变了this的指向

var myObject={value:100}var foo=function(){console.log(this);console.log(this.value);console.log("...............");}foo();foo.apply(myObject);foo.call(myObject);var newFoo=foo.bind(myObject);newFoo();

foo本来指向全局对象window,但是call,apply和bind将this绑定到了myObject上,所以,foo里面的this就指向了myObject。执行代码如下:
clipboard.png


人情世故
5楼 · 2021-01-21 01:09

有对象就指向调用对象
没调用对象就指向全局对象
用new构造就指向新对象
通过 apply 或 call 或 bind 来改变 this 的所指。

相关问题推荐

  • 回答 120

    相对前几年来说,要高上不少了,毕竟入行的人也是越来越多了,基础的工作对应想要参与的人群基数越来越大,但是对于高端人才的需求还是很多,人才还是相对稀缺性的。所以,想要学web或者其他技术也一样,别等,别观望。web前端就业方向特别多包括web前端开发...

  • 回答 25

    相对定位和绝对定位是定位的两种表现形式,区别如下:一、主体不同1、相对定位:是设置为相对定位的元素框会偏移某个距离。2、绝对定位:absolute 脱离文档流,通过 top,bottom,left,right 定位。二、特点不同1、相对定位:在使用相对定位时,无论是否进行移...

  • 抓包是什么意思?2020-04-01 17:36
    回答 7
    已采纳

    抓包(packet capture)就是将网络传输发送与接收的数据包进行截获、重发、编辑、转存等操作,也用来检查网络安全。抓包也经常被用来进行数据截取等。抓包可以通过抓包工具来查看网络数据包内容。通过对抓获的数据包进行分析,可以得到有用的信息。目前流行的...

  • 回答 89

    常用的前端框架有Bootstrap框架、React框架、Vue框架、Angular框架、Foundation框架等等

  • 回答 65
    已采纳

    前端是目的就业前景非常不错的一个计算机技术,但是自学的话还是有一定难度的,网络上自学是碎片化的,同时互联网技术跟新换代快,自己的话比较吃力也学习不到最新的技术。

  • SSR 是什么意思?2020-03-20 18:56
    回答 6

    SSR就是一台服务器,可以利用 SSR 在远程的服务器上配置 SSR,使其能够成为 SSR 节点,这样本地电脑或者其它设备利用 SSR 节点实现 VPN 或者远程上网及游戏加速等方面。ShadowsocksR(简称 SSR)是 Shadowsocks 分支,在 Shadowsocks 的基础上增加了一些数据...

  • 回答 52
    已采纳

    计算机培训方向比较多,建议找适合自己的方向选择培训编程类:JAVA、WEB、Python、C/C++、C#等测试类:软件测试运维类:云计算、网络安全设计类:UI设计、3D建模等

  • 回答 11

    1、代码判断xAxis: {type: 'time',splitLine: {show: false},interval: 3600, // 设置x轴时间间隔axisLabel: {formatter: function(value, index) {return liangTools.unix2hm(value)}}},首先要把xAxis 显示类型设置成time,然后设置对应X轴......

  • 回答 8

    HTML5 + CSS + JavaScript 开发 跨平台重用代码 

  • 回答 4

    采用rem单位自动响应,并提供独有栅格化系统快速定义宽高、边距节省css代码量,同时总结各大型移动端网页,提供一套ui颜色搭配规范,尺寸规范,字体规范等。

  • 回答 10

    iView UI、ioni、SUI

  • 回答 6

     jQTouch 

  • 回答 4

    如果只是普通的移动端用vue react 或者dva 如果是要编译成小程序什么的或者混生 就用uni-app(对应vue语法)taro(对应react) 或者纯原生 这个没有限制的,自己怎么舒服怎么来

  • 回答 4

    因为可以运用在网页和小程序的开饭中,而且开源,用着便宜,企业都很喜欢

  • 回答 10

    一、Visual Studio Code下载地址:https://code.visualstudio.com/微软在2015年4月30日Build 开发者大会上正式宣布了 Visual Studio Code 项目:一个运行于 Mac OS X、Windows和 Linux 之上的,针对于编写现代 Web 和云应用的跨平台源代码编辑器。Visual Stud...

  • 回答 9

    jQuery自带淡入淡出效果 https://www.w3school.com.cn/jquery/jquery_fade.asp 看看这个 

没有解决我的问题,去提问