一.类的简介
类的由来
- 在js中,生成实例对象的传统方法是通过构造函数,如下所示
function Point(x,y){
this.x=x;
this.y=y;
}
Point.prototype.toString=function(){
return '('+this.x+','+this.y+')'
}
var one=new Point(1,2)
console.log(one.toString());
class Person{
constructor(x,y) {
this.x=x;
this.y=y;
}
toString(){
return '('+this.x+','+this.y+')'
}
}
var two=new Person(3,4)
console.log(two.toString());
在本质上,类的数据类型就是函数,类本身就是指向自身的构造函数
本质上,类的所有方法都是定义在类的prototype属性上面
也就是说,类的实例的constructor===类的原型的constructor
class Point{}
console.log(typeof Point)
console.log(Point===Point.prototype.constructor)
console.log(new Point().constructor === Point.prototype.constructor)
class Other{
constructor(name) {
this.name=name;
}
toValue(){
return this.name+'原型链上'
}
}
var one=new Other('hh')
console.log(one.toValue())
类内部定义的方法默认都是不可枚举的!外部使用原型定义的方法默认是可以枚举的
class Other{
constructor() {
}
toValue(){
return this.name+'原型链上'
}
}
Other.prototype.getData=function(){}
console.log(Object.keys(Other.prototype))
constructor构造器方法
constructor方法是类的默认方法,在通过new命令生成对象实例时,会自动调用该方法
- 一个类是默认具有constructor方法的,即使没有显示声明,但是会默认具有一个空的constructor方法
constructor方法默认会返回类的实例对象,但是可以显式使用return返回其他
class One{}
console.log(new One())
class Two{
constructor(){}
}
console.log(new Two())
class Three{
constructor(){
console.log('构造器')
}
}
console.log(new Three())
class Four{
constructor(){
return {name:'a',age:10}
}
}
console.log(new Four())
类和函数的一个区别在于,类必须使用new调用否则会报错!而函数不需要使用new也可以执行
但是对于类的实例方法,可以直接用类去调用
class Func{
static a(){
return 'ddds'
}
}
console.log(Func.a())
类的实例
类的实例的属性都是定义在原型上的。除非类在构造器声明了!
class Point{
constructor(x,y){
this.x=x;
this.y=y;
}
a(){
return '定义在原型链上'
}
}
var p=new Point(2,3)
console.log(p.hasOwnProperty('x'))
console.log(p.hasOwnProperty('y'))
console.log(p.hasOwnProperty('a'))
console.log(p.__proto__.hasOwnProperty('a'))
class Point{}
var one=new Point()
var two=new Point()
console.log(one.__proto__===two.__proto__)
one.__proto__.add=function(){
return 'add'
}
console.log(one.add())
console.log(two.add())
getter和setter
在类内部可以使用get和set关键字,对某个属性设置存值函数和和取值函数
set和get函数都是设置在函数的Descriptor对象上的
class one{
a='使用getter,setter函数'
get a(){
return this.a;
}
set a(val){
this.a=val;
}
}
var p=new one()
console.log(p.a)
p.a='改变'
console.log(p.a)
var desc=Object.getOwnPropertyDescriptor(one.prototype,'a')
console.log(desc)
console.log('get' in desc)
console.log('set' in desc)
class表达式
- class类也可以使用表达式的形式定义,需要注意的是:
var outer=class inner{
getName(){
return inner.name;
}
}
var c=new outer()
console.log(c.getName())
另外还有一种立即执行的class表达式,但是不可取,使用频率太低
let person=new class{
constructor(name) {
this.name=name;
}
getName(){
console.log(this.name)
}
}('yiye')
person.getName()
注意点
只要在类或者模块中,那么默认就是严格模式,不需要使用'use strict'来指定运行模式
类中不存在变量提升(因为必须保证子类在父类的后面!)
class one{}; class two extends one{};
类也具有函数的name属性,可以通过类.name来获取类的名称
- 类的 [Symbol.iterator]方法默认就是类被循环时使用的迭代器
class Point{
constructor(...args) {
this.args=args
}
*[Symbol.iterator](){
for(let arg of this.args){
yield arg;
}
}
}
var p=new Point(1,3,'d')
for(var item of p){
console.log(item);
}
this的指向需要额外注意,this默认指向类的实例,但是有时会报错
class one{
constructor(name) {
this.name=name;
}
getName(){
return this.name;
}
}
var a=new one('yiye')
var {getName}=a;
var name='hh'
console.log(getName())
- 因为超出字数限制,所以分多次发~
注意点:由于之前没有注意类名首字母要大写的规范,所以修改过一次,上面代码如果有问题就看看类名
本文参考阮一峰ES6教程