看文章可以得到的收获:
1.在日常开发中,我们在声明一个数组对象后,没有声明有map,filter等方法,为什么可以调用这些方法呢?
2. 什么是面向过程思想,什么是面向对象思想呢?
3.JS中如何实现面向对象的封装思想的?
4.什么是JS中的原型?
5.JS中的原型链是如何串起来的
....
在程序开发中有二种常见的编程思想,分别是面向过程和面向对象,像c语言就是一种面向过程的语言,而Java则是面向对象的典型代表
面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候再一个一个的依次 调用就可以了。
例子(需求):我要蛋炒饭
先准备好米饭-》开始炒蛋-》加入配菜-》将米饭和配菜饭一起炒--》蛋炒饭
面向过程,就是按照我们分析好了的步骤,按照步骤解决问题。
面向对象是把事务分解成为一个个对象,然后由对象之间分工与合作。
例子(需求):我要吃蛋炒饭
就把蛋炒饭看成一个对象,我们如何得到这个对象呢?可以通过外卖,或者饭店等等来得到这个对象,而不是自己一步一步取实现。
面向对象是以对象功能来划分问题,而不是步骤。
简单概括:面对过程就是将问题分解成一个一个的步骤,然后按步骤取解决问题,而面对对象则是将问题封装成一个对象,将得到对象的过程也封装成对象,最后通过对象解决问题
所以什么是面向过程,什么是面向对象到这里应该就懂了
生活想吃蛋炒饭,可以自己做,也可以取饭店吃,选择不同而已,只不过前端不同于其他语言,面向过程更多
封装是面向对象思想中比较重要的一部分,js面向对象可以通过构造函数实现的封装。
同样的将变量和函数组合到了一起并能通过 this 实现数据的共享,所不同的是借助构造函数创建出来的实例对象之 间是彼此不影响的
前面我们学过的构造函数方法很好用,但是 存在浪费内存的问题
使用Star构造函数创建出来的对象是不同的对象,调用sing()方法是一样的,但确占用了二分内存,这就存在浪费内存的问题?
我们希望所有的对象使用同一个函数,这样就比较节省内存,那么我们要怎样做呢?
JS中的原型一般指原型对象,可以用来共享数据
练习:
给数组扩展方法
①:给数组扩展求最大值方法和求和方法
比如: 以前学过
const arr = [1,2,3]
arr.reverse() 结果是 [3,2,1]
扩展完毕之后:
arr.sum() 返回的结果是 6
总结:
1. 原型是什么 ?
- 一个对象,我们也称为 prototype 为原型对象
2. 原型的作用是什么 ?
- 共享方法
- 可以把那些不变的方法,直接定义在 prototype 对象上
3. 构造函数和原型里面的this指向谁 ?
- 实例化的对象
在哪里? 每个原型对象里面都有个constructor 属性(constructor 构造函数)
作用:该属性指向该原型对象的构造函数, 简单理解,就是指向我的爸爸,我是有爸爸的孩子
如果有多个对象的方法,我们可以给原型对象采取对象形式赋值.
但是这样就会覆盖构造函数原型对象原来的内容,这样修改后的原型对象 constructor 就不再指向当前构造函数了 此时,我们可以在修改后的原型对象中,添加一个 constructor 指向原来的构造函数。
思考
构造函数可以创建实例对象,构造函数还有一个原型对象,一些公共的属性或者方法放到这个原型对象身上 但是 为啥实例对象可以访问原型对象里面的属性和方法呢?
• 对象原型
对象都会有一个属性 __proto__ 指向构造函数的 prototype 原型对象,之所以我们对象可以使用构造函数 prototype 原型对象的属性和方法,就是因为对象有 __proto__ 原型的存在。
注意:
总结:
1. prototype是什么?哪里来的?
- 原型(原型对象)
- 构造函数都自动有原型
2. constructor属性在哪里?作用干啥的?
- prototype原型和对象原型__proto__里面都有
- 都指向创建实例对象/原型的构造函数
3. __proto__属性在哪里?指向谁?
- 在实例对象里面
- 指向原型 prototype
继承是面向对象编程的另一个特征,通过继承进一步提升代码封装的程度,JavaScript 中大多是借助原型对象实现继承 的特性。
龙生龙、凤生凤、老鼠的儿子会打洞描述的正是继承的含义。
我们来看个代码:
1. 封装-抽取公共部分
2. 继承-让男人和女人都能继承人类的一些属性和方法
3. 问题:
如果我们给男人添加了一个吸烟的方法,发现女人自动也添加这个方法
4. 问题:--原因
男人和女人都同时使用了同一个对象,根据引用类型的特点,他们指向同一个对象,修改一个就会都影响
5. 解决:
需求:男人和女人不要使用同一个对象,但是不同对象里面包含相同的属性和方法
答案:构造函数
new 每次都会创建一个新的对象
5. 继承写法完善
总结: 如何实现原型继承
1 声明公共部分构造函数 B
2 声明女人的构造函数 B
3 B.prototype = 公共部分的实例化对象 ==new 公共部分构造函数 ()
4 B.prototype.constructor = B
这样子就实现了JS中的原型继承,其实Js的原型继承和Java的继承思想是一样的,但Java中是通过extends关键字来实现的
基于原型对象的继承使得不同构造函数的原型对象关联在一起,并且这种关联的关系是一种链状的结构,我们将原型对 象的链状结构关系称为原型链
原型链-查找规则
① 当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性。
② 如果没有就查找它的原型(也就是 __proto__指向的 prototype 原型对象)
③ 如果还没有就查找原型对象的原型(Object的原型对象)
④ 依此类推一直找到 Object 为止(null)
⑤ __proto__对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线
⑥ 可以使用 instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上
这个就和java中的继承中变量的查找类似,优先查找当前类是否有对象,没有则向上查找,最后查不到就返回null,但不同的是java还有修饰符的概念会对继承的变量进行显示,还有就是java中关联父类是通过关键字super来实现的,从而形成关系链,而Js是通过对象原型__proto__对象来实现的
所以这就明白为什么我们创建的数组对象,尽管没有创建有map方法却可以调用,因为我们创建的数组对象的原型对象(prototype)的对象原型(__proro__)是Array,而Array中有对应得map方法,所以就可以用了
面向对象封装消息提示