文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

编程语言中this、call、apply的用法分析

2023-06-14 05:41

关注

小编给大家分享一下编程语言中this、call、apply的用法分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

前言+思考题

记得当时找实习的时候,总是会在简历上加上一句——熟悉Js,例如this指向、call、apply等…

而每次投递简历时我都会经历如下步骤

思考题

下面几道题是我在网上搜索出来的热度较高的问题,如果大佬们可以轻松的回答上,并有清晰的思路,不妨直接点个赞吧(毕竟也消耗了不少脑细胞),如果大佬们能在评论处指点一二,就更好了!!!

填空题:

问答题:

代码分析题:

var name = 'window'var person1 = {  name: 'person1',  show1: function () {    console.log(this.name)  },  show2: () => console.log(this.name),  show3: function () {    return function () {      console.log(this.name)    }  },  show4: function () {    return () => console.log(this.name)  }}var person2 = { name: 'person2' }person1.show1()person1.show1.call(person2)person1.show2()person1.show2.call(person2)person1.show3()()person1.show3().call(person2)person1.show3.call(person2)()person1.show4()()person1.show4().call(person2)person1.show4.call(person2)()

一、this的指向

百度、谷歌上输入“this的指向”关键字,大几千条文章肯定是有的,总不至于为了全方面、无死角的掌握它就要将所有的文章都看一遍吧?所以不如梳理出一个稳固的框架,顺着我们的思路来填充它。

思维导图

编程语言中this、call、apply的用法分析

本节精华:
分析

1、作为对象的方法调用

当函数作为对象的方法被调用时,this指向该对象

var obj = {    a: 'yuguang',    getName: function(){        console.log(this === obj);        console.log(this.a);    }};obj.getName(); // true yuguang

2、作为普通函数调用

当函数不作为对象的属性被调用,而是以普通函数的方式,this总是指向全局对象(在浏览器中,通常是Window对象)

window.name = 'yuguang';var getName = function(){    console.log(this.name);};getName(); // yuguang

或者下面这段迷惑性的代码:

window.name = '老王'var obj = {    name: 'yuguang',    getName: function(){        console.log(this.name);    }};var getNew = obj.getName;getNew(); // 老王

而在ES5的严格模式下,this被规定为不会指向全局对象,而是undefined

3、构造器调用

除了一些内置函数,大部分Js中的函数都可以成为构造器,它们与普通函数没什么不同

构造器普通函数的区别在于被调用的方式
当new运算符调用函数时,总是返回一个对象,this通常也指向这个对象

var MyClass = function(){    this.name = 'yuguang';}var obj = new MyClass();obj.name; // yuguang

但是,如果显式的返回了一个object对象,那么此次运算结果最终会返回这个对象。

var MyClass = function () {    this.name = 1;    return {        name: 2    }}var myClass = new MyClass(); console.log('myClass:', myClass); // { name: 2}

只要构造器不显示的返回任何数据,或者返回非对象类型的数据,就不会造成上述问题。

4、call或apply调用

跟普通的函数调用相比,用call和apply可以动态的改变函数的this

var obj1 = {    name: 1,    getName: function (num = '') {        return this.name + num;    }};var obj2 = {    name: 2,};// 可以理解成在 obj2的作用域下调用了 obj1.getName()函数console.log(obj1.getName()); // 1console.log(obj1.getName.call(obj2, 2)); // 2 + 2 = 4console.log(obj1.getName.apply(obj2, [2])); // 2 + 2 = 4

5.箭头函数

箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this。

因此,在下面的代码中,传递给setInterval的函数内的this与封闭函数中的this值相同:

this.val = 2;var obj = {    val: 1,    getVal: () => {        console.log(this.val);    }}obj.getVal(); // 2

常见的坑

就像一样,有的时候this会指向undefined

情况一

var obj = {    name: '1',    getName: function (params) {        console.log(this.name)    }};obj.getName();var getName2 = obj.getName;getName2();

这个时候,getName2()作为普通函数被调用时,this指向全局对象——window。

情况二

当我们希望自己封装Dom方法,来精简代码时:

var getDomById = function (id) {    return document.getElementById(id);};getDomById('p1') //dom节点

那么我们看看这么写行不行?

var getDomById = document.getElementByIdgetDomById('p1') // Uncaught TypeError: Illegal invocation(非法调用)

这是因为:

利用call和apply修正情况二

document.getElementById = (function (func) {    return function(){        return func.call(document, ...arguments)    }})(document.getElementById) // 利用立即执行函数将document保存在作用域中

二、call和apply

不要因为它的“强大”而对它产生抗拒,了解并熟悉它是我们必须要做的,共勉!

思维导图

编程语言中this、call、apply的用法分析

1.call和apply区别

先来看区别,是因为它们几乎没有区别,下文代码实例call和apply都可以轻易的切换。

当它们被设计出来时要做到的事情一摸一样,唯一的区别就在于传参的格式不一样

因为在所有(非箭头)函数中都可以通过arguments对象在函数中引用函数的参数。此对象包含传递给函数的每个参数,它本身就是一个类数组,我们apply在实际使用中更常见一些。

call是包装在apply上面的语法糖,如果我们明确的知道参数数量,并且希望展示它们,可以使用call。

当使用call或者apply的时候,如果我们传入的第一个参数为null,函数体内的this会默认指向宿主对象,在浏览器中则是window

借用其他对象的方法

我们可以直接传null来代替任意对象

Math.max.apply(null, [1, 2, 3, 4, 5])
2.call和apply能做什么?

使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数——来时MDN

1.调用构造函数来实现继承

通过“借用”的方式来达到继承的效果:

function Product(name, price) {this.name = name;this.price = price;}function Food(name, price) {Product.call(this, name, price); //this.category = food;}var hotDog = new Food('hotDog', 20);

2.调用函数并且指定上下文的 this

此时this被指向了obj

function showName() {    console.log(this.id + ':' + this.name);};var obj = {    id: 1,    name: 'yuguang'};showName.call(obj)

3.使用call单纯的调用某个函数

Math.max.apply(null, [1,2,3,10,4,5]); // 10

三、模拟实现一个call

先来看一下call帮我们需要做什么?

var foo = {value: 1};function show() {console.log(this.value);};show.call(foo); //1

就像解方程,要在已知条件中寻找突破哦口:

第一版代码

上面提到的3点,仅仅完成了一点,且传入的参数

var foo = {    value: 1};function show() {    console.log(this.value);};Function.prototype.setCall = function (obj) {    console.log(this); // 此时this指向show    obj.func = this; // 将函数变成对象的内部属性    obj.func(obj.value); // 指定函数    delete obj.func // 删除函数,当做什么都没发生~}show.setCall(foo);

第二版代码

为了解决参数的问题,我们要能获取到参数,并且正确的传入:

var foo = {    value: 1};function show(a, b) {    console.log(this.value);    console.log(a + b);};Function.prototype.setCall = function (obj) {    obj.fn = this; // 将函数变成对象的内部属性    var args = [];    for(let i = 1; i < arguments.length; i++){        args.push('arguments[' + i + ']');    }    eval('obj.fn(' + args + ')'); // 传入参数    delete obj.fn; // 删除函数,当做什么都没发生~}show.setCall(foo, 1, 2); // 1 3

此时,我们就可以做到,传入多个参数的情况下使用call了,但是如果你仅想用某个方法呢?

第三版代码

Function.prototype.setCall = function (obj) {    var obj = obj || window;    obj.fn = this;    var args = [];    for(var i = 1, len = arguments.length; i < len; i++) {    args.push('arguments[' + i + ']');  }  var result = eval('obj.fn(' + args +')');  delete obj.fn;  return result;};// 测试一下var value = 2;var obj = { value: 1 };function bar(name, age) {  console.log(this.value);  return {    value: this.value,    name: name,    age: age  }}bar.setCall(null); // 2console.log(bar.setCall(obj, 'yuguang', 18));

四、bind

bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用 —— MDN

提到了callapply,就绕不开bind。我们试着来模拟一个bind方法,以便加深我们的认识:

Function.prototype.bind = function (obj) {    var _this = this; // 保存调用bind的函数    var obj = obj || window; // 确定被指向的this,如果obj为空,执行作用域的this就需要顶上喽    return function(){        return _this.apply(obj, arguments); // 修正this的指向    }};var obj = {    name: 1,    getName: function(){        console.log(this.name)    }};var func = function(){    console.log(this.name);}.bind(obj);func(); // 1

这样看上去,返回一个原函数的拷贝,并拥有指定的 this 值,还是挺靠谱的哦~

以上是“编程语言中this、call、apply的用法分析”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注编程网行业资讯频道!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯