火锅网站建设,什么是域名为什么需要它,购物商城源码,永久免费不收费的软件app目录 一、前言二、ES6与ES5继承机制区别三、super作为函数1、构造函数this1#xff09;、首先要明确this指向①、普通函数②、箭头函数③、注意事项 2#xff09;、其次要明确new操作符做了哪些事情 2、super()的用法及注意点1#xff09;、用法2#xff09;、注意点 四、s… 目录 一、前言二、ES6与ES5继承机制区别三、super作为函数1、构造函数this1、首先要明确this指向①、普通函数②、箭头函数③、注意事项 2、其次要明确new操作符做了哪些事情 2、super()的用法及注意点1、用法2、注意点 四、super作为对象1、super在子类普通方法中作为对象2、super在子类静态方法中作为对象 五、总结 一、前言
类的继承可以通过extends实现让子类继承父类的属性和方法而在子类内部构造函数constructor必须调用super()实现继承super()代表父类构造函数调用之后生成一个继承父类的this对象
二、ES6与ES5继承机制区别
ES5的继承机制是先创造一个独立的子类的实例对象然后再将父类的方法添加到这个对象上面即“实例在前继承在后”ES6的继承机制则是先将父类的属性和方法加到一个空对象上面然后再将该对象作为子类的实例即“继承在先实例在后”所以ES6的继承必须先调用super()这样会生成一个继承父类的this对象没有这一步就无法继承父类。这意味着新建子类实例时父类的构造函数必定会先运行一次super既可以作为函数使用也可以作为对象使用两种方法有很大的不同
三、super作为函数
super()作为函数调用时子内constructor内部必须调用代表父类的构造函数调用之后生成的是子类的实例即super()内部this指向的是子类的实例由构造函数this指向可得出构造函数内部this指向的是生成的实例而super()调用之后生成的是子类实例
1、构造函数this
1、首先要明确this指向
①、普通函数
内部的this指向函数运行时所在的对象也即指向函数的直接调用者
如果一个函数在全局环境运行this就指向顶层对象浏览器中为window对象如果一个函数作为某个对象的方法运行this就指向那个对象如果一个函数作为构造函数this指向它的实例对象
②、箭头函数
没有自己的this对象内部的this就是定义时上层作用域中的this
③、注意事项
构造函数只能是普通函数箭头函数不能作为构造函数没有prototype不可以对箭头函数使用new命令否则会抛出一个错误
2、其次要明确new操作符做了哪些事情
创建一个空对象instance({})将instance的[[prototype]]属性指向构造函数fn的原型即instance.[[prototype]] fn.prototype也即instance的_ proto_要指向构造函数的原型prototype执行构造函数使用 call/apply 改变 this 的指向 让this指向创建出来的实例instance若函数返回值的是对象类型则作为new方法的返回值返回否则返回刚才创建的全新对象
function isObject (target) {return (typeof target object || typeof target function) target ! null
}
function myNew (fn, ...args) {// 使用Object.create(Y)就说明实例的__proto__指向了Y即实例的原型对象是Y// Object.create()创建一个新对象使用现有的对象来提供新创建的对象的__proto__// 并且执行[[Prototype]]链接; 通过new创建的每个对象将最终被[[Prototype]]链接到这个函数的prototype对象上。const instance Object.create(fn.prototype)// 改变this指向let res fn.apply(instance, args)// 若res是个对象就直接返回否则返回创建的对象// return res instanceof Object ? res : instancereturn this.isObject(res) ? res : instance
}如果不用new操作符直接调用那么构造函数就相当于普通函数了执行对象就 是window严格模式下为undefined即this指向了window严格模式下为undefined
由此可以看出构造函数内部this指向实例对象
2、super()的用法及注意点
1、用法 下面代码中B是A的子类B继承Asuper虽然代表了父类A的构造函数但是返回的是子类B的实例即super内部的this指的是B的实例 B里边的super()在这里相当于A.prototype.constructor.call(this) class A {constructor() {// new.target指向当前正在执行的函数console.log(new.target.name);}
}
class B extends A {constructor() {super();}
}
new A() // A
// 在super()执行时它指向的是子类B的构造函数而不是父类A的构造函数
// 即super()内部的this指向的是B的实例
new B() // Bnew.target指向被new调用的构造函数在普通的函数调用中函数调用new.target的值undefined在类的构造方法中new.target指向直接被new执行的构造函数 2、注意点
子类的构造函数constructor内必须执行一次super函数 这是因为子类自己的this对象必须先通过父类的构造函数完成塑造得到与父类同样的实例属性和方法然后再对其进行加工添加子类自己的实例属性和方法。如果不调用super()方法子类就得不到自己的this对象新建子类实例时父类的构造函数必定会先运行一次 在子类的构造函数中只有调用super()之后才可以使用this关键字否则会报错 super()调用之后才能让子类实例继承父类然后才能在该基础上对子类实例进行属于它的特有操作 不管有没有显示定义任何一个子类都有constructor()方法而且里边默认会调用super()作为构造函数时super()只能用于在子类的构造函数之中用在其他地方就会报错 使用super()的时候必须显示指定是作为函数还是作为对象使用否则会报错 由于对象总是继承其他对象的所以可以在任意一个对象中使用super关键字
四、super作为对象 super作为对象时在子类普通方法中指向父类的原型对象在子类静态方法中指向父类 1、super在子类普通方法中作为对象 当super作为对象在子类普通方法非静态方法中使用时由于super指向父类的原型对象所以定义在父类原型对象上的属性和方法都可以被访问到而定义在父类实例上父类构造函数this.xxx的方法或属性无法被访问到 在子类普通方法中通过super调用父类的方法时方法内部的this指向当前的子类实例相当于执行的是super.fn.call(this) 下面的代码中父类A有定义在原型对象的属性b和方法p()还有定义在实例对象的属性a可以看到的是定义在原型对象的b和p都能被super.访问到而定义在实例对象的a无法被访问到
class A {constructor() {this.a 123 // 定义在A的实例上的属性a}// 定义在A.prototype上的方法p() {return 2;}
}A.prototype.b 123 // 定义在A原型对象的属性bclass B extends A {constructor() {super();console.log(super.p()); // 2 相当于console.log(A.prototype.p())}getData() {console.log(super.a) // a定义在父类的实例对象上所以为undefinedconsole.log(super.b) // b定义在父类的原型对象上所以为123}
}let b new B();b.getData()在子类普通方法中通过super调用父类的方法时方法内部的this指向当前的子类实例相对于执行的是super.fn.call(this)
class A {constructor() {this.x 1; // 父类实例的x是1}print() {console.log(this.x);}
}class B extends A {constructor() {super();this.x 2; // 子类实例的x是2}m() {// 实际上执行的是super.print.call(this)super.print(); // 调用父类的方法但是方法内部this是子类实例所以输出2}
}let b new B();
b.m() // 2由于this指向子类实例所以如果通过super对某个属性赋值这时super就是this赋值的属性会变成子类实例的属性
class A {constructor() {this.x 1;}
}class B extends A {constructor() {super();this.x 2;super.x 3;console.log(super.x); // undefinedconsole.log(this.x); // 3}
}let b new B();上面代码中super.x赋值为3这时等同于对this.x赋值为3。而当读取super.x的时候读的是A.prototype.x所以返回undefined
2、super在子类静态方法中作为对象
当super作为对象在子类静态方法中使用时这时super将指向父类而不是父类的原型对象。在子类的静态方法中通过super调用父类的方法时方法内部的this指向当前的子类而不是子类的实例
class Parent {static myMethod(msg) {console.log(static, msg);}myMethod(msg) {console.log(instance, msg);}
}class Child extends Parent {static myMethod(msg) {// super作为对象在子类静态方法中使用super指向的是父类// 也即要调用父类的myMethod方法那就是父类的静态方法Parent.myMethod// 而属于一个类的方法就是静态方法也就是由static关键字定义的方法super.myMethod(msg); // 调用的是Parent.myMethod()}myMethod(msg) {// super作为对象在子类普通方法中使用super指向的是父类的原型对象// 此时的super.myMethod()也即Parent.prototype.myMethod()// 由class语法糖和原来构造函数创建类的写法相对比可知super.myMethod(msg);}
}Child.myMethod(1); // static 1var child new Child();
child.myMethod(2); // instance 2五、总结
通过本文的介绍我们了解了在ES6中使用extends关键字实现继承并且学习了super()在子类中的用法和作用以及注意点。super()的正确使用可以让我们更加方便地在子类中调用父类的构造函数和方法从而更加灵活地使用面向对象编程。希望本文能够帮助各个小伙伴更好地理解ES6中Class继承的super()关键字。