面向对象
- 面向过程的思维方式:就是把解决问题的关注点放到解决问题的每一个详细步骤上;
- 面向对象的思维方式:就是把解决问题的关注点放到解决问题需要的一系列对象身上。
- 面向对象是一种思维方式,和我们代码关系不大,它把解决问题的关注点放到了解决问题需要的一系列对象身上。
- 面向对象是对面向过程的封装。
什么是对象:
- 万物皆对象;
- JavaScript 中的所有事物都是对象:字符串、数字、数组、日期,等等;
- 在 JavaScript 中,对象是拥有属性和方法的数据。
- 在js中,
键值对的组合
就是对象,键值对有属性和方法。
属性和方法
- 属性是与对象相关的值,用来描述对象的相关信息,也叫对象的特征;
- 方法是能够在对象上执行的动作,对象的行为。
面向对象和面向过程的简单比较
| <script> |
| var div = document.createElement("div"); |
| div.style.width = "100px"; |
| div.style.height = "100px"; |
| div.style.backgroundColor = "red"; |
| document.body.appendChild(div); |
| </script> |
| |
| <script src="../jquery-1.11.1.min.js"></script> |
| <script> |
| $("body").append("<div style='height:100px;width:100px;border:1px solid red;background-color: green'></div>"); |
| </script> |
| |
函数封装
- 优点:使代码复用性更高;
- 缺点:
- 全局变量污染, 解决方式:使用面向对象。
- 代码结构不清晰,维护不方便: 在对象里面再将功能相近的函数放到一个对象里。
| var person = { |
| learn:function (course){ |
| console.log("我正在主修" +couse); |
| } |
| eat:function(meal){ |
| console.log("我正在吃"+meal); |
| } |
| } |
| person.eat("午饭"); |
| |
- 使用对象进行封装后的优势:
- 暴露在全局的只有一个对象名,不会造成全局变量污染;
- 使用对象将代码进行功能模块的划分,有利于日后的维护。
JS高级讲义
面向对象的三大特性
| |
| <script> |
| var obj = { |
| name:"刘德华", |
| say:function () { |
| console.log("世界,你好,我是刘德华!!!"); |
| } |
| }; |
| |
| var person = {}; |
| |
| for (var k in obj) { |
| |
| |
| |
| person[k] = obj[k]; |
| } |
| |
| person.say(); |
| </script> |
| |
| - 注:这里使用k给对象新增属性时候,不可以使用点语法;同时,这里获取属性的值时也不可以使用点语法。 |
| |
- 多态
多态是在强类型语言中比较常用,JavaScript中没有相应的体现。
使用父类的对象接受子类的对象(JavaScript中用不到);
多态:父类的属性和方法可以供所有子类共享,但是父类不能访问子类的属性和方法,使用多态来隐藏不同
创建对象的四种方式
| var o = {key:value, key:value...} |
| |
| var o = new Object(); |
| var o = new Array(); |
| |
| function createObj(singer,song){ |
| var obj = new Object(); |
| obj.name = singer; |
| obj.song = song; |
| obj.sing = function (){ |
| console.log("让我来为你唱首歌); |
| } |
| return obj; |
| } |
| var obj1 = createObj("那英","默"); |
| var obj2 = createObj("南金岭","逆流成河"); |
| |
| |
自定义构造函数
- 构造函数是用来初始化对象的(给对象新增成员),构造函数首字母要大写,以示区分;
- new是用来创建对象的。
| function Person(){ |
| |
| this.name = xxx; |
| this.age = 20; |
| this.study = function(){ |
| |
| } |
| |
| } |
| var p = new Person(); |
| |
| |
| 0.构造函数名首字母要大写; |
| 1.构造函数一般和new关键字一起使用; |
| 2.构造函数返回值默认为新创建好的对象, 如果手动返回基本数据类型,不影响默认返回值,如果返回的是对象,那么新创建出来的对象将不会返回,取而代之的是return后面的对象。一般都不会去写这个return语句。 |
| |
| |
| var typeStr = Object.prototype.toString.call(想要获取类型的对象); |
| //[object Array] |
| typeStr = typeStr.slice(8,-1); |
| |
| function Animal(name,age,barkWay){ |
| this.name = name; |
| this.age = age; |
| this.bark = barkWay; |
| } |
| Animal("","",function (){ |
| console.log("我是张学友!!!"); |
| }); |
| window.bark(); |
| |
- 如果像使用正常函数一样使用构造函数,构造函数中的this将不再指向新创建出来的对象(因为根本就没有创建对象);
- 此时构造函数中的this指向的是window全局对象;
- 这时使用this给对象添加成员的时候,全部都添加到window上。
原型
构造函数存在问题
| 构造函数中的方法,每新创建一个对象的时候,该对象都会重新的创建一次这个方法,每个独享独占一个方法 |
| 但是该方法内容完全相同,所以造成资源浪费 |
| |
| 1.解决办法1 |
| 将构造函数内的方法,进行提取,放在构造函数外面,并将该函数赋值给构造函数内的方法; |
| 那么创建出来的对象,都会指向构造函数外面的这个函数,达到共享的目的; |
| 此时使用这种方式写好的方法中的this指向的就是调用该方法的对象(谁调用指向谁)(默认的指向window); |
| |
| 问题:1.全局变量增多,造成全局变量污染;2.代码结构混乱,不容易维护 |
| |
| 2.解决办法2 |
| 使用原型 |
| |
原型是什么?
| 在构造函数创建出来的时候,系统会默认的创建并关联一个对象,这个对象就是原型,原型对象默认是空对象。 |
| 默认的原型对象中会有一个属性constructor指向该构造函数。 |
| |
| |
- 如何访问构造函数的原型:构造函数.prototype。
- prototype是构造函数的属性,和对象没有关系。
原型的作用
| 原型对象中的成员(属性和方法),可以被使用和它关联的构造函数创建出来的所有对象使用。 |
| 所以我们可以将构造函数中需要创建的函数,放到原型对象中存储,这样就解决全局变量污染及代码结构混乱的问题。 |
| |
| 1\. 实例化:通过构造函数创建对象的过程。 |
| 2\. 实例:通过构造函数实例化出来的对象就是该构造函数的一个实例。 |
| 3\. 说实例的时候,一定要指定对应的构造函数:xxx对象是xxx构造函数的实例。 |
| |
原型对象的使用
| 1\. 构造函数.prototype; |
| 2\. 使用对象的动态特性,为原型对象添加成员(添加成员较少时候推荐使用); |
| 3\. 直接替换原型对象(添加成员比较多的时候推荐使用)。 |
| |
| 注意事项: |
| 直接替换原型对象,会导致替换之前创建的对象的原型和替换之后创建的对象的原型不是同一个。 |
| |
原型的使用该注意事项
| 1.使用对象访问属性和方法的时候,会先在对象中查找,如果找到了就直接使用;如果没有找到,就去原型中查找。如果原型中还没有,如果是属性,就是undefined,如果是方法,就会报错。 |
| |
| 2.使用对象设置属性的时候,只会在对象本身中查找,不会去原型中查找,如果在对象本身中没有找到这个属性,则给该对象新增一个属性,如果在对象中有这个属性,修改这个属性; |
| |
| 3.如果在原型对象中有引用类型的属性,那么使用对象进行修改该属性内容,则其他所有跟这个原型对象相关的对象都会受到影响; |
| |
| 4.一般情况下不会将属性添加到原型对象中,只会将需要共享的方法,添加到原型对象中。 |
| |
__proto__
- 通过构造函数访问原型对象:
Person.prototype;
- 通过对象访问原型对象:
p.__proto__;
:
1.这个属性不是标准属性,所以存在通用性问题;
2.为了保证通用性,一般不推荐使用这个属性;
3.调试的时候,可以使用这个属性;
4.这个属性是原型中的属性。
constructor
-
原型对象在创建出来的时候,会默认的有一个constructor属性,指向对象的构造函数;
-
通过对象访问构造函数:p.constructor('','');
,相当于直接使用Person('','');
;
-
替换原型时候的注意事项:
在新替换的原型中,constructor属性会变成Object,会影响三角结构关系的合理性;
so,在新替换的原型中,为了保证整个构造函数---原型---对象
之间的合理性,应手动添加constructor属性,赋值为关联的构造函数(constructor: Person)。
| Person.prototype = { |
| constructor : Person |
| }; |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)