前端JavaScript中的class类
⽬录
1、类
1.1 constructor()
1.2 getter和setter
1.3 this
1.4 静态属性
1.5 静态⽅法
2、继承
2.1 super关键字
2.2 _proto_和prototype
2.3 继承中的__proto__
2.4 继承实例中的__proto__
3、⼩结
1、类
类是⽤于创建对象的模板。JavaScript中⽣成对象实例的⽅法是通过构造函数,这跟主流⾯向对象语⾔(java,C#)写法上差异较⼤,如下:
function Point(x, y) {
this.x = x;
this.y = y;
}
String = function () {
return '(' + this.x + ', ' + this.y + ')';
};
var p = new Point(1, 1);
ES6提供了更接近Java语⾔的写法,引⼊了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。
如下:constructor()是构造⽅法,⽽this代表实例对象:
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
类的数据类型就是函数,它本⾝就是指向函数的构造函数:
// ES5 函数声明
function Point() {
//...
}
// ES6 类声明
class Point {
//....
constructor() {
}
}
typeof Point // "function"
Point === structor // true
在类⾥⾯定义的⽅法是挂到Point.prototype,所以类只是提供了语法糖,本质还是原型链调⽤。
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
Point.prototype = {
//....
toString()
}
var p = new Point(1, 1);
类的另⼀种定义⽅式类表达式
// 未命名/匿名类
let Point = class {
constructor(x, y) {
this.x = x;
this.y = y;
}
};
Point.name // Point
函数声明和类声明有个重要区别,函数声明会提升,类声明不会提升。
> let p = new Point(); // 被提升不会报错
> function Point() {}
>
> let p = new Point(); // 报错,ReferenceError
> class Point {}
>
1.1 constructor()
constructor()⽅法是类的默认⽅法,new⽣成实例对象时会⾃动调⽤该⽅法。
⼀个类必须有constructor()⽅法,如果没有显式定义,引擎会默认添加⼀个空的constructor() 。
constructor()⽅法默认返回实例对象(即this)。
class Point {
}
// ⾃动添加
class Point {
constructor() {}
}
1.2 getter和setter
与 ES5 ⼀样,在类的内部可以使⽤get和set关键字,对某个属性设置存值函数和取值函数,拦截该属性的存取⾏为。class User {
constructor(name) {
this.name = name;
}
get name() {
return this.name;
}
set name(value) {
this.name = value;
}
}
1.3 this
类的⽅法内部的this,它默认指向类的实例,在调⽤存在this的⽅法时,需要使⽤hod()⽅式,否则会报错。class User {
constructor(name) {
this.name = name;
}
printName(){
console.log('Name is ' + this.name)
}
}
const user = new User('jack')
user.printName() // Name is jack
const { printName } = user;
printName() // 报错 Cannot read properties of undefined (reading 'name')
如果要单独调⽤⼜不报错,⼀种⽅法可以在构造⽅法⾥调⽤bind(this) 。
class User {
constructor(name) {
this.name = name;
this.printName = this.printName.bind(this);
}
printName(){
console.log('Name is ' + this.name)
}
}
const user = new User('jack')
const { printName } = user;
printName() // Name is jack
bind(this) 会创建⼀个新函数,并将传⼊的this作为该函数在调⽤时上下⽂指向。
另外可以使⽤箭头函数,因为箭头函数内部的this总是指向定义时所在的对象。
class User {
constructor(name) {
this.name = name;
}
printName = () => {
console.log('Name is ' + this.name)
}
}
const user = new User('jack')
const { printName } = user;
printName() // Name is jack
1.4 静态属性
静态属性指的是类本⾝的属性,⽽不是定义在实例对象this上的属性。
class User {
}
User.prop = 1;
User.prop // 1
1.5 静态⽅法
可以在类⾥⾯定义静态⽅法,该⽅法不会被对象实例继承,⽽是直接通过类来调⽤。
静态⽅法⾥使⽤this是指向类。
class Utils {
static printInfo() {
this.info();
}
static info() {
console.log('hello');
}
}
Utils.printInfo() // hello
关于⽅法的调⽤范围限制,⽐如:私有公有,ES6暂时没有提供,⼀般是通过约定,⽐如:在⽅法前⾯加下划线_print()表⽰私有⽅法。
2、继承
Java中通过extends实现类的继承。ES6中类也可以通过extends实现继承。
继承时,⼦类必须在constructor⽅法中调⽤super⽅法,否则新建实例时会报错。
class Point3D extends Point {
constructor(x, y, z) {
super(x, y); // 调⽤⽗类的constructor(x, y)
this.z = z;
}
toString() {
String() + ' ' + this.z ; // 调⽤⽗类的toString()
javascript属于前端吗}
}
⽗类的静态⽅法,也会被⼦类继承
class Parent {
static info() {
console.log('hello world');
}
}
class Child extends Parent {
}
Child.info() // hello world
2.1 super关键字
在⼦类的构造函数必须执⾏⼀次super函数,它代表了⽗类的构造函数。
class Parent {}
class Child extends Parent {
constructor() {
super();
}
}
在⼦类普通⽅法中通过super调⽤⽗类的⽅法时,⽅法内部的this指向当前的⼦类实例。
class Parent {
constructor() {
this.x = 1;
this.y = 10
}
printParent() {
console.log(this.y);
}
print() {
console.log(this.x);
}
}
class Child extends Parent {
constructor() {
super();
this.x = 2;
}
m() {
super.print();
}
}
let c = new Child();
c.printParent() // 10
c.m() // 2
2.2 _proto_和prototype
初学JavaScript时, _proto_和prototype 很容易混淆。⾸先我们知道每个JS对象都会对应⼀个原型对象,并从原型对象继承属性和⽅法。
prototype ⼀些内置对象和函数的属性,它是⼀个指针,指向⼀个对象,这个对象的⽤途就是包含所有实例共享的属性和⽅法(我们把这个对象叫做原型对象)。
_proto_ 每个对象都有这个属性,⼀般指向对应的构造函数的prototype属性。
下图是⼀些拥有prototype内置对象:
根据上⾯描述,看下⾯代码
var obj = {} // 等同于 var obj = new Object()
// obj.__proto__指向Object构造函数的prototype
obj.__proto__ === Object.prototype // true
// String 调⽤⽅法从Object.prototype继承
// 数组
var arr = []
arr.__proto__ === Array.prototype // true
对于function对象,声明的每个function同时拥有prototype和__proto__属性,创建的对象属性__proto__指向函数prototype,函数
的__proto__⼜指向内置函数对象(Function)的prototype。
function Foo(){}
var f = new Foo();
f.__proto__ === Foo.prototype // true
Foo.__proto__ === Function.prototype // true
2.3 继承中的__proto__
类作为构造函数的语法糖,也会同时有prototype属性和__proto__属性,因此同时存在两条继承链。
⼦类的__proto__属性,表⽰构造函数的继承,总是指向⽗类。
⼦类prototype属性的__proto__属性,表⽰⽅法的继承,总是指向⽗类的prototype属性。
class Parent {
}
class Child extends Parent {
}
Child.__proto__ === Parent // true
Child.prototype.__proto__ === Parent.prototype // true
2.4 继承实例中的__proto__
⼦类实例的__proto__属性,指向⼦类构造⽅法的prototype。
⼦类实例的__proto__属性的__proto__属性,指向⽗类实例的__proto__属性。也就是说,⼦类的原型的原型,是⽗类的原型。
class Parent {
}
class Child extends Parent {
}
var p = new Parent();
var c = new Child();
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论