【JS】ES6类Class复习笔记以及与ES5类构造函数的对比

40 篇文章 2 订阅
21 篇文章 1 订阅
本文详细探讨了ES6中Class的特性,指出Class内部默认开启严格模式,介绍了Class中属性的四种写法及其在原型链中的表现。同时,对比了ES5构造函数与ES6 Class的不同,强调了构造器中的`this`行为以及实例属性的添加方式。文章还提出了一个关于原型链覆盖问题的思考,并记录了一个未解之谜。
摘要由CSDN通过智能技术生成

ES6类

es6中class会自动开启严格模式,所以没有指定this的时候,this会是undefined
到目前为止,本人遇到过的,在class内部的属性有四种写法,以下展示:

        class Fun {
            constructor() {
            	//构造器中的this固定是类的实例对象,所以以下写法会给实例对象上添加属性
                this.d = d
                this.e = () => {
                    console.log('e', this);
                }
            }

            // a是静态方法,放在Fun类的自身上,只能由Fun调用,es5只能在外部Fun.xx = xxx这种方式
            static a() {
                console.log('a', this);
            }

            // b放在Fun的原型对象上,供实例对象调用,因为实例对象本身没有b,所以顺着原型链往上找
            b() {
                console.log('b', this);
            }

            // c放在了实例对象上,这种写法,可以弥补在构造器中没写的内容,
            // 比如构造器中写this.xxx = xxx,也可以在外部直接写xxx=xxx,是一样的,但是如果两者都写了,以构造器为准
            c = () => {
                console.log('c', this);
            }
        }
        function d() {
            console.log('d', this);
        }

        let f = new Fun()
        console.log(f);
        // console.log(Fun);
        Fun.a()
        // Fun.b()//会报错--Fun.b is not a function
        // Fun.c()//会报错--Fun.c is not a function

        // f.a()//会报错--f.a is not a function
        f.b()
        f.c()
        f.d()
        f.e()

在这里插入图片描述

可以看到Fun及其实例对象f的内部如下
在这里插入图片描述
a挂在Fun本身上;
b挂在Fun原型prototype上,也是d的原型__ptoro__上;
c、d、e挂在Fun实例对象f上;

所以为什么f.b()因为在自身上找不到,所以顺着原型链去找到了,就可以调用,但是Fun.b()却不行,同样都是不在自身上,但是原型链上有

这就要涉及原型链上的知识了,一个函数自身上没有的属性或者方法,会顺着原型链去往上找,那么这个时候是把自身当做是一个实例对象,所以往上找的是__proto__里面的内容,而不是去找prototype,prototype是跟自己的实例对象中的__proto__内容一致,相当于从prototype复制给自身实例对象的__proto__,所以当Fun.b()执行的时候,Fun里面没有,但是Fun的prototype里面有,也不会去调用,因为顺着原型链找的是Fun的__proto__,Fun的prototype只是给了f的__proto__一个依据。因为Fun的__proto__里面也没有b,所以找不到,也就报错了

注意1
构造器中的写this.xxx = xxx,也可以在外部直接写xxx=xxx,是一样的,都是在类的实例对象上添加属性,因为构造器的this就是实例对象,但是如果两者都写了,以构造器为准

        class Fun {
            constructor() {
                this.c = ()=>{
                    console.log('重置c');
                }
            }
            c = () => {
                console.log('c', this);
            }
        }
        
        let f = new Fun()
        f.c()

在这里插入图片描述

可以看出是构造器中的c生效了,这个我在之前的React项目里也遇到过,总结了一篇链接

注意2
每一次new Fun()的时候,其实可以把Fun当做普通函数看待,所以Fun里面的函数会跑一遍,但是一般这种构造函数,一般不会直接写要输出之类的函数,但是为了测试,在一个class中,只有constructor会被自动调用,其他的要么是挂载实例上,要么原型上,要运行这些被挂载的函数,需要单独调用,只有constructor在new的时候就被调用,所以在里面可以写输出语句,比如

        class Fun {
            constructor() {
                console.log('?');
            }
        }
        let f = new Fun()

仅仅只是new了,就可以看到?被输出
在这里插入图片描述

ES5与ES6类的对比

ES5只能用function构造函数来进行构造类,如下

        // es5构造函数与es6构造函数区别
        function F() {
            // a会保存在f实例对象里
            this.a = 1
            // 构造函数里的函数,下面这种直接写的,不会存在实例对象里,也不会在D中,这只是普通的函数声明
            function b(x) {
                console.log(x);
            }
            // 并不能做F的静态属性(同上),而且这里相当于是省略了var关键字,在class里面要写清楚
            c = 2
            // 只是把b当做一个new 的过程中能执行的一个函数,当然如果都没有b(c)这句代码,那这个b函数压根就没啥存在感
            //可以看做是es6里面的constructor里面的立即执行的代码,本来function也是函数,是一段要执行的代码
            b(c)

        }
        // d会保存到原型链上
        F.prototype.d = 1
        // e会保存到F构造函数静态属性里
        F.e = 3
        let f = new F()
        // F.b()//这样是取不到b函数的,因为b不是F的属性,只能通过F.d这种才能加静态属性

同样的F函数,要达到以上效果,无非是实现以下四种

  • 赋予实例对象属性 f.xx
  • 赋予构造函数静态属性 F.xx
  • 赋予原型对象属性 F.prototype.xx或者 f. __ proto__ .xx , 注意f.xx只能访问到原型对象(如果f本身上没有),不能修改原型对象,不然会给f实例对象本身添加一个xx属性 具体可见此处
  • 在内部执行的函数,可类似constructor函数
        class F {
            constructor() {
                // 实例对象上
                this.a = 1

                // 普通函数
                function b(x) {
                    console.log(x);
                }
                let c = 2
                b(c)
            }

            // 保存到实例对象f上
            aa = 1

            // F构造函数本身上
            static e = 3

			//在原型对象上,现在有个问题是想在原型对象上加属性,不是加函数对象,比如刚刚的d就只是一个1,不是一个函数,要如何做
			//我知道的是在外部 通过 F.prototype.g = 1  添加,在内部不知道怎么办
            d(){
                console.log(4);
            }
	
			//在实例对象上
			g = () =>{
				consloe.log(6)
			}

        }
		
        let f = new F()

一个难题,判断输出

    class A {
      a = () => {
        console.log(1);
      }
    }
    class B extends A {
      a(){
        console.log(2);
      }
    }

    let b = new B()
    b.a()

结果是1
按理说
在A里面,a作为实例对象的属性,B继承A,那么B的prototype属性指向的就是A 的实例对象,这里面应该是有a的,然后B里面在其原型对象上添加a,我认为就会覆盖实例对象上原来的a,变成输出2,通过截图也能看到,确实,在原型对象里是输出2 的a,而不是输出1的a,但是最后的b里面却还是输出1
在这里插入图片描述
搞不懂,先记下来吧

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值