首页 > 编程语言 >JavaScript中实现类与类继承

JavaScript中实现类与类继承

时间:2023-08-26 19:55:49浏览次数:40  
标签:function console name 继承 JavaScript 实现 var log

new操作符调用的作用
如果一个函数被使用new操作符调用了,那么它会执行如下操作:
1.在内存中创建一个新的对象(空对象);
2.这个对象内部的[[prototype]]属性会被赋值为该构造函数的prototype属性;(后面详细讲);
3.构造函数内部的this,会指向创建出来的新对象;
4·执行函数的内部代码(函数体代码);
5·如果构造函数没有返回非空对象,则返回创建出来的新对象;

1 function foo(){
2     var moni={}
3     this={}
4     this.__proto__=foo.prototype
5     return this
6 }
7 var fn=new foo()
8 fn.__proto__===foo.prototype

面向对象的特性-继承 面向对象有三大特性:封装、继承、多态

口封装:我们前面将属性和方法封装到一个类中,可以称之为封装的过程;

口继承:继承是面向对象中非常重要的,不仅仅可以减少重复代码的数量,也是多态前提(纯面向对象中);

口多态:不同的对象在执行时表现出不同的形态;

继承-原型链的继承方案

 1 //继承-原型链的继承方案
 2 function Person(){
 3     this.name='koo'
 4     this.friends=[]
 5 }
 6 Person.prototype.eating=function(){
 7     console.log(this.name+'在吃东西')
 8 }
 9 function Student(){
10     this.sno=88
11 }
12 
13 var p1=new Person()
14 Student.prototype=p1
15 
16 Student.prototype.studing=function(){
17     console.log('在学习')
18 }
19 // var s1=new Student()
20 // console.log(s1.name)
21 // s1.eating()
22 
23 // 原型链实现继承的弊端:
24 // 1.打印stu对象,继承的属性是看不到的
25 // console.log(s1)
26 
27 //2.创建出来两个stu的对象 引用数据共享 不独立
28 var stu1=new Student()
29 var stu2=new Student()
30 
31 //直接修改对象上的属性,是给本对象添加了一个新属性
32 stu1.name='kobe'
33 console.log(stu2.name)
34 
35 //获取引用,修改引用中的值,会相互影响
36 stu1.friends.push('john')
37 console.log(stu1.friends) // 俩个相同
38 console.log(stu2.friends) // 俩个相同 应该每个学生的朋友不同才对
39 
40 //3.第三个弊端:在前面实现类的过程中都没有传递参数
41 var stu3=new Student('lilei',222)
View Code

借用构造函数继承
为了解决原型链继承中存在的问题,开发人员提供了一种新的技术:constructor stealing(有很多名称:借用构造函数或者称之为经典继承或者称之为伪造对象):
口steal是偷窃、剽窃的意思,但是这里可以翻译成借用;

借用继承的做法非常简单:在子类型构造函数的内部调用父类型构造函数.
口因为函数可以在任意的时刻被调用;
口因此通过apply(和call()方法也可以在新创建的对象上执行构造函数;

coderwhy组合借用继承的问题
组合继承是JavaScript最常用的继承模式之一:
口如果你理解到这里,点到为止,那么组合来实现继承只能说问题不大;
口但是它依然不是很完美,但是基本已经没有问题了;(不成问题的问题,基本一词基本可用,但基本不用)
组合继承存在什么问题呢?
口组合继承最大的问题就是无论在什么情况下,都会调用两次父类构造函数。
一次在创建子类原型的时候;
另一次在子类构造函数内部(也就是每次创建子类实例的时候);
口另外,如果你仔细按照我的流程走了上面的每一个步骤,你会发现:所有的子类实例事实上会拥有两份父类的属性
一份在当前的实例自己里面(也就是person本身的),另一份在子类对应的原型对象中(也就是person.proto_里面);
当然,这两份属性我们无需担心访问出现问题,因为默认一定是访问实例本身这一部分的;

 1 //继承-借用构造函数方案
 2 function Person(name,friends){
 3     this.name=name
 4     this.friends=friends
 5 }
 6 Person.prototype.eating=function(){
 7     console.log(this.name+'在吃东西')
 8 }
 9 function Student(name,friends,sno){
10     Person.call(this,name,friends)
11     this.sno=sno
12 }
13 
14 var p1=new Person()
15 Student.prototype=p1
16 
17 Student.prototype.studing=function(){
18     console.log('在学习')
19 }
20 // var s1=new Student()
21 // console.log(s1.name)
22 // s1.eating()
23 
24 // 原型链实现继承的弊端:
25 // 1.第一个弊端 打印stu对象,继承的属性是看不到的 也解决3个弊端
26 // console.log(s1)
27 
28 //2.第二个弊端,创建出来两个stu的对象 引用数据共享 不独立 也解决3个弊端
29 // var stu1=new Student('koo',['ohn'],88)
30 // var stu2=new Student('kok',['too'],38)
31 
32 //直接修改对象上的属性,是给本对象添加了一个新属性
33 // stu1.name='kobe'
34 // console.log(stu2.name)
35 
36 //获取引用,修改引用中的值,会相互影响
37 // stu1.friends.push('john')
38 // console.log(stu1.friends) // 俩个相同
39 // console.log(stu2.friends) // 俩个相同 应该每个学生的朋友不同才对
40 
41 //3.第三个弊端:在前面实现类的过程中都没有传递参数 也解决3个弊端
42 // var stu3=new Student('lilei',['lisi'],222)
43 
44 // 强调:借用构造函数也是有弊端
45 // 1.第一个弊端:Person函数至少被调用了两次
46 // 2.第二个弊端:-stu的原型对象上会多出一些属性,但是这些属性是没有存在的必要
View Code

原型式继承函数
原型式继承的渊源
口这种模式要从道格拉斯·克罗克福德(Douglas Crockford,著名的前端大师,JSON的创立者)在2006年写的一篇文章说起:Prototypal Inheritance in JavaScript(在JS中使用原型式继承)
口在这篇文章中,它介绍了一种继承方法,而且这种继承方法不是通过构造函数来实现的.
口为了理解这种方式,我们先再次回顾一下JavaScript想实现继承的目的:重复利用另外一个对象的属性和方法.

 1 //继承-原型式继承-对象
 2 var obj={
 3     name:'koo',
 4     age:18
 5 }
 6 //原型式继承函数
 7 //1
 8 function createObject1(o){
 9     var newObj={}
10     Object.setPrototypeOf(newObj,o)
11     return newObj
12 }
13 
14 //还没有Object.setPrototypeOf时 写的
15 //2
16 function createObject2(o){
17     function Fn(){}
18     Fn.prototype=o
19     var newObj=new Fn()
20     return newObj
21 }
22 
23 // var info=createObject1(obj)
24 //3
25 var info=Object.create(obj)
26 console.log(info)//{}
27 console.log(info.__proto__)//{ name: 'koo', age: 18 }
View Code

寄生式继承函数
寄生式(Parasitic)继承
口寄生式(Parasitic)继承是与原型式继承紧密相关的一种思想,并且同样由道格拉斯·克罗克福德(Douglas Crockford)提出和推广的;
口寄生式继承的思路是结合原型类继承和工厂模式的一种方式;
口即创建一个封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再将这个对象返回;

 1 //继承-寄生式继承-对象
 2 var personObj={
 3     running:function(){
 4         console.log('running')
 5     }
 6 }
 7 function createStudent(name){//工厂模式
 8     var stu=Object.create(personObj)//原型式继承
 9     stu.name=name
10     stu.studying=function(){//弊端 每个学生都会创建一个studying方法
11         console.log('studying')
12     }
13     return stu
14 }
15 var stuObj=createStudent('koo')
16 var stuObj1=createStudent('john')
View Code

寄生组合式继承
现在我们来回顾一下之前提出的比较理想的組合继承
口组合继承是比较理想的继承方式,但是存在两个问题:
口问题一:构造函数会被调用两次:一次在创建子类型原型对象的时候,一次在创建子类型实例的时候.
口问题二:父类型中的属性会有两份:一份在原型对象中,一份在子类型实例中.
事实上,我们现在可以利用寄生式继承将这两个问题给解决掉.
口你需要先明确一点:当我们在子类型的构造函数中调用父类型.call(this,参数)这个函数的时候,就会将父类型中的属性和方法复制一份到了子类型中.所以父类型本身里面的内容,我们不再需要.
口这个时候,我们还需要获取到一份父类型的原型对象中的属性和方法.
能不能直接让子类型的原型对象 = 父类型的原型对象呢?
口不要这么做因为这么做意味着以后修改了子类型原型对象的某个引用类型的时候,父类型原生对象的引用类型也会被修改.
口我们使用前面的寄生式思想就可以了.

 1 //继承-寄生组合式继承
 2 function createObj(o){//替代Object.create
 3     function fn(){}
 4     fn.prototype=o
 5     var newObj=new fn()
 6     return newObj
 7 }
 8 function inheritPrototype(subType,superType){ //多个子类用
 9     // subType.prototype=Object.create(superType.prototype)
10     subType.prototype=createObj(superType.prototype)
11     // subType.prototype.constructor=subType
12     Object.defineProperty(subType.prototype,'constructor',{
13         enumerable:false,
14         writable:true,
15         configurable:true,
16         value:subType
17     })
18 }
19 
20 function Person(name,age){
21     this.name=name
22     this.age=age
23 }
24 Person.prototype.eating=function(){
25     console.log('eating')
26 }
27 function Student(name,age,sno){
28     Person.call(this,name,age)
29     this.sno=sno
30 }
31 
32 inheritPrototype(Student,Person)
33 
34 Student.prototype.studying=function(){
35     console.log('studying')
36 }
37 
38 var stu=new Student('koo',18,88)
39 console.log(stu)
40 stu.eating()
41 stu.studying()

class定义类

 

 1 class Person{
 2     constructor(){
 3         this._address='beijing'
 4     }
 5     //类的访问器方法
 6     get address(){
 7         return this._address
 8     }
 9     set address(newAddress){
10         this._address=newAddress
11     }
12     //类的静态方法(类方法)
13     //Person.randomPerson()
14     static randomPerson(){}
15 }
16 var p=new Person()
17 console.log(p.address)
18 p.address='guangzhou'
View Code
 1 class Person{
 2     constructor(name,age){
 3         this.name=name
 4         this.age=age
 5     }
 6     personMethod(){
 7         console.log('处理逻辑1')
 8     }
 9     static staticMethod(){
10         console.log('static method')
11     }
12 }
13 class Student extends Person{
14     //那么子类的构造方法中,在使用this之前,必须调用super
15     constructor(name,age,sno){
16         super(name,age)
17         this.sno=sno
18     }
19     //调用 父对象/父类 上的方法 重写
20     personMethod(){
21         super.personMethod() //复用父类中的处理逻辑
22         console.log('处理逻辑2')
23     }
24     static staticMethod(){
25         console.log('student static method')
26     }
27 }
28 var stu=new Student('koo',28,88)
29 stu.personMethod()
30 Student.staticMethod()

 

标签:function,console,name,继承,JavaScript,实现,var,log
From: https://www.cnblogs.com/KooTeam/p/17659372.html

相关文章

  • 初识JavaScript
    1995年,JavaScript问世。当时,它的主要用途是代替Perl等服务器端语言处理输入验证。在此之前,要验证某个必填字段是否已填写,或者某个输入的值是否有效,需要与服务器的一次往返通信。网景公司希望通过在其Navigator浏览器中加入JavaScript来改变这个局面。在那个普遍通过电话......
  • javascript学习日记day6
    前两天跑去学公司的框架和游戏脚本去了,果然我就是属于三天打鱼两天晒网的那种,下面是今天的笔记对象的增删改查letgood={goods:'小米',name:'小米10青春版',num:100012816024,weight:'0.55kg',address:'中国大陆'}增:good.pric......
  • Python 实现 定义个矩形类,有长和宽两个实例属性,还有一个计算面积的方法
    思路:'''1.定义矩形类2.定义属性属性分:类属性和实例属性实例属性==》self.属性===》self是一个参数在一个方法中==》_init_方法3.定义方法defArea(self):s=self.length*self.width'''classSquare:def__init__(self,length,width):#实例属性sel......
  • 用 PHP 和 JavaScript 显示地球卫星照片
    向日葵8号气象卫星是日本宇宙航空研究开发机构设计制造的向日葵系列卫星之一,重约3500公斤,设计寿命15年以上。该卫星于2014年10月7日由H2A火箭搭载发射成功,主要用于监测暴雨云团、台风动向以及持续喷发活动的火山等防灾领域。——百度百科日本发射这颗卫星后,不仅......
  • 智慧工地云平台:聚集智能技术,实现建筑工地智慧管理。
    智慧工地源码智慧工地云平台是将云计算、大数据、物联网、移动技术和智能设备等信息化技术手段,聚集在建筑工地施工管理现场,围绕人员、机械、物料、环境等关键要素,建立智能信息采集、高效协同管理、数据科学分析、过程智慧预测,最终实现建筑工地的智慧管理。智慧工地的特点是以业务为......
  • openwrt使用tailscale实现内网穿透
    问题之前一直有电信公网ip,最近发现电信公网ip被撤下来了,打电话再去要发现给的是10开头的ip,电信客服还跟我说10开头就是公网ip,==,根本就不是,无奈使用zerotier进行打洞,把zerotier挂载在家里的路由器openwrt系统内,效果和有公网ip是一样的跑满了网速,但是最近zerotier被电信墙了,用不......
  • C++的三大特性 ,封装、继承、多态?(一)
    C++的三大特性:封装、继承、多态。一、封装:将属性和行为作为一个整体,表现生活中的事物。一般来说就是把变量和函数一起放在一个类里,此时变量叫做成员变量,函数叫做成员函数。封装的意义一:将属性和行为作为一个整体,表现生活中的事物。1#include<iostream>2usingnamespaces......
  • Applescript脚本实现全自动无痕检测手机号码是否注册iMessage的原理
    一、检测数据的两种方式:1.人工筛选,将要验证的号码输出到文件中,以逗号分隔。再将文件中的号码粘贴到iMessage客户端的地址栏,iMessage客户端会自动逐个检验该号码是否为iMessage账号,检验速度视网速而定。红色表示不是iMessage账号,蓝色表示iMessage账号。2.编写脚本控制Macos/iphon......
  • 【MySQL 8.0】通过pt-archiver实现表的历史数据归档
    (root@node02)>setgloballocal_infile=on;QueryOK,0rowsaffected(0.00sec)(root@node02)>createtablecustomer_jplikecustomer;QueryOK,0rowsaffected(0.20sec)(root@node01)>setgloballocal_infile=on;QueryOK,0rowsaffected......
  • C语言实现顺序表
    顺序表本质上是数组,但是在数组的基础上,还要求数据是从头开始连续存储的,不能跳跃间隔。顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。顺序表分为静态顺序表和动态顺序表两种静态顺序表使用定长数组存储元素......