面向对象
是编程思想,JAVA
、PHP
、C#
、C++
、.net(dot net)
、JS
…这些都是面向对象编程的
面向过程
编程思想:C语言
是面向过程的
html、css
:是标记语言
不是编程语言,没有所谓的面向对象编程less、sass:属于css预编译语言,旨在把css变为编程语言(面向对象的编程语言)
面向对象
JS本身就是
基于面向对象创造出来的语言,而非是面向对象的语言
JS
可以模拟
实现继承
和封装
,但是无法模拟
实现多态
,所以我们说JS是一门基于对象的语言
,而非是面向对象的语言
。
JavaScript是通过原型(prototype)来实现面向对象编程
面向对象的三大特性:
1、封装
隐藏对象的属性和实现细节,仅对外提供公共访问方式
,将变化隔离,便于使用,提高复用性和安全性
。
2、继承
提高代码复用性
;继承是多态的前提。
3、多态
父类或接口定义的引用变量可以指向子类或具体实现类的实例对象
。提高了程序的拓展性。
对象、类、实例
对象
:编程语言中的对象是泛指,万物皆对象(我们所要研究学习以及使用的都是对象)
类
:是抽象的。对象的具体细分(按照属性或者特性细分为一些类别)
实例
:是具体的。某一类中具体的事物(对象数据类型)
实例就是一个对象
[实际生活当中]
+人
+正常人类
+程序员类
我就是程序员类别中的一个实例
JS中常用的内置类
- 关于数据类型的:
Number
:每一个数字或者NaN是它的一个实例String
:字符串类Boolean
:布尔类Null
Undefined
:浏览器屏蔽了我们操作Null或者Undefined这个类Object
:对象类,每一个对象数据类型都是它的实例Array
:数组类RegExp
:正则类Date
:日期类- …
Function
:函数类,每一个函数都是它的一个实例
- 关于元素对象和元素集合的
HTMLCollection
:元素集合类NodeList
:节点集合类HTMLDivElement
: html div标签类HTMLElement
: html标签类Element
: 标签类Node
: 节点类EventTarget
: 事件对象类
每一个HTML标签都有一个自己所属的内置类
1 | //获取元素集合类 |
1 | //获取节点集合类方法: |
目前阶段学习面向对象对于我们的意义
研究数组:
1、创建一个数组的实例,研究其基础语法和结构
2、如果想要研究数据具备的功能方法,我们只需要看Array/Object这些类上都赋予了它什么样的方法
问题
document.getElementById
它的上下文
只能是document
,为什么其他的不可以?(控制台dir(document))?
因为
getElementById
这个方法只有Document这个类才有
,其他标签类上没有;并且document
是Document
的实例,所以document
才能使用这个方法
我们遇到一个数据(对象)时 先考虑它是谁的实例,这个类提供给了它什么方法
基于面向对象创建数据值
1 | //=>字面量创建方式 |
两种创建方式在核心意义上没有区别,都是创建Array这个类的一个实例,但是语法上是有区别的
- 1、字面量创建方式传递什么进来,都是给数组加入内容
- 2、构造函数创建方式
new Array(10)
;//创建一个长度为10的数组,数组中的每一项都是空new Array('10')
;如果只传递一个实参
并且实参不是数字
,相当于把当前值``作为
数组的第一项存储进来
new Array(10,20,30)
; //如果传递多个实参
,不是设置长度,而是把传递的内容当做数组中的每一项存储起来
1 | var obj={name:'哈哈哈'} |
1 | var num=12; //字面量创建出来的是一个基本数据类型值(但是也是Number的一个实例,可以调取Number赋予它的方法) |
严谨的面向对象中,所有类创建实例都得通过new方式创建,创建出来的结果不可能出现基本数据类型值,都是对象数据类型值
但是基本数据类型值 都是对应类的一个实例 都能使用对应类的方法
构造函数设计模式(constructor)
在js当中,当我们使用
new XXX()
执行函数的时候,此时的函数就不是普通的函数了,而是变为一个类,返回的结果叫做当前类的实例(对象数据类型的this),我们把这种new XXX()执行的方式称之为构造函数设计模式
使用构造函数方式,主要是为了创建类和实例的,也就是基于面向对象编程思想来实现一些需求的处理
1 | function Fn(name,age,job){ |
普通函数执行
VS 构造函数执行
普通函数执行
1、开辟一个新的 私有作用域
2、把创建函数的字符串 复制过来 变为真正的js表达式
3、形参赋值
4、变量提升
5、代码自上而下执行(return 后面的值就是当前函数返回的结果)
6、栈内存释放或者不释放问题
1 | function fn(num){ |
构造函数执行
1、首先和普通函数执行一样,也需要开辟一个新的私有作用域
2、把创建函数的字符串 复制过来 变为真正的js表达式
3、在私有作用域中完成类似于普通函数的操作:形参赋值、变量提升
4、在代码自上而下执行之前 构造函数有属于自己的比较特殊的操作:“浏览器” 会在当前作用域当中默认创建一个对象数据类型的值(开辟堆内存),并且会让当前函数中的 “执行主体(this)指向创建出来的对象”
5、像普通函数一样自上而下执行构造函数代码:this.XXX=XXX这些操作都是给默认创建的这个对象增加属性名和属性值
6、代码执行完成以后,即使函数中没有return ,在构造函数模式中:浏览器会默认的把创建的对象返回到函数的外面
(相当于 默认 return this;)
构造函数执行,既具备普通函数执行的一面,也具备自己独有的一些操作
在构造函数执行期间,浏览器默认创建的对象(也就是函数体中的this)就是当前这个类的一个实例,浏览器会把默认创建的实例返回,所以我们说:new Fn()执行,Fn是一个类,返回的结果是Fn这个类的一个实例
构造函数执行,构造函数体中的this是当前类的实例
(就是一个json)
实例是对象数据类型(json)
1 | function Fn(num){ |
深入理解构造函数执行的步骤
当构造函数或者类,执行的时候不需要传递任何的实参时,此时我们是否加小括号就不重要了(不传递实参的情况下,小括号可以省略)
构造函数执行同时具备了普通函数执行的一面 也有自己特殊的一面,
但是和实例相关的只有自己特殊的一面
(也就是this.XXX=XXX才相当于给当前实例增加的属性)
函数体中出现的私有变量,和实例都没有直接的关系,只有this.XXX=XXX才和实例有关
在构造函数中,使用var,function声明的变量称为私有变量
;私有变量的作用域,只在构造函数内容有效
。即只能在构造函数内部使用,在构造函数外部,无论使用对象名还是类名都无法调用
通过类创建出来的每一个实例都是单独的个体(单独的堆内存空间),实例和实例之间是不相同并且独立互不影响的(
市面上部分开发把这种模式叫做单例模式,这种说法是错的,js当中这种模式叫做构造函数设计模式
)
在构造函数体中通过this.XXX=XXX给实例设置的属性都是当前实例的私有属性
构造函数体(默认返回的是实例:对象类型值)当我们自己手动设置了return时,return的是基本类型值时
,对最后返回的实例没有任何影响
,但是如果返回的是引用数据类型的值时
,会把默认返回的实例替换掉不再是实例
1 | function Fn(){ |
1 | function Fn(){ |
XX instanceof YY:测当前实例xx是否属于某个类yy
instanceof:用来检测当前实例xx是否属于某个类yy
instanceof解决了typeof无法识别是数组还是正则的问题
检测数据类型:typeof,instanceof,constructor,object.prototype.tostring.call
1 | function Fn(){ |
hasOwnProperty VS in
XX.hasOwnProperty(YY): 检测当前这个属性YY是不是XX这个对象的私有属性(不仅要是对象的属性,而且需要是私有的才可以)
YY in XX:用来检测当前这个属性YY是否隶属于对象XX(不管是对象的私有属性还是公有属性,只要有返回的就是 true)
1 | var obj={ |
1 | function Fn(){ |
检测一个属性是否是当前对象的公有属性
1、是对象的一个属性
2、不是对象的私有属性
1 | function hasPubProperty(attr,obj){ |