1.类的由来
说明: js中生成实例对象的方法是通过构造函数方法实现。
function Add(x, y) {
this.x = x
this.y = y
}
Add.prototype.talk = function () {
return this.x + this.y
}
const obj1 = new Add(1, 2)
console.log(obj1.talk()); //3
2.ES6中class
说明:事实上,ES6的class看一一个语法糖,新的写法让对象原型的写法更加清晰,更像面向对象编程的语法而已。
class Add1 {
constructor(x, y) {
this.x = x
this.y = y
}
talk() {
return this.x + this.y
}
}
const obj2 = new Add1(1, 2)
console.log(obj2.talk()); //3
注意:定义了一个类,里面有个constructor方法,称为构造方法,this代表实例对象。类里面也定义了一个方法,可以省略function,直接将函数定义进去。
3.类数据类型是函数
说明:实际上,类的数据类型其实是函数,类本身指向构造函数,使用方法跟构造函数的用法完全一致。
class Fun {
}
console.log(typeof Fun); //function
console.log(Fun.prototype.constructor === Fun); //true
3.1类的方法
说明:类的所有方法都定义在类的prototype属性上面。
class Fun1{
constructor(){
}
good(){
}
talk(){
}
}
Fun1.prototype={
constructor(){
},
good(){
},
talk(){
}
}
注意:上面的代码其实是等价的。
3.2类的原型
说明:由于类的方法都定义在prototype对象上面,所以类的新方法可以添加prototype对象上面。
class Fun2 {
}
Object.assign(Fun2.prototype, {
love() {
console.log("Studying Web");
},
life() {
}
})
const obj3 = new Fun2()
obj3.love() //Studying Web
注意:类内部方法所有定义的方法,都是不可枚举的。
4.constructor方法
说明:constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法,一个类必须有construcotor方法,没有都会自动添加的。
class Fun3{
}
class Fun3{
constructor(){
}
}
注意: 上面的代码时等价的。
5.类的实例
说明:类的属性和方法,除非显示定义在其本身(显示定义就是定义在实例对象上),否则都是定义在原型上(即定义在class上)。
class Fun4 {
constructor(x, y) {
this.x = x
this.y = y
}
good() {
console.log("Entertain" + "传入的值是" + this.x, this.y);
}
}
const obj4 = new Fun4(5, 2)
obj4.good()//Entertain传入的值是5 2
console.log(obj4.hasOwnProperty("x")); //true
console.log(obj4.hasOwnProperty("good")); //false
console.log(obj4.__proto__.hasOwnProperty("good")); //true
注意:所有说类中的方法是定义在原型链上的,而非显示定义在实例对象上,实例对象能够访问是因为通过原型链进行查找。
6.实例属性的新写法
说明:实例属性除了定义在constructor方法里面的this上面,也可以定义在类内部的最顶层。
// 以前写法
class Fun5 {
constructor(x) {
this.x = 0
}
}
class Fun6 {
_x = 0;
}
const obj6 = new Fun6()
const obj5 = new Fun5()
console.log(obj6._x); //0
console.log(obj5.x); //0
注意: 上面的代码结果是相同的。
7.getter和setter
说明:类的内部可以使用get和set关键字,对某个属性设置存值函数和取值函数,拦截该属性的存取行为。
class Fun7 {
constructor() {
}
get prop() {
console.log("获取值");
}
set prop(value) {
console.log("value:" + value);
}
}
const obj7 = new Fun7()
obj7.prop //获取值
obj7.prop = "李四" //value:李四
8.属性表达式
说明:类的属性名,可以采用表达式。
const methodGood = "getName"
class Fun8 {
[methodGood]() {
console.log("我是getName方法");
}
}
const obj8 = new Fun8()
obj8[methodGood]() //我是getName方法
9.Class表达式
说明:类也可以用表达式的形式定义。
const obj9 = new class {
constructor(name) {
this.name = name
}
tell() {
console.log("我的名字是:" + this.name);
}
}("李四").tell() //我的名字是:李四
注意:new class相当于一个函数,李四是传入的参数,tell是里面的方法。
10.静态方法,静态属性
说明:如果在一个方法前,加上static关键字,表示该属性和方法不会被实例继承,而是直接通过类的调用,称为静态方法。
class Fun10 {
static name = 3
}
const obj10 = new Fun10()
console.log(Fun10.name); //3
console.log(obj10.name);//undefined
注意:如果静态方法包含this关键字,整个this指的是类,而不是实例,静态方法和非静态方法可以重名。
10.1.父类的静态方法,可以被子类继承。
class Father {
static talk() {
console.log("I'am father");
}
}
class Child extends Father {
}
Child.talk() //I'am father
10.2.静态方法也是可以从super对象上调用的.
class Father1 {
static talk() {
console.log("I'am father1");
}
}
class Child1 extends Father1 {
constructor() {
}
static talk() {
super.talk()
}
}
Child1.talk() //I'am father1
11.私有方法和私有属性
说明:方法是在属性名之前使用#表示。
class Fun11 {
#name = "李四"
#talk() {
console.log("我的名字是" + this.#name);
}
}
const obj11 = new Fun11()
// console.log(obj11.#name); // Private field '#name' must be declared in an enclosing class
注意:私有属性也可以设置getter方法和setter方法; 私有属性和私有方法也可以加上static关键字。如下面代码
class Fun12 {
static #name = "王二"
}
const obj12 = new Fun12()
//console.log(Fun12.#name); //Private field '#name' must be declared in an enclosing class
12. in运算符
说明: try...catch结构可以判断某个私有属性是否存在,可读性很差。现在in运算符可以判断。
class Fun13{
#name="张三"
#talk(){
console.log("私有方法");
}
judege(){
console.log(#name in this);
}
}
const obj13=new Fun13()
obj13.judege() //true
console.log("#name" in obj13); //false
说明:私有属性虽然外面不能访问,但是定义类的里面,可以访问,私有属性虽然外面不能访问,但是定义类的里面,可以访问。
13.静态块
说明:静态块作用是进行初始化。
class Fun14{
static x=10
static{
this.x //10
Fun14.x //10
}
}
注意:静态块内部可以使用类名或this,指代当前类。
14.类的注意点
- ES6实际上把整个语言升级到严格模式。
- 不存在提升。
- 具有name属性指向类名(函数名)。
- this的指向,一般指向类的实例。