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
搞不懂,先记下来吧