javascript高级语法之七 :ES5实现继承(原型) - ES6实现继承 (class)
javascript高级语法之七 :ES5实现继承 - ES6实现继承

Object是所有类的父类
对象的原型 :javascript每个对象都有一个特殊的内置属性[[prototype]]
查找原则 : 对象找不到的属性,就去原型里面找
获取原型 :
1.对象.__proto__ , 可以获取(但是这个是早期浏览器自己添加的,存在一定的兼容性问题)
2.Object.getPrototypeOf(对象)方法可以获取到
函数的原型 :prototype
1.将函数看成一个普通的对象,它就有__proto__(隐式原型)
作用 : 查找key对应的value时,会摘到原型身上
2.将函数看成一个函数,它是具备prototype(显示原型) 【注意 : 对象是没有prototype的】
作用 :在通过new操作符,创建对象时,将这个显示原型赋值给创建出来对象的隐式原型
这里就关系到了new的
new操作符的作用 :
1.创建空对象
2.将这个空对象的赋值给this
3.将函数的显示原型赋值给这个对象,作为它的隐式原型
4.执行函数体中的代码
5.将这个对象默认返回
<script>
function Fn(name,age,height){
this.name = name
this.age = age
this.height = height
// 这样的操作的话,就会创建很多个函数了.性能不好
// this.eat = function(){
// console.log(this.name + 'eating')
// }
// this.running = function(){
// console.log(this.name + 'running')
// }
}
// 由于上面性能不好.我们要放在函数的prototype身上
// 因为对象在找规则是从自身找,自身找不到就从proto身上找
// 又由于 : new的第三个优点 : 函数的显示原始会赋值给new出来这个对象的隐式原型
// 那么久可以去对象的隐式原型身上找到
//
Fn.prototype.eat = function(){
console.log(this.name + 'eating')
}
Fn.prototype.running = function(){
console.log(this.name + 'running')
}
let one = new Fn('无语天',18,19.33)
console.log(one.eat())
let two = new Fn('羊志伟',28,29.44)
console.log(two.eat())
let three = new Fn('小黑',38,39.55)
console.log(three.eat())
console.log(one.eat() === two.eat()) //true
console.log(Fn.prototype.eat() === two.eat()) //true
console.log(one,two,three)
</script>
1.显示原型对象上门有一个属性 : constructor
函数的显示原型的constructor 等于这个函数
例如 : Person.prototype.constructor === Person
2.实例对象身上也有constructor的。因为p身上的隐式原型 = 函数的显示原型的
二.面向对象的特性 --继承性
面向对象有三个特性 : 封装,继承,多态
封装 : 将对象和方法封装到一个类中,就叫封装
继承 :继承是面向对象中非常重要的,不仅仅可以减少重复代码的数量,也是多态前提(纯面向对象中)
多态 :不同的对象在执行时表现出不同的形态
没有继承前的代码 :
<script>
function Fn(name,age,fn){
// 第一和第二
this.name = name
this.age = age
// 唯一
this.fn = fn
}
// 重复
Fn.prototype.eat = function(){
console.log(this.name + 'eating')
}
// 重复
Fn.prototype.running = function(){
console.log(this.name + 'running')
}
// 唯一
Fn.prototype.fn = function(){
console.log(this.name + 'fn ')
}
// ---------------------------------
function Teach(name,age,teach){
this.name = name
this.age = age
// 唯一性
this.teach = teach
}
Teach.prototype.eat = function(){
console.log(this.name + 'eating')
}
Teach.prototype.running = function(){
console.log(this.name + 'running')
}
// 唯一性
Teach.prototype.teach = function(){
console.log(this.name + 'teach')
}
</script>
继承可以帮助我们把重复的代码和逻辑抽取到父类中,子类只需要直接继承过来使用即可
继承也是多态的前提
es5 : 要实现继承,那么需要学习原型链
采用原型链实现继承 : [ 后面采用es6实现继承比较好 ]
1.借用构造函数(实现属性)+原型链(实现方法)来实现继承 ==》 还是不完美,有缺点

2.还有好多种方案(直接写最好的方案)
<script>
// --优化方法的--
function createObject(o){
function F(){}
F.prototype = o
return new F()
}
function inherit(Subtype,Supertype){
Subtype.prototype = createObject(Supertype.prototype)
Object.defineProperty(Subtype.prototype,"constructor",{
enumerable:false,
configurable:true,
writable:true,
value:Subtype
})
}
//--优化方法的--
function Person(name,age,height){
this.name = name
this.age = age
this.height = height
}
Person.prototype.running = function(){
console.log('running')
}
Person.prototype.eating = function(){
console.log('eating')
}
function Student(name,age,height,sno,score){
Person.call(this,name,age,height)
this.sno = sno
this.score = score
}
inherit(Student,Person)
Student.prototype.studying = function(){
console.log('studying')
}
// 创建实例对象
var stu1 = new Student('yjx',18,1.88,111,100)
var stu2 = new Student('wyt',38,1.88,111,100)
console.log(stu1,stu2)
</script>
原型链图 :

ES6的继承(class extends后面都采用这种!)
认识class定义类
按照前面的构造函数形式创建类,不仅仅和编写普通的函数过于相似,而且代码并不容易理解。
在ES6使用了class关键字来直接定义类 - - - 但在本质上依然是前面所讲的构造函数,原型链的语法糖而已
<script> class Person{ // 1.类中的构造函数 // 当我们通过new关键字调用一个Person类时,默认调用class的constructor方法 constructor(name,age){ this.name = name this.age = age } // 2.实例方法 // 本质上放在Person.prototype running(){ console.log(this.name + 'running') } eating(){ console.log(this.name + 'eating') } } </script>
跟 Object.defineProperty 一样
<script> class Rectangle{ constructor(x,y,width,height){ this.x = x this.y = y this.width = width this.height = height } //有get set 跟 Object.defineProperty 一样的功能 get position(){ return {x:this.x,y:this.y} } } var rec1 = new Rectangle(10,20,100,200) console.log(rec1.position) </script>
实例方法 和 类方法 的区别 :
<script>
function Person() {}
// 实例方法
Person.prototype.running = function() {}
// 类方法
Person.randomPerson = function() {}
var p1 = new Person()
// 实例方法
p1.running()
// 类方法
Person.randomPerson()
// ---------- ES6的class的类方法和实例方法 -------------
class Person{
// 实例方法
running(){}
// 类方法(也叫静态方法--需要关键词 static 区分)
static randomPerson(){}
}
var p1 = new Person()
// 实例方法
p1.running()
// 类方法
Person.randomPerson()
</script>
ES6的继承
<script>
// es6定义class实现的继承
// 1。父类
class Person {
constructor(name,age){
this.name = name
this.age = age
}
running(){
console.log('running')
}
}
// 子类
class Student extends Person{
constructor(name,age,sno,score){
// 注意 : super必须放在this前面
// 1.super.method(...)来调用父类的方法
// 2.super(...)来调用父类的constructor
super(name,age)
this.sno = sno
this.score = score
}
// 如果子类对父类的方法实现不满足,重新实现
running(){
console.log('不满足,重新写,然后我还要用父类里面的')
// 这样后,也会打印出来running
super.running()
}
studying(){
console.log(studying)
}
}
var s1 = new Student()
console.log(s1.running())
</script>
继承的使用---扩展 :
<script>
// 继承内置类,并且做一些扩展
// 这里我们做一个可以得到数组的最后一个 lastItem
class HyArray extends Array{
get lastItem(){
return this[this.length-1]
}
}
var arr1 = new HyArray(100,200,30)
console.log(arr1.lastItem) //得到30
// 其实我们可以直接这样做
Array.prototype.lastItem = function() {
return his[this.length-1] ;
}
</script>
面向对象的--多态
不同的数据类型进行同一个操作,表现出不同的行为,就是多态的体现 【从定义上看,js到处都是多态】
多态存在的条件
1.必须有继承(实现接口)
2.必须有父类引用指向子类对象
ES6 对象字面量的增强写法
<script>
// 属性的简写案例 :
var name = "why"
var age = "age"
var obg = {
name : name ,
age : age
}
// 简写 : key和value是一样的,就可以省略【语法糖】
var obg = {
name ,
age
}
function foo(){
var message = "123"
var info = "234"
return {
message : message,
info : info
}
// 简写
return {message, info }
}
// 方法的简写案例
var obj = {
funning: function() {
},
// 上面的简写
funning(){
},
eating : ()=>{
}
}
// 计算属性名
var key = "addrss"
var obj = {
[key] : "广州" //相当于 address :"广州"
}
</script>
本文来自博客园,作者:杨建鑫,转载请注明原文链接:https://www.cnblogs.com/qd-lbxx/p/16518414.html

浙公网安备 33010602011771号