类的本质
类的本质其实还是一个函数,我们也可以简单的认为,类就是函数的另外一种写法
创建方法
class name {
// class body
}
在类里添加函数
class name {
// class body
函数名称(){}
}
// 使用: 对象名.函数名称(参数);
利用类创建对象
var 对象名 = new name();
利用类创建的对象使用类里的方法
对象名.类里的方法名(传参)
类 constructor 构造函数
- consrtuctor() 方法是类的构造函数(默认方法)
- 可以接受传递参数,同时返回实例对象,通过 new 命令生成对象实例时,自动调用该方法。
- 如果没有显式定义,类内部会自动给我们创建一个 constructor(){};
语法规范
- 类名首字母大写
- 生成实例new不能省略
- 创建类的时候,类名后面不要加小括号
- 生成实例,类名后面加小括号
- 构造函数不需要加function
注意
在ES6中类没有变量提升,所以必须先定义类,才能通过类实例化对象
类里面的公有的属性和方法一定要加 this 使用
this的指向问题
-
constructor 里 this 指向的是创建的实例对象
-
方法里面的 this 指向这个方法的调用者
封装
- 封装的访问主要是一种君子约定
- _变量名 的数据只能在类里面访问
- get / set 实现对私有变量的封装
- 真正实现数据的私有需要用到ES6的Proxy
class 类名{
constructor(参数1,参数2){
this._参数1 = 参数1;
this.参数2 = 参数2;
}
set 参数2(value){ //限定条件 }
get 参数2(){ return this._参数2 }
}
类的继承
extends关键字
//父类:
class Father { }
//子类继承父类
class Son extends Father { }
super关键字
该关键字用于访问和调用对象父类上的函数。可以调用父类的构造函数,也可以调用父类的普通函数
class Son extends Father {
constructor(形参){
super(形参);
}
}
子类调用父类的构造函数方法
- 子类传参给子类的constructor
- super关键字再把接收的形参传给父类的constructor
- 父类的constructor方法运行
- 传给子类
子类调用父类的普通函数
-
就近原则,子类有就用子类的,子类没有就调用父类的
-
在子类中调用父类的方法
super.父类的方法名()
子类在构造函数中使用 super ,必须放在 this 前面
必须先调用父类的构造方法,在使用子类构造方法
子类扩展父类的方法
class Son extence Father{
constructor(参数1,参数2) {
super(参数1,参数2);// 调用父类方法
this.参数1 = 参数1;
this.参数2 = 参数2;
}
子类扩展方法名() {
console.log(this.参数1,this.参数2);
}
}
静态 static
在一个方法或者属性前,加上 static 关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。
如果静态方法包含this关键字,这个this指的是类,而不是实例。
静态属性
static.静态属性名 = 值
静态方法
static.静态方法名 = function() {}
// 调用
父类名.静态方法名();
私有
私有方法和私有属性,是只能在类的内部访问的方法和属性,外部不能访问
// 私有属性
#属性名 = 值
// 私有方法
#方法名 = function() {}
ES6之前并没有给我们提供 extends 继承,可以通过 构造函数+原型对象 模拟实现继承,被称为组合继承
fun.call(this A如果,arg1,arg2.....)
// 调用这个函数,并且修改函数运行时的 this 指向
// thisArg : 当前调用函数this的指向对象
// arg : 传递的其他参数
用父级构造函数继承属性,通过call()改变this指向
子构造函数内部{ father.call(this,参数1,参数2....) }
// 不能这样写 : Son.prototype = Father.prototype
// 这样子类修改 prototype 的同时也会修改父类的 prototype
造一个新爹,子类修改新爹的 prototype ,在让新爹的 prototype 指向 son
Son.prototype = new Father();
Son.prototype.constructor = Son;
创建对象
利用 new Object()
var 名字 = new Object();
利用对象字面量创建对象
var 名字 = { 内容 }
构造函数创建对象
function 构造函数名(形参){
this.属性(形参) = 值;
this.方法 = function ( ) { }
}
构造函数名首字母要大写
构造函数不需要 return 就可以返回结果
构造函数创建对象的使用 var 名字 = new 构造函数名(value,value,value)
属性
function 构造函数名(形参){
this.属性(形参) = 值,
writable:false,
configurable:true,
enumerable:true
}
writable 能不能修改这个值
configurable 能不能删除这个值
enumerable 能不能迭代这个
构造函数
构造函数是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值。把公共的属性和方法抽取出来,封装到这个函数里。
注意:构造函数存在浪费内存的问题,用原型对象解决(写在原型对象里)
语法规范
名称首字母大写,与 new 一起使用
new关键字执行时顺序
- 在内存中创建一个新的空对象
- 让 this 指向这个对象
- 执行构造函数里面的代码,给这个新对象添加属性和方法
- 返回这个新对像(构造函数不需要return)
构造函数中的属性和方法成为之成员
-
静态成员
在构造函数本身上添加的成员
构造函数名.静态成员名 = 值;
只能通过构造函数来访问 -
实例成员
构造函数内部通过 this 添加的成员
只能通过实例化的对象来访问
function 构造函数名(){
this.实例成员名 = 值
}
JavaScript 的成员查找机制(规则)
-
当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性
-
如果没有就查找它的原型(proto 指向的 prototype 原型对象)
-
如果还没有就查找原型对象的原型(Object的原型对象)
-
一直查找到 Object 为止(null)
原型对象 prototype
- 每一个构造函数都有一个 prototype 属性,指向另一个对象。
- 这个 prototype 就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有
- 可以把那些不变的方法,直接定义在 prototype 上,这样所有对象的实例都可以共享这些方法
- this 指向实例对象
- 原型的作用是共享方法
// 在prototype里追加一个方法
构造函数名.prototype.函数名 = function( ){ }
// 覆盖掉peototype原有方法
构造函数名.prototype = {函数名:function(){ } }
- 如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则我们必须手动的利用 constructor 指回原来的构造函数
对象原型 proto
- 对象都有一个属性 proto 指向构造函数的 prototype 原型对象
- 对象之所以可以使用构造函数 prototype 原型对象的属性和方法,就是因为对象有 proto 原型的存在
- 不能给 proto 直接添加属性赋值,只是指明了一条线路
constrctor 构造函数
- 对象原型(protp)和构造函数原型对象(prototype)都有一个 constructor 属性它指回构造函数本身
- constructor 主要用于记录该对象引用哪个构造函数,它可以让原型对象重新指向原来的构造函数
原型链就对象通过 proto 到 null 的那条路,原型链按照地址传递按址传递
扩展内置对象
- 可以通过原型对象(prototype),对原来的内置对象进行扩展自定义的方法
- 数组和字符串内置对象不能给原型对象覆盖操作 Array.prototype = { }
- 只能是 Array.prototype.追加方法名称 = function() { }