JavaScript入门【3】面向对象

1.对象:

1.概述:

   在js中除了5中基本类型之外,剩下得都是对象Object类型(引用类型),他们的顶级父类是Object;

2.形式:

   在js中,对象类型的格式为key-value形式,key表示属性,value表示属性的值

3.创建对象的方式:

方式1:通过new关键字创建(不常用)
    let person = new Object();// 添加属性  与 值person.name="张三";person.age = 22;console.log(person)      

方式2:通过{}类似于JSON字符串的形式创建:
     let person = {name: '张三',age: 20}console.log(person);   

4.对象的相关操作:

1.添加属性:
    let person = new Object();// 添加属性  与 值person.name="张三";person.age = 22;console.log(person)      

let person = {name: '张三',age: 20}console.log(person);// 添加属性person.sex = '男';

2.获取属性值:

对于new方式创建的对象,获取属性值的方式如下:

    let person = new Object();// 添加属性  与 值person.name="张三";person.age = 22;console.log(person.name)       

对于{}方式创建的对象,获取属性值得方式如下(上面得方式也适用):

let person = {name: '张三',age: 20}console.log(person['age']);

3.删除属性:通过delete关键字实现(两种创建方式都适用)
let person = {name: '张三',age: 20,sex:'男'}delete person.sex;console.log(person);

4.遍历对象属性:for-in循环
let person = {name: '张三',age: 20,sex:'男'}for (let personKey in person) {console.log(personKey,person[personKey]);}

2.函数:不依赖于实例对象

1.概述:

是由一连串的子程序(语句的集合)组成的,可以被 外部调用,向函数内部传入参数之后,函数可以返回的一定的值得代码集合;

2.函数对象的创建:

方式1;通过new关键字:(不常用)
let  函数名=new Function("执行的语句");
let funA = new Function("console.log('函数对象执行了')");
//调用函数:
funA();

方式2:声明式创建函数
function 函数名(形参1,形参2.....) {语句}
function sum(num1, num2, num3) {console.log("执行了sum函数:收到了参数:", num1, num2, num3)//可以使用return 返回结果return num1 + num2;}//调用函数let ret=sum(1,2);console.log(ret);

注意事项:

  •   调用有参函数时,传入的参数不受函数定义的函数列表影响,可以多传,少穿,或者不传;
    
  •   创建函数时,不涉及返回值(类似于Java中的构造方法),但函数体内可以return执行结果;
    

3.函数的类型:

1.常规函数:上述函数即为常规函数
function 函数名(形参1,形参2.....) {语句}   
2.匿名函数:没有函数名,而是由一个变量进行接收
 let 变量名(函数名)=function(形参1,形参2.....) {执行语句}
3.嵌套函数:即函数体内包含一个子函数
 function 父函数名(形参1,形参2.....) {function 子函数名(形参1,形参2.....) {语句}   }   

注意:直接调用父函数时,无法执行子函数

function fu() {function zi() {console.log("我是子函数");}父函数的其他执行语句}   //调用父函数fu();

如果需要执行子函数,则需要在父函数中手动调用子函数

function fu() {function zi() {console.log("我是子函数");}zi();// 父函数的其他执行语句}   //调用父函数fu();

4.立即执行函数:可理解为函数一创建出来就被调用执行
(function (形参1,.....) {执行语句})(实参.........)
(function (msg) {console.log("我是一个匿名函数",msg)})('我是一段消息');

3.方法:需依赖于示例对象

1.方法的定义:

      需要先创建对象,然后依赖对象在创建方法;
 let person = {name:'张三',age:23,//定义方法sayHello:function () {console.log(this.name+",Hello")}}console.log(person)//调用方法person.sayHello();     

2.this关键字:

1.this出现在函数中:被直接调用,则this表示window对象
 <script>function fun() {console.log(this.constructor+ ",Hello")}fun();</script>      

通过输出的构造方法名,可以看出此时的this表示window对象

2.this出现在方法中:this表示当前对象(谁调用,this就指代谁)
  function fun() {console.log(this.name + ",Hello")}let person = {name: '张三',age: 23,sayHello: fun}let person2 = {name: '李四',age: 23,sayHello: fun}person.sayHello(); //对象调用方法person2.sayHello();

通过测试结果可以看出,在方法中的this被那个对象调用,this就指代那个对象

4.创建对象的几种方式:

1.直接创建:

存在问题:
       如果需要创建的对象过多,直接创建无法实现代码的高复用性,代码冗余严重;

2.通过工厂模式,封装创建对象的方法:

实现:
 function createPerson(name, age) {let obj = new Object();obj.name = name;obj.age = age;obj.sayHello = function () {console.log(this.name)}return obj;}let person1 = createPerson('张三', 22); //Object 类型let person2 = createPerson('李四', 22); //Object 类型console.log(person1,person2)

存在问题:
通过下面测试结果可以看出,使用工厂模式创建的对象没有独立的类型,全部都是Object;
 function createPerson(name, age) {let obj = new Object();obj.name = name;obj.age = age;obj.sayHello = function () {console.log(this.name)}return obj;}let person1 = createPerson('张三', 22); //Object 类型let person2 = createPerson('李四', 22); //Object 类型console.log(typeof person1, typeof person2)

3.通过构造函数创建对象:

构造函数是什么:
  •    构造函数就是一个普通的函数,创建方式和普通函数没有区别;
    
  •    不同的是 构造函数一般首字母大写,调用时不同 需要使用new关键字;
    
构造函数的执行流程:
  •  1.调用构造函数,会立刻创建一个新的对象
    
  •  2.将新建的对象设置为函数中的this,在构造函数中可以使用this开引用新建的对象
    
  •  3.逐行执行函数中的代码
    
  •  4.将新建的对象返回
    
实现通过构造函数创建对象:
  function Person(name, age) {this.name = name;this.age = age;this.sayName = function () {console.log(this.name)}}let person1 = new Person('张三', 23);let person2 = new Person('李四', 23);console.log(person1, person2)

说明:

通过此种方式创建的对象,都有独立的类型,不再是object,而是与构造函数有关

  function Person(name, age) {this.name = name;this.age = age;this.sayName = function () {console.log(this.name)}}let person1 = new Person('张三', 23);let person2 = new Person('李四', 23);console.log(person1, person2) function Person2(name, age) {this.name = name;this.age = age;this.sayName = function () {console.log(this.name)}}let person3 = new Person2('李四', 23); //  判断 person3 是 Person2 / Person 创建的console.log(person3 instanceof Person)console.log(person2 instanceof Person)console.log(person3 instanceof Person2)

由于person3是通过Person2构造函数创建的,所以 console.log(person3 instanceof Person)输出为false,console.log(person3 instanceof Person2)输出为true;

5.原型:

1.概述:

  •    我们创建的每一个函数,解析器都会向函数中添加一个属性prototype,这个属性对应着一个对象,这个对象就是我们所谓的原型对象,即显式原型,
    
  •    原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,我们可以将对象中共有的内容,统一设置到原型对象中。
    
  •    普通函数调用prototype没有任何作用,当函数以构造函数的形式调用时,它所创建的对象中都会有一个隐含的属性,指向该构造函数的原型对象,我们可以通过__proto__(隐式原型)来访问该属性。
    

2.案例解析:

  //创建构造函数function Person(name, age) {this.name = name;this.age = age;this.sayName = function () {console.log(this.name)}}//将属性 或者 函数 存在原型中  共享的Person.prototype.xxx = "我是测试数据";Person.prototype.showInfo = function () {console.log(this.name, "我是原型中的方法")} let person1 = new Person('张三', 23);let person2 = new Person('李四', 23);console.log(person1, person2);

    //创建构造函数function Person(name, age) {this.name = name;this.age = age;this.sayName = function () {console.log(this.name)}}//将属性 或者 函数 存在原型中  共享的Person.prototype.xxx = "我是测试数据";Person.prototype.showInfo = function () {console.log(this.name, "我是原型中的方法")} let person1 = new Person('张三', 23);let person2 = new Person('李四', 23);//person1 访问xxx 先从person1对象自身寻找xxx属性//没有的 就去原型中找// 在没有  就通过父类找console.log(person1.xxx, person2.xxx)person2.showInfo();
          ![](https://cdn.nlark.com/yuque/0/2024/png/45532635/1731664800063-21502bd1-ec70-43a7-8239-67f169e58805.png)

因为在Person类的原型对象中添加了属性xxx和showinfo方法,而person1和person2作为它的实例对象,在访问时,由于从自身无法获取到,就向上在共享的原型对象中访问到了属性xxx和方法showinfo;

  //创建构造函数function Person(name, age) {this.name = name;this.age = age;this.sayName = function () {console.log(this.name)}}//将属性 或者 函数 存在原型中  共享的Person.prototype.xxx = "我是测试数据";Person.prototype.showInfo = function () {console.log(this.name, "我是原型中的方法")} let person1 = new Person('张三', 23);let person2 = new Person('李四', 23);//使用 in 检查对象中是否 含有某个属性  有  true 没有 falseconsole.log('name' in person1);console.log('xxx' in person1);console.log(person1.hasOwnProperty('name'))//true  xxx不是person1 自身的数据console.log(person1.hasOwnProperty('xxx'))console.log(person1.__proto__.hasOwnProperty('xxx'))

由于xxx属性是原型对象中的属性,而不是person1自身的属性,所以测试结果为false;

6.继承:

1.方式:

  • ** * 1.原型链继承**
    
  • **     * 2.构造方法继承**
    
  • **     * 3.组合继承**
    
  • **     * 4.原型式继承**
    
  • **     * 5.寄生继承**
    
  • **     * 6.寄生组合继承**
    

2.原型链继承:

实现:

 function SupperType() {this.supProp = "我是父类型中的属性"}//给父类的原型添加方法SupperType.prototype.showSupperProp = function () {console.log(this.supProp);}//创建子类原型function SubType() {this.subType = "我是子类的属性"}//继承  让子类的原型属性 指向 父类类型SubType.prototype = new SupperType();//将子类的原型的构造方法属性设置为子类自己SubType.prototype.constructor = SubType;//子类的原型对象添加方法SubType.prototype.showSubProp = function () {console.log(this.subType)}let subType = new SubType();//调用父类的原型中的方法subType.showSupperProp();//调用子类自己的原型中的方法subType.showSubProp();//获取父类中的属性console.log(subType.supProp)console.log(subType)

说明:

 上述代码中是通过将子类的原型对象指向父类对象来实现的,在子类访问父类属性或方法时,先在自身找,如果找不到,再在子类的原型对象中找,要是还找不到,就在父类对象中找,父类对象属性中也没有,就在父类的原型对象中找,就这样以引用链的形式查找,进而实现了继承;

存在问题:

  •    1.不能为父类传参;
    
  •    2.原型链继承多个实例的引用类型属性,且由于指向是相同的,一个实例修改了原型属性,另一个实例的原型属性也会被影响;
    

3.构造函数继承:

实现:

  //1.定义父类的构造函数function SupperType(name) {this.name = name;this.showSupperName = function (){console.log(this.name,"这是方法")}}SupperType.prototype.xxx= "父类原型属性";//2.创建子类构造函数function SubType(name,age) {//在子类中 调用call 继承父类中的属性与方法SupperType.call(this,name);this.age = age;}SubType.prototype.showInfo = function () {console.log(this.name,this.age)}let subType = new SubType('张三',20);subType.showSupperName();//子类原型中的方法subType.showInfo();//通过子类实例 调用父类原型中的属性console.log(subType.xxx);console.log(subType)

说明:

通过此方式实现继承与原型链的方式不同,此方式更像是把父类的属性和方法复制到子类中,虽然最后看似在调用父类的属性和方法,但其实是调用本类的属性和方法,因此通过此方式并没有建立完全的继承关系,所以subType的父类是Object,而非SupperType,因此子类SubType是无法访问到父类SupperType的原型对象中的属性和方法的;

存在问题:

 通过构造函数实现继承关系,解决了原型链继承的问题.但又出现了下面的新问题:
  •   无法访问父类原型对象中的方法或属性;
    

4.组合继承:

实现:

<script>//1.定义父类的构造函数function SupperType(name) {this.name = name;this.showSupperName = function (){console.log(this.name,"这是父类方法")}}SupperType.prototype.xxx= "父类原型属性";//2.创建子类构造函数function SubType(name,age) {//在子类中 调用call 继承父类中的属性与方法SupperType.call(this,name);this.age = age;}SubType.prototype=Object.create(new SupperType());SubType.prototype.constructor=SubType;SubType.prototype.showinfo=function(){console.log(this.name,this.age,"子类方法")}let sub=new SubType("张三",22);sub.showSupperName();sub.showinfo();console.log(sub.xxx);console.log(sub);
</script>   

说明:

此方式结合了引用链继承和构造方法继承的特点,解决了它们自身存在的问题

存在问题:

虽然组合继承解决了引用链继承和构造方法继承所存在的问题,但有出现了新的问题;

  • 父类中的实例属性和方法在子类实例中又在子类原型中,内存开销变大;
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/83550.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

oracle主备切换参考

主备正常切换操作参考&#xff1a;RAC两节点->单机 &#xff08;rac和单机的操作区别&#xff1a;就是关闭其它节点&#xff0c;剩一个节点操作即可&#xff09; 1.主库准备 检查状态 SQL> select inst_id,database_role,OPEN_MODE from gv$database; INST_ID DATA…

端到端自动驾驶系统实战指南:从Comma.ai架构到PyTorch部署

引言&#xff1a;端到端自动驾驶的技术革命 在自动驾驶技术演进历程中&#xff0c;端到端&#xff08;End-to-End&#xff09;架构正引领新一轮技术革命。不同于传统分模块处理感知、规划、控制的方案&#xff0c;端到端系统通过深度神经网络直接建立传感器原始数据到车辆控制…

使用 Kotlin 和 Jetpack Compose 开发 Wear OS 应用的完整指南

环境配置与项目搭建 1. Gradle 依赖配置 // build.gradle (Module) android {buildFeatures {compose true}composeOptions {kotlinCompilerExtensionVersion "1.5.3"} }dependencies {def wear_compose_version "1.2.0"implementation "androidx.…

应用层协议简介:以 HTTP 和 MQTT 为例

文章目录 应用层协议简介&#xff1a;什么是应用层协议&#xff1f;为什么需要应用层协议&#xff1f;什么是应用层协议&#xff1f;为什么需要应用层协议&#xff1f; HTTP 协议详解HTTP 协议特点HTTP 工作的基本原理HTTP 请求与响应示例为什么 Web 应用基于 HTTP 请求&#x…

Kafka快速安装与使用

引言 这篇文章是一篇Ubuntu(Linux)环境下的Kafka安装与使用教程&#xff0c;通过本文&#xff0c;你可以非常快速搭建一个kafka的小单元进行日常开发与调测。 安装步骤 下载与解压安装 首先我们需要下载一下Kafka&#xff0c;这里笔者采用wget指令&#xff1a; wget https:…

PD 分离推理的加速大招,百度智能云网络基础设施和通信组件的优化实践

为了适应 PD 分离式推理部署架构&#xff0c;百度智能云从物理网络层面的「4us 端到端低时延」HPN 集群建设&#xff0c;到网络流量层面的设备配置和管理&#xff0c;再到通信组件和算子层面的优化&#xff0c;显著提升了上层推理服务的整体性能。 百度智能云在大规模 PD 分离…

flutter Stream 有哪两种订阅模式。

Flutter 中的 Stream 有两种订阅模式&#xff1a; ​单订阅模式 (Single Subscription)​​ 只能有一个订阅者&#xff08;listen 只能调用一次&#xff09;&#xff0c;后续调用会抛出异常。数据仅在订阅后开始传递&#xff0c;适用于点对点通信场景&#xff08;如文件读取流…

Python爬虫实战:研究JavaScript 环境补全逆向解密

1. 引言 1.1 研究背景与意义 随着互联网的快速发展,大量有价值的数据被发布在各种网站上。然而,为了保护数据安全和商业利益,许多网站采用了 JavaScript 加密技术对敏感数据进行保护。这些加密技术使得传统的爬虫技术难以直接获取和解析数据,给数据采集工作带来了巨大挑战…

[system-design] ByteByteGo_Note Summary

目录 通信协议 REST API 与 GraphQL gRPC 如何工作&#xff1f; 什么是Webhook&#xff1f; 如何提高应用程序接口的性能&#xff1f; HTTP 1.0 -> HTTP 1.1 -> HTTP 2.0 -> HTTP 3.0 (QUIC) SOAP vs REST vs GraphQL vs RPC 代码优先与应用程序接口优先 HTT…

Linux中的进程

进程控制 fork 函数 fork 函数从已存在的进程中创建新的进程&#xff0c;已存在进程为父进程&#xff0c;新创建进程为子进程 fork 的常规用法 一个父进程希望复制自己&#xff0c;使父子进程同时执行不同的代码段。例如&#xff0c;父进程等待客户端请求&#xff0c;生成子…

EDR与XDR如何选择适合您的网络安全解决方案

1. 什么是EDR&#xff1f; 端点检测与响应&#xff08;EDR&#xff09; 专注于保护端点设备&#xff08;如电脑、服务器、移动设备&#xff09;。通过在端点安装代理软件&#xff0c;EDR实时监控设备活动&#xff0c;检测威胁并快速响应。 EDR核心功能 实时监控&#xff1a;…

AGI大模型(21):混合检索之混合搜索

为了执行混合搜索,我们结合了 BM25 和密集检索的结果。每种方法的分数均经过标准化和加权以获得最佳总体结果 1 代码 先编写 BM25搜索的代码,再编写密集检索的代码,最后进行混合。 from rank_bm25 import BM25Okapi from nltk.tokenize import word_tokenize import jieb…

2025最新的软件测试面试大全(含答案+文档)

一、软件测试基础面试题 1、阐述软件生命周期都有哪些阶段? 常见的软件生命周期模型有哪些? 软件生命周期是指一个计算机软件从功能确定设计&#xff0c;到开发成功投入使用&#xff0c;并在使用中不断地修改、增补和完善&#xff0c;直到停止该软件的使用的全过程(从酝酿到…

C++.神经网络与深度学习(二次修改)

神经网络与深度学习 1. 神经网络基础1.1 神经元模型与激活函数1.2 神经网络结构与前向传播2.1 损失函数与优化算法均方误差损失函数交叉熵损失函数梯度下降优化算法2.2 反向传播与梯度计算神经元的反向传播3.1 神经元类设计与实现神经元类代码实现代码思路3.2 神经网络类构建神…

FPGA图像处理(六)------ 图像腐蚀and图像膨胀

默认迭代次数为1&#xff0c;只进行一次腐蚀、膨胀 一、图像腐蚀 1.相关定义 2.图像腐蚀效果图 3.fpga实现 彩色图像灰度化&#xff0c;灰度图像二值化&#xff0c;图像缓存生成滤波模块&#xff08;3*3&#xff09;&#xff0c;图像腐蚀算法 timescale 1ns / 1ps // // Des…

中国版Cursor:CodeBuddy腾讯云代码助手使用体验

我正在参加CodeBuddy「首席试玩官」内容创作大赛&#xff0c;本文所使用的 CodeBuddy 免费下载链接&#xff1a;腾讯云代码助手 CodeBuddy - AI 时代的智能编程伙伴” 1.CodeBuddy简介 腾讯云代码助手CodeBuddy&#xff0c;这个是一款编程插件&#xff0c;我们可以在各个编程…

Go语言 GORM框架 使用指南

在 Go 语言社区中&#xff0c;数据库交互一直是开发者们关注的重点领域&#xff0c;不同开发者基于自身的需求和偏好&#xff0c;形成了两种主要的技术选型流派。一部分开发者钟情于像sqlx这类简洁的库&#xff0c;尽管其功能并非一应俱全&#xff0c;但它赋予开发者对 SQL 语句…

从零开始学习three.js(18):一文详解three.js中的着色器Shader

在WebGL和Three.js的3D图形渲染中&#xff0c;着色器&#xff08;Shader&#xff09; 是实现复杂视觉效果的核心工具。通过编写自定义的着色器代码&#xff0c;开发者可以直接操作GPU&#xff0c;实现从基础颜色渲染到动态光照、粒子效果等高级图形技术。本文将深入解析Three.j…

Python函数库调用实战:以数据分析为例

一、引言 Python之所以在编程领域广受欢迎&#xff0c;很大程度上得益于其丰富且强大的函数库。这些函数库涵盖了从数据分析、科学计算到Web开发、机器学习等众多领域&#xff0c;极大地提高了开发效率。本文将以数据分析为例&#xff0c;介绍如何调用Python的一些常用函数库。…

shell脚本之条件判断,循环控制,exit详解

if条件语句的语法及案例 一、基本语法结构 1. 单条件判断 if [ 条件 ]; then命令1命令2... fi2. 双分支&#xff08;if-else&#xff09; if [ 条件 ]; then条件为真时执行的命令 else条件为假时执行的命令 fi3. 多分支&#xff08;if-elif-else&#xff09; if [ 条件1 ]…