2019-11-29:
学习内容:
一、(1)class:
生成实例对象的传统方法:构造函数
ES6的class:
生成实例对象:var b = new Point(x, y)
构造函数的prototype
属性,在 ES6 的“类”上面继续存在。事实上,类的所有方法都定义在类的prototype
属性上面:(以下3种方式都一样)
(2)constructor 方法:
constructor
方法,这就是构造方法,而this
关键字则代表实例对象。constructor
方法默认返回实例对象(即this
),完全可以指定返回另外一个对象。
通过new
命令生成对象实例时,自动调用该方法。
(3)实例对象:
类的所有实例共享一个原型对象:xxx.prototype。 __proto__属性
假如Photo有两个实例p1和p2,对p的原型添加一个printName方法,p2也能使用,不推荐这么用。
(4)get 和set 关键字:
对定义的属性进行存值和取值函数,因此赋值和读取行为都被自定义了。
(5)用表达式写一个类:
需要注意的是,这个类的名字是Me
,但是Me
只在 Class 的内部可用,指代当前类。在 Class 外部,这个类只能用MyClass
引用。如果类的内部没用到的话,可以省略Me。
(6)注意点:
i、默认用严格模式。
ii、不存在提升,这个是和ES5生成实例对象最大的区别
iii、如果某个方法之前加上星号(*
),就表示该方法是一个 Generator 函数。
⚠️iiii、this 的指向:
避免如果将这个方法提取出来单独使用,this
会指向该方法运行时所在的环境(由于 class 内部是严格模式,所以 this 实际指向的是undefined
),应该将这个方法的this 绑定在构造函数中,或者用箭头函数(react就是利用这个)
iiiii、私有方法:没有给出实现方法,只有在方法名称前加 _ ,自我约束(类似于python)
(7)静态方法:
加static 关键字变成静态方法,实例用不了,但是子类可以,这个定义在ts也有。
(8)new.target 属性:
如果构造函数不是通过new
命令或Reflect.construct()
调用的,new.target
会返回undefined
,因此这个属性可以用来确定构造函数是怎么调用的。
能被实例:
Class 内部调用new.target
,返回当前 Class:
如果是继承的子类使用,new.target 返回子类的name。这样能限定一个类不能实例只能被(某一个子类)继承,更不能被实例:
二、class的继承:
(1)继承:
Class 通过 extend 关键字继承。
constructor
方法和toString
方法之中,都出现了super
关键字,它在这里表示父类的构造函数,用来新建父类的this
对象。
子类必须在constructor
方法中调用super
方法,否则新建实例时会报错。这是因为子类自己的this
对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。如果不调用super
方法,子类就得不到this
对象。
在子类的构造函数中,只有调用super
之后,才可以使用this
关键字,否则会报错。
(2)Object.getPrototypeOf() 方法:
该方法用于从子类获得父类,也能用于判断一个类是否继承了另一个类:
(3) super 关键字:
既可以当作函数使用,也可以当作对象使用。
i、super
作为函数调用时,代表父类的构造函数。ES6 要求,子类的构造函数必须执行一次super
函数。作为函数时,super()
只能用在子类的构造函数之中,用在其他地方就会报错。
假如A是父类,B继承了A,注意,super
虽然代表了父类A
的构造函数,但是返回的是子类B
的实例,即super
内部的this
指的是B
的实例,因此super()
在这里相当于A.prototype.constructor.call(this)
。
ii、super
作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。super
在普通方法之中,指向A.prototype
,所以super.p()
就相当于A.prototype.p()
。 由于super
指向父类的原型对象,所以定义在父类实例上的方法或属性,是无法通过super
调用的。
使用super
的时候,必须显式指定是作为函数、还是作为对象使用,否则会报错。例如:不能写 console.log(super)
(4)类的 prototype 属性和 __proto__ 属性:
ES5 中每一个对象都有__proto__
属性,指向对应的构造函数的prototype
属性。
Class 作为构造函数的语法糖,同时有prototype
属性和__proto__
属性,因此同时存在两条继承链。
(1)子类的__proto__
属性,表示构造函数的继承,总是指向父类。
(2)子类prototype
属性的__proto__
属性,表示方法的继承,总是指向父类的prototype
属性。
通过子类实例的__proto__.__proto__
属性,可以修改父类实例的行为。
(5)原生构造函数的继承:
原生构造函数是指语言内置的构造函数,通常用来生成数据结构。ECMAScript 的原生构造函数大致有下面这些。
- Boolean()
- Number()
- String()
- Array()
- Date()
- Function()
- RegExp()
- Error()
- Object()
ES6 允许继承原生构造函数定义子类,因为 ES6 是先新建父类的实例对象this
,然后再用子类的构造函数修饰this
,使得父类的所有行为都可以继承。
上面这个例子也说明,extends
关键字不仅可以用来继承类,还可以用来继承原生的构造函数。因此可以在原生数据结构的基础上,定义自己的数据结构。