最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • JavaScript 面试题外的【this】

    正文概述 掘金(坂有桑)   2021-04-06   592

    假如在 js 中去掉 this ,会怎么样?

    • 全局函数 -> 直接写 window 嘛,干嘛用 this
    • 箭头函数 -> 在下内部本就没有 this,还是按照闭包的规则,该是谁就是谁
    • bindapplycall -> 在下本就是针对 this 的元编程,自然也不再需要,别了您内
    • 构造方法,对象方法 -> (尴尬)

    其实 js 中的 this ,设计的目的便是实现看起来像 java 的 oop 模式。

    const a = new foo()
    a.bar() 
    

    上述代码中,作为构造函数的 foothis 应该指向一个新的对象并作为结果返回,而作为方法的 bar 应该访问的是其对应的实例对象 a

    让我们再瞟一眼声明

    function foo() {console.log(this)}
    
    function bar() {console.log(this)}
    
    // 在某不知名的角落里
    foo.prototype.bar = bar
    

    在声明的时候我哪知道谁是构造函数,谁是实例方法(掀桌)。

    好吧,那只能看函数执行时动态确定了,用 new [fn](...args) 执行的是构造函数,用 obj.[fn](...args) 执行的是对象方法。以此确定 this 的指向。

    如此看来在函数中,本就不该访问 this,应该报错。在拥有闭包作用域的 lambda 表达式中,this 应该按闭包的规则向上层查找。

    慢着,js 的函数本身就带闭包作用域那咋办?

    啊啊啊,不管了, 直接就指向 window 吧,本就一周设计出来的玩意,还想咋地,又不是不能用……


    js 相比其他很多语言拥有更高度的动态性,而这种动态性并非都是优势,一些来自于过于敷衍的设计的动态性,往往会造成各种灾难,this 便是一例。

    this 这种灾难来自于设计者想把全局函数、lambda 表达式、构造函数、对象上的方法糅合在一起。然而这并无必要。

    为什么其他语言不会有这种问题,因为其他语言把全局函数、lambda 表达式、构造函数、对象上的方法声明时分的很清楚,并不需要动态去确定。

    以 rust 举例

    pub struct ClassName {
        field: i32,
    }
    
    impl ClassName {
        // 充当构造函数的静态方法 new,返回一个 ClassName 实例
        pub fn new(value: i32) -> ClassName {
            ClassName {
                field: value
            }
        }
    
        pub fn public_method(&self) {
            // 方法内显示声明的 self 即是 js 内部隐式声明的 this
            println!("from public method");
            self.private_method();
        }
    
        fn private_method(&self) {
            println!("from private method");
        }
    }
    

    而 scala 的设计显然更为精妙。

    // class 的声明代表这是一个构造函数
    class Point(xc: Int, yc: Int) {
       // 构造函数中声明的变量/常量就是对象的属性
       var x: Int = xc
       var y: Int = yc
    
       // 构造函数中声明的函数就是对象的方法
       def move(dx: Int, dy: Int) {
          x = x + dx
          y = y + dy
          println ("x 的坐标点: " + x);
          println ("y 的坐标点: " + y);
       }
    }
    
    

    今时今日的 js 已经不再是那个 js 了。在 this 问题上,TC39 委员会又做了那些努力呢。

    首先,箭头函数替代了履行了 function 中 lambda 表达式的职能。在箭头函数中访问 this,也会以闭包的方式逐层向上查找了。var _this = this 已经成为了历(li)史(shi)。

    全局函数中的 this,其实在严格模式中已经解决了一部分。

    而真正应该用到 this 的地方即构造方法和实例方法,全都在 class 声明的括号内部。

    也就说一般情况下,在我们的代码中, this 只能出现在 class 的括号内。

    class Point {
      constructor(x, y) {
        // 显示声明的构造函数
        this.x = x;
        this.y = y;
      }
    
      toString() {
        // 显示声明的对象方法
        return '(' + this.x + ', ' + this.y + ')';
      }
    }
    

    为啥整篇文章避而不谈 call/apply/bind。因为在我看来这仨都属于 js 元编程的范畴。

    何谓元编程?

    简而言之,就是在代码层面上赋予新的解释,针对代码进行编程。可以是由原来的代码生成新的代码,也可以是改写原代码的功能。

    例如 proxy 就是让用户改写对象上的操作,call/apply/bind 则是改写函数内部的动态作用域规则(由于箭头函数内没有动态作用域,所以对它没用), with那更是厉害到让人闻风丧胆。

    而元编程则是业务代码中不允许出现,框架代码中慎之又慎的东西。

    我希望在你用到的时候已经不需要这篇文章了。


    时下,不少人选择以面向面试题学习作为自己的学习方式。然而实际上应试教育和实际开发是有比较大的出入的。

    譬如 this ,是前端基础面试题中的常客,同时在哪都有汗牛充栋的的文章一一列举 this 在不同的上下文环境中的指向的文章。有些文章甚至想出各种“花式”技巧,什么就近原则啊,什么各种嵌套啊。有用吗?私以为并没有啥用。反倒是那些能真的讲讲 this 为什么如此设计,以及如何应用的文章寥寥。


    下一篇,打算聊聊绝大多数人都没在代码里写过的 WeakMap WeakSet,如果大家觉得本文还有点内容,还请高抬贵手点个赞哈。


    起源地下载网 » JavaScript 面试题外的【this】

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元