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