什么是类:
在ES6中新增加了类的概念,可以使用class
关键字声明一个类,
之后以这个类来实例化对象。类抽象了对象的公共部分,它泛指
某一大类( class )对象特指某一个,通过类实例化一个具体的对象
表面看起来可以支持正式的面向对象编程,但实际上它背后使用的仍然
是原型和构造函数的概念
。
同时class类是构造函数的【语法糖
】
一、类定义
//1. 匿名类
let Example = class {};
//2.命名类
let Example = class Example {};
//3.类声明
class Example {}
//不可以重复声明一样的名字,如果同时声明一个的类名会报错
二、类不会被提身,他不具备变量提升
class Example {}
let wq = new Example();
//在声明一个类时,必须是先声明一个类,再去实例这个类对象
//不能是先实例这个类对象,再去声明这个类,他不具备提升作用
//跟构造函数作比较
let star = new Star();
function Star() {}
//构造函数具备变量提升,其实是function函数具备变量提升,构造函数可以先实例对象,在声明构造函数
三、创建类和添加方法
class Sxample {
constructor(uname, age) {
this.uname = uname;
this.age = age;
}
show(money) {
console.log(this.uname + money);
}
artistic(talent) {
console.log(this.uname + talent);
}
}
var example1 = new Sxample("王总", 18);
var example2 = new Sxample("王老板", 28);
console.log(example1.uname, example1.age);
console.log(example2.uname, example2.age);
example1.show("很有钱");
example2.artistic("很有钱");
/*
知识要点:
1.类constructor构造函数:
constructor()方法是类的构造函数(默认方法),用于传递参数返回实例对象,
通过new命令生成对象实例时,自动调用该方法。如果没有显示定义,类内部会自动给拽们创建一个constructor
2.总结要点
(1) 通过class 关键字创建类,类名我们还是习惯性定义首字母大写
(2) 类里面有个constructor函数,可以接受传递过来的参数,同时返回实例对象
(3) constructor函数只要new生成实例时,就会自动调用这个函数,如果我们不写这个函数,类也会自动生成这个函数
(4) 生成实例 new 不能省略(这个new干了些啥)
1.在内存中创建了一个新对象
2.这个新对象内部的[[Prototype]]指针被赋值为构造函数的prototype属性
3.构造函数内部的this被赋值为了这个新对象(即this指向新对象)
4.执行构造函数内部的代码(给新对象添加属性)
5.如果构造函数返回非空对象,则返回该对象:否则,返回刚创建的新对象
(5) 最后注意语法规范,创建类,类名后面不要加小括号,生成实例类名后面加小括号,构造函数不需要加function
(6) 我们类里面所有的函数不需要写function
(7) 多个函数方法之间不需要添加逗号分隔
*/
四、(extends、super)类的继承
//1.extends
class Father {
constructor() {}
money() {
console.log(10000 + "元");
}
}
class Son extends Father {
/*money() {
console.log('我自己有100块钱');
}*/
money1() {
console.log(100 + "元");
}
}
var son = new Son();
son.money();
son.money1();
/*
知识要点:
// 继承中的属性或者方法查找原则:就近原则
// 1.继承中,如果实例化子类输出一个方法,先看子类有没有这个方法,如果有就先执行子类的
// 2.继承中,如果子类里面没有,就去查找父类有没有这个方法,如果有,就执行父类的这个方法(就进原则)
*/
//2.super调用父类的构造函数----------------------------------------------------------
class Father {
constructor(x, y) {
this.x = x;
this.y = y;
}
sum() {
console.log(this.x + this.y);
}
}
class Son extends Father {
constructor(x, y) {
super(x, y);
this.x = x;
this.y = y;
}
}
var son = new Son(1, 2);
son.sum();
//3.super调用父类的普通函数----------------------------------------------------------
class Father {
constructor(uname) {
this.uname = uname;
}
say() {
return "我是爸爸";
}
}
class Son extends Father {
constructor(uname) {
super(uname);
}
say() {
console.log("我是儿子");
console.log(super.say() + "的儿子" + this.uname);
}
}
var son = new Son("张三");
son.say();
/*
知识要点:
(1).super关键字用于访问和调用对象父类上的函数。可以调用父类的构造函数,也可以调用父类的普通函数
(2)使用super时要注意几个问题(*代表比较常用的注意事项)
1.super()只能在子类构造函数和静态方法内使用
2.不能单独引用super()关键字,要么用它调用构造函数,要么用它引用静态方法 *
3.调用super()会调用父类构造函数,并将返回实例赋值给this *
4.super()的行为如同调用构造函数,如果需要给父类构造函数传参,则需要手动传入
5.如果没有定义类构造函数,在实例化派生类时会调用super(),而且会传入所有传给子类的参数
6.在类构造函数中,不能调用super()之前引用this *
7.如果在子类中显示定义了构造函数,则要么必须在在其中调用super(),要么必须在其中返回一个对象
*/
五、子类继承父类方法同时扩展自己的方法
// 父类有加法方法
class Father {
constructor(x, y) {
this.x = x;
this.y = y;
}
sum() {
console.log(this.x + this.y); //8
}
}
// 子类继承父类加法方法 同时 扩展减法方法
class Son extends Father {
constructor(x, y) {
// 利用 super 调用父类的构造函数
// super 必须在子类this之前调用 但也可以省略掉this的操作
super(x, y);
//this.x = x;
//this.y = y;
}
subtract() {
console.log(this.x - this.y); //2
}
}
var son = new Son(5, 3);
son.sum();
son.subtract();
六、类遵循严格模式
什么是严格模式:
JavaScript除了提供正常模式外,还提供了严格模式。ES5的严格模式是采用具有限制性
JavaScript变体的一种方式,即在严格的条件下运行的JS代码
严格模式在IE10以上版本的浏览器中才会被支持,旧版本浏览器中会被忽略
怎么开启严格模式:
【为函数开启严格模式】两种情况
一、为脚本开启严格模式
为整个脚本文件开启严格模式,需要在所有语句之前放一个特定语句 “use strict”;(或 ‘use strict’)
二、为函数开启严格模式
要给某个函数开启严格模式,需要把 “use strict”;(或 ‘use strict’;)声明放在函数体所有语句之前
//1.没有开启严格模式时,里面的this指向是window
function fn() {
console.log(this); //window
}
fn();
//2.当开启严格模式时,里面的this指向是undefined
function fn() {
"use strict";
console.log(this); //undefined
}
fn();
//3.而class类默认是在严格模式下
class Star {
show() {
function uname() {
console.log(this);//undefined
}
uname();
}
}
var star = new Star();
star.show();
七、类的静态属性
//1.构造函数里的静态成员和实例成员
function Star(uname, age) {
this.uname = uname;
this.age = age;
// this.show = function () {
// console.log("我是实例成员");
// };
}
var star = new Star("王总", 18);
console.log(star.uname);
console.log(Star.uname); //实例成员不可以通过构造函数来访问
// star.show();
Star.sex = "男";
console.log(star.sex); //静态成员不可以通过对象来访问
console.log(Star.sex);
Star.prototype.show = function () { //通过prototype来添加方法知识优化了在里面添加方法,但实际他还是要通过实例对象来访问这个函数法法
console.log("我是通过原型的方法");
};
star.show(); //通过实例来访问
star.__proto__.show = function () {
console.log("我是方法");
};
star.show(); //通过实例来访问
console.log(star);
/*
知识要点:
构造函数的静态成员和实例成员
(1)静态成员:在构造函数本上添加的成员称为静态成员,只能由构造函数本身访问
1.静态成员 在构造函数本身上添加成员
2.静态成员 只能通过构造函数来访问
(2)实例成员:在构造函数内部创建对象成员称为实例成员,只能由实例化的对象来访问
1.实例成员就是构造函数内部通过this添加的成员 uname、age、sing 就是实例成员
2.实例成员只能通过实例化的对象来访问
*/
//2.类里面的静态
class Star {
constructor(uname, age) {
this.uname = uname;
this.age = age;
}
show() {
console.log("我原型对象是" + this.uname);
}
static sing(uname) {
console.log("我原型对象是" + uname);
}
}
var star = new Star("王总", 18);
var star1 = new Star("王老板");
star.show();
Star.sing("王老板");
//3.子类的静态方法能够通过super来调用父类的静态方法
class Person {
static getName() {
return "lear";
}
}
class Student extends Person {
static getName2() {
return super.getName() + ",hi";
}
}
console.log(Student.getName2());
/*
类里面的静态属性——[static]
1.class本身的属性,即直接定义在类内部的属性(Class.propname),
不需要实例化。 ES6 中规定,Class 内部只有静态方法,没有静态属性。
2.静态方法通常用于执行不特定于实例的操作,也不要求存在类的实例于
原型成员类似,静态成员每个类上只能有一个
3.静态类成员在类定义中使用static关键字作为前缀,在静态成员中,
this引用自身。其他所有约定跟原型成员一样。
*/
八、把类当成一个特殊函数,类的是返回对象
// 1.通过typeof操作符检测类标识符,表明它是一个函数
class Person {}
console.log(Person);
console.log(typeof Person); //function
// 2.类标识有prototype属性,而这个原型也有一个constructor属性指向类自身
class Person1 {}
console.log(Person1.prototype); //{constructor: ƒ}
console.log(Person1 === Person1.prototype.constructor); //true
// 3.与普通函数一样,可以使用instanceof操作符检查构造函数原型是否存在于实例的原型链中
class Person2 {}
var p = new Person2();
console.log(p instanceof Person2); //true
/*
4.由此可知,可以使用instanceof操作符检查一个对象与构造函数,以确定这个对象是不是类
的实例。只不过此时的构造函数要使用标识符,比如前面的例子中要检查p和Person2如前所述
,类本身具有与普通构函数一样的行为,在类的上下文中.类本身在使用new调用时就会被当成
构造函数。重点在于,类中定义的 constructor 方法【不会】被当成构造函数,在对它使用
instanceof操作符时会返回false但是,如果在创建实例时直接将类构造函数当成普通构造函
数来使用,那么instanceof操作符的返回值会返回ture
*/
class Person3 {}
var p3 = new Person3();
console.log(p3.constructor === Person3); //true
console.log(p3 instanceof Person3); //true
console.log(p3 instanceof Person3.constructor); /false
var p4 = new Person3.constructor();
console.log(p4.constructor === Person3); //false
console.log(p4 instanceof Person3); //false
console.log(p4 instanceof Person3.constructor); //true
九、实例化对象共享原型对象
// 1.构造函数共享
function Person(uname, age) {
this.uname = uname;
this.age = age;
this.sing = function () {
console.log("我在里面创建");
};
}
Person.prototype.show = function () {
console.log("我是原型链");
};
var wz = new Person("王总", 18);
var zh = new Person("张总", 28);
wz.sing();
zh.sing();
wz.show();
zh.show();
console.log(wz.sing === zh.sing); //false
console.log(wz.show === zh.show); //true
console.log(star.__proto__ === star1.__proto__); //true
// 2.类的共享
class Example {
constructor(a, b) {
this.a = a;
this.b = b;
}
sum() {
return this.a + this.b;
}
}
Example.prototype.sub = function () {
console.log("我是原型对象");
};
let exam1 = new Example(2, 1);
let exam2 = new Example(3, 1);
console.log(exam1.sum === exam2.sum); //true
console.log(exam1.sub === exam2.sub); //true
// 类的所有实例共享一个原型对象。
console.log(exam1.__proto__ === exam2.__proto__); //true
十、类是一个块级作用域
{
function fn() {
console.log("我可以被外面给获取到");
}
class Star {
show() {
console.log("我不能被我们给获取到");
}
}
}
fn();
var star = new Star(); // ReferenceError: Star is not defined
star.Star();