1. 概述
是ES5中构造函数的变种,结构清晰,类似于强语言,类型是function(constuctor构造函数)。
普通函数属于构造函数,可以使用new方法来创建;但箭头函数不可以使用new方法来创建,因为它没有this环境。那就来验证一下吧!
function fn(){
this.age = 22;
var a = 3 , b = 4;
console.log('已调用');
return a + b;
}
console.log(fn()); //打印'已调用' 打印7
const gn = new fn(); //打印'已调用'
console.log(gn); //fn {age: 22}
const xn = ()=>{return 'hihi'};
console.log(xn()); //hihi
const x1 = new xn(); // x is not a constructor
2. 特性(同let)
a. 没有变量提升,也称为暂时性死去。也就是说不能先使用在定义,会报错
b. 具有块级作用域。可以理解为只在{ }内运行代码,不会访问到外面的代码
c. 同一作用域内不能声明同名变量,会报错‘该类名已经被声明了
总结:var let const的区别
var :会提前声明(可以先访问,打印为undefined,后面再声明)
没有块级作用域(函数才有作用域)
可以重复声明两个一样的变量,对业务来说是不好区分的
let:不会隐式声明提升
具有块级作用域
同一作用域内不能重名,会报错
{
let a = 100;
var b = 23;
}
console.log(b); //23
console.log(a); // a is not defined
const:同let,但初始化后不能更改值,声明的同时就要初始化(赋值)
3. 创建类
语法:class 类名 { }
4. 类的使用
1. 通过类,实例化一个对象
2. 如果想要传参,需要手动在类里面写一个构造函数
每个类里面只能存在一个constructor构造函数,如果不写,类在底层会自动添加一个空的构造函数,以保证类的正确运行
复习:构造函数new关键字的步骤
1. 创建一个新对象
2. 将this指向这个新对象,this的到的是新对象的引用地址
3. 将新对象的__proto__指向构造函数的protype属性
4. 执行这个构造函数
5. 返回this 新对象得到的this的引用地址
3. 类里面的constructor里面的this指向新的实例对象
下例中,xzq通过new Person1()创建,所以this指向了xzq,那后面调用constructor里面的函数时,通过xzq来调用,而不是Person1。
class Person1 {
constructor(name,age,job){
this.name = name;
this.age = age;
this.job = job;
this.sayJob = function(){
console.log(this.job);
}
}
}
const xzq = new Person1('xzq',40,'singer');
console.log(xzq);//Person1 {name: 'xzq', age: 40, job: 'singer', sayJob: ƒ}
xzq.sayJob(); //singer
4. 使用new关键字创建一个对象的时候,new一次就会调用一次constructor函数。
在普通函数里面,我们可以在函数内部直接写一个没有声明的变量,并且给它赋值,函数外面的代码是可以访问到该函数里面的这个变量的。
function Per(name, age) {
count = 9;
this.name = name;
this.age = age;
count = 9;
}
const xuegao = new Per('小雪糕',4)
console.log(xuegao); //Per {name: '小雪糕', age: 4}
但如果在全局里面使用严格模式的话,访问这个没有声明的变量会报错。
'use strict';
function Per(name, age) {
this.name = name;
this.age = age;
count = 9;
}
const xuegao = new Per('小雪糕',4)
console.log(xuegao); //count is not defined
在class类的构造函数内的语法,默认使用的是严格模式('use strict'),所以不能在里面写count=1,会出现上面一样的错误。
class Cat {
constructor(name,age){
this.name = name;
this.age = age;
count = 1; //count is not defined
}
}
const mijiu = new Cat('mijiu',3);
console.log(mijiu); //Cat {name: 'mijiu', age: 3}
注意:一般情况下constructor函数内写的代码是用来给新对象添加属性和方法的,尽量不要在这里面写其他不相关的代码
5. 类原型方法
定义:写在constructor之外的方法,称为类原型(原型对象)上的方法
如果用 = 赋值,虽然是写在constructor之外,但相当于是写在构造函数内部,属于实例对象本身的方法。
class Dog {
//写在constructor之外的方法,为Dog原型(Prototype)上的方法
sayName() {
console.log(this.name);
}
constructor(name, age) {
this.name = name;
this.age = age;
}
//虽然写在constructor之外,但使用等号赋值,所以属于实例对象本身的方法
sayAge = function () {
console.log(this.age);
}
hairColor = 'yellow';
}
const gangya = new Dog('钢牙', 4);
console.log(gangya); //Dog {hairColor: 'yellow', name: '钢牙', age: 4, sayAge: ƒ}
//没有出现sayName,它在原型对象里面
console.log(gangya.sayName()); //undefined 函数没有返回值,所以返回undefined
6. 类自己的方法(静态方法)
使用static关键字声明的,都属于类自己的方法,也就是说控制台打印时,这个方法名会出现在类的原型对象中。
class Cat {
constructor(name, age) {
this.name = name;
this.age = age;
}
static hairColor = 'grey'; //类自己的方法,控制台中它出现在类的原型对象中[[Prototype]]:Object constructor: class Cat hairColor: "grey"
static sayName() {
console.log('sayName');
}
}
const mijiu = new Cat('米酒', 3);
console.log(mijiu); Cat {name: '米酒', age: 3};
console.log(Cat.sayName()); // 打印sayName 打印'类的方法'
console.log(mijiu.sayName()); //报错:jiu.sayName is not a function
//因为static声明的方法是类自己方法,不是实例对象的。所以调用时需要用类名去调用,不能用实例对象去调用
调用类的方法时,要是用类名去调用,而不是实例对象。
7. 类的继承
1. 子类要继承父类,使用关键字extends,语法:class 子类名 extends 父类名 { }
2. 在子类使用this之前需要使用super()去调用父类的constructor构造函数
3. 子类只能继承一个父类,而父类可以有多个子类继承
4. 子类继承一个父亲,将会拥有父类的所有属性和方法(实例、类原型对象、静态)
class Tv{
constructor(name) {
this.name = name;
}
sayName(){
console.log(this.name);
}
static sayName(){
console.log('Tvshow');
}
}
class Movie extends Tv{
constructor(actor){
super();
this.name = actor;
}
}
const bnpa = new Movie('保你平安');
bnpa.sayName(); //打印'保你平安' 实例对象的方法
Movie.sayName(); //打印'Tvshow' 类的方法