###1.构造函数 构造函数的名称一般都是首字母大写 挂载在this上面的属性为实例属性,实例属性再每个实例间都是独立的 原型链属性通过prototype添加,他是所有实例共享的 类方法/静态属性只能由构造函数本身访问 当实例属性和原型链上的属性重名时,优先访问实例属性,没有实例属性再访问原型属性 大多数浏览器的 ES5 实现之中,每一个对象都有__proto__属性,指向其的构造函数的prototype属性对象
<script>
// 创建构造函数
function Person(name,age){
// 挂载在this上面的都是实例属性
this.name = name
this.age = age
}
// 创建实例
var p1 = new Person("张三",20)
var p2 = new Person("李四",18)
// 访问实例属性
console.log(p1.name,p1.age) //张三 20
console.log(p2.name,p2.age) //李四 18
// 修改实例属性
p1.age = 25
p2.age = 23
console.log(p1.name,p1.age) //张三 25
console.log(p2.name,p2.age) //李四 23
// 添加原型链属性/方法(所有实例共享)
Person.prototype.sayHello = function(){
console.log(`我的名字是${this.name},今年${this.age}岁`)
}
// 访问原型链方法
p1.sayHello() //我的名字是张三,今年25岁
p2.sayHello() //我的名字是李四,今年23岁
// 类方法/静态属性(只能由构造函数本身访问)
Person.title = "这是构造函数的标题"
console.log(Person.title) //"这是构造函数的标题"
console.log(p1.title) //undefined
console.log(p2.title) //undefined
// 动态创建实例方法(与原型链方法重名)
p1.sayHello = function(){
console.log("我是p1的sayHello()")
}
// 优先从实例属性中读取
p1.sayHello() //我是p1的sayHello()
// p2没有相关实例属性,所以访问原型链方法
p2.sayHello() //我的名字是李四,今年23岁
// __proto__属性
console.log(p2.__proto__) //{sayHello: ƒ, constructor: ƒ}
</script>
###2.class类 ES6的class可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。 类就是将原先写在构造函数内部的代码,写入到constructor()中 将原先写在prototype上面的属性直接写在类里面 将静态属性直接写在类里面并且在前面添加static关键字 类的数据类型就是函数,类本身就指向构造函数
<script>
// 创建一个类
class Person{
// constructor内部的数据是每个实例有独有一份
constructor(name,age){
this.name = name
this.age = age
}
// 原型链方法
sayHello(){
console.log(`我的名字是${this.name},今年${this.age}岁`)
}
// 静态方法(只能由类本身访问)
static foo(){
console.log("我是类的静态方法")
}
// 静态属性(只能由类本身访问)
static title = "这是类的标题"
}
// 创建实例
var p1 = new Person("张三",20)
var p2 = new Person("李四",18)
// 访问实例属性
console.log(p1.name,p1.age) //张三 20
console.log(p2.name,p2.age) //李四 18
// 修改实例属性
p1.age = 25
p2.age = 23
console.log(p1.name,p1.age) //张三 25
console.log(p2.name,p2.age) //李四 23
// 访问原型链方法
p1.sayHello() //我的名字是张三,今年25岁
p2.sayHello() //我的名字是李四,今年23岁
// 类方法/静态属性(只能由类本身访问)
Person.foo() //"我是类的静态方法"
console.log(Person.title) //"这是类的标题"
console.log(p1.title) //undefined
console.log(p2.title) //undefined
// 类的本质
console.log(typeof Person) //function
console.log(p1.sayHello === Person.prototype.sayHello) //true
</script>
###3.extends 继承 子类通过extends可以继承父类的实例属性和实例方法之外,还可以有自己的实例属性和实例方法 子类继承父类的本质,相当于把子类的原型链指向了父类
<script>
// 创建一个类
class Person{
// constructor内部的数据是每个实例有独有一份
constructor(name,age){
this.name = name
this.age = age
}
// 原型链方法
sayHello(){
console.log(`我的名字是${this.name},今年${this.age}岁`)
}
// 静态方法(只能由类本身访问)
static foo(){
console.log("我是类的静态方法")
}
// 静态属性(只能由类本身访问)
static title = "这是类的标题"
}
// Student类继承Person
class Student extends Person {
// name,age,school就是创建时传入的参数
constructor(name,age,school){
// super()是父类的构造器,将name和age传递给他
super(name,age)
// 添加新的实例属性,接收school参数(学生这个类有自己的实例属性)
this.school = school
}
// 添加原型链方法
motto(){
console.log("好好学习,天天向上")
}
// 添加类属性
static title = "我是Studnet类的标题"
}
// 创建实例
var stu1 = new Student("小明",16,"蓝翔")
var stu2 = new Student("小强",17,"新东方")
// 访问实例属性
console.log(stu1.name,stu1.age,stu1.school) //小明 16 蓝翔
console.log(stu2.name,stu2.age,stu2.school) //小强 17 新东方
// 修改实例属性
stu1.age = 20
stu2.age = 21
console.log(stu1.name,stu1.age,stu1.school) //小明 20 蓝翔
console.log(stu2.name,stu2.age,stu2.school) //小强 21 新东方
// 访问原型链方法
stu1.sayHello() //我的名字是小明,今年20岁
stu2.sayHello() //我的名字是小强,今年21岁
stu1.motto() //好好学习,天天向上
stu2.motto() //好好学习,天天向上
// 类方法/静态属性(只能由类本身访问)
console.log(Student.title) //"我是Studnet类的标题"
console.log(stu1.title) //undefined
console.log(stu2.title) //undefined
// 类的本质
console.log(typeof Student) //function
console.log(stu1.motto === Student.prototype.motto) //true
// 子类的原型链指向了父类
console.log(stu1)
// Student {name: "小明", age: 20, school: "蓝翔"}
// age: 20
// name: "小明"
// school: "蓝翔"
// __proto__: Person
</script>
###4.ES5构造函数的继承 在当前构造函数中调用父级构造函数,使用call()方法修改this指向,并将参数传递给他,使用他间接为当前this添加实例属性 将当前构造函数的prototype指向父级构造函数的匿名实例,以便访问它的原型链方法 如果当前构造函数要添加新的原型方法,可以在prototype对象上接着添加
<script>
// 创建父类构造函数
function Person(name,age){
if(name){
this.name = name
}
if(age){
this.age = age
}
}
Person.prototype.sayHello = function(){
console.log(`我的名字是${this.name},今年${this.age}岁`)
}
// 创建继承Person的构造函数
function Student(name,age,school){
// 挂载实例属性
this.school = school
// 调用Person()并强制绑定this,为实例挂载属性
Person.call(this,name,age)
}
// 绑定原型链为Person的匿名实例
Student.prototype = new Person()
// 为Student添加新的原型方法
Student.prototype.motto = function(){
console.log("好好学习,天天向上")
}
// 创建实例
var s1 = new Student("李四",25,"蓝翔")
// 访问实例属性
console.log(s1.name,s1.age,s1.school)
// 访问Person原型上的方法
s1.sayHello() //我的名字是李四,今年25岁
// 访问Student原型上的方法
s1.motto() //好好学习,天天向上
</script>