前端之路(JS高级篇)

本文详细探讨了JavaScript中的面向对象编程,包括对象的基本概念、创建对象的多种方式及其优缺点,重点讲解了原型和原型链的概念、构造函数与实例之间的关系,以及原型链的查找原则。此外,还介绍了Object.prototype成员、闭包以及正则表达式的基础知识,深入剖析了函数的多种调用模式和作用域。
摘要由CSDN通过智能技术生成

面向对象编程

什么是对象??

(1) 从视觉角度 : 对象是单个事物的抽象。

一本书、一个人都可以是对象,一张网页、一个与远程服务器的连接也可以是对象。当实物被抽象成对象,实物之间的关系就变成了对象之间的关系,从而就可以模拟现实情况,针对对象进行编程。

(2) 从编程角度 : 对象是无序键值对的集合,其属性可以包含基本值、对象或者函数等等

每个对象都是基于一个引用类型创建的,这些类型可以是系统内置的原生类型,也可以是开发人员自定义的类型。

 

什么面向对象 ?

面向对象编程 —— Object Oriented Programming,简称 OOP ,是一种编程开发思想。

它将真实世界各种复杂的关系,抽象为一个个对象,然后由对象之间的分工与合作,完成对真实世界的模拟。
​
在面向对象程序开发思想中,每一个对象都是功能中心,具有明确分工,可以完成接受信息、处理数据、发出信息等任务。
​
因此,面向对象编程具有灵活、代码可复用、高度模块化等特点,容易维护和开发,比起由一系列函数或指令组成的传统的过程式编程(procedural programming),更适合多人合作的大型软件项目。

员工才面向过程,老大都是面向对象

面向对象与面向过程:

  • 面向过程就是亲历亲为,事无巨细,面面俱到,步步紧跟,有条不紊,面向过程是解决问题的一种思维方式,关注点在于解决问题的过程。

  • 面向对象就是找一个对象,指挥得结果,解决问题的思维方式,关注点在解决问题的对象上。

  • 面向对象将执行者转变成指挥者

  • 面向对象不是面向过程的替代,而是面向过程的封装

面向对象的特性:
​
- 封装性
  - 将功能的具体实现,全部封装到对象的内部,外界使用对象时,只需要关注对象提供的方法如何使用,而不需要关心对象对象的内部具体实现,这就是封装。
- 继承性
  - 在js中,继承的概念很简单,一个对象没有的一些属性和方法,另外一个对象有,<!-- 拿过来用,就实现了继承。-->
  - 注意:在其他语言里面,继承是类与类之间的关系,在js中,是对象与对象之间的关系。
- [多态性]
  - 多态是在强类型的语言中才有的。js是弱类型语言,所以JS不支持多态。

创建对象的方式:

单独创建 ( 2种 ) 和 批量创建 ( 2种 )

字面量创建对象

缺点 : 不能很方便的批量创建

var person = {
  name: 'Jack',
  age: 18,
  sayName: function () {
    console.log(this.name)
  }
}

构造函数 Object 创建对象

缺点 : 属性要一个一个的添加,也是 不能很方便的批量创建,

//在js中,对象有动态特性,可以随时的给一个对象增加属性或者删除属性。
var person = new Object()
person.name = 'Jack'
person.age = 18
​
person.sayName = function () {
  console.log(this.name)
}

工厂函数 创建对象

缺点 : 但却没有解决对象识别的问题,创建出来的对象都是Object类型的。

// 工厂函数
function createPerson (name, age) {
  return {
    name: name,
    age: age,
    sayName: function () {
      console.log(this.name)
    }
  }
}
// 实例对象
var p1 = createPerson('Jack', 18)
var p2 = createPerson('Mike', 18)

自定义构造函数创建

function Person (name, age) {
  this.name = name
  this.age = age
  this.sayName = function () {
    console.log(this.name)
  }
}
​
var p1 = new Person('Jack', 18)
p1.sayName() // => Jack
​
var p2 = new Person('Mike', 23)
p2.sayName() // => Mike

注意点:

1. 构造函数 => 函数 + 首字母大写
2. 构造函数要配合new操作赋一起使用才有意义
3. new的作用 :   (牢记)
    - 创建一个新对象
    - this指向了这个新对象
    - 执行构造函数, 给对象添加属性和方法
    - 返回新对象
4. 构造函数的作用 : 实例化对象 即:给对象赋值,添加属性和方法

构造函数的缺点 :

使用构造函数带来的最大的好处就是创建对象更方便了,但是其本身也存在一个浪费内存的问题:

function Person (name, age) {
  this.name = name
  this.age = age
  this.type = 'human'
  this.sayHello = function () {
    console.log('hello ' + this.name)
  }
}
​
var p1 = new Person('lpz', 18)
var p2 = new Person('Jack', 16)
console.log(p1.sayHello === p2.sayHello) // => false

解决方案 :

// 全局声明的
function sayHello () {
  console.log('hello ' + this.name)
}
​
function Person (name, age) {
  this.name = name
  this.age = age
  this.type = 'human'
    // 先有的sayHello,  你再去指引的
  this.sayHello = sayHello
}
​
​
var p1 = new Person('lpz', 18)
var p2 = new Person('Jack', 16)
​
console.log(p1.sayHello === p2.sayHello) // => true

缺点:会暴漏很多的函数,容易造成全局变量污染。

 

原型

原型的基本概念

Javascript 规定,每一个构造函数都有一个 prototype 属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数( Person() )的实例 ( p、p1等 )继承 。 这个对象就是原型,也叫原型对象。

这也就意味着,我们可以把所有对象实例需要共享的属性和方法直接定义在 prototype 对象上。

原型的作用 : 共享数据 (也解决了构造函数资源浪费的问题)

// 原型:
//1. 在js中, 任何一个函数,都会自带一个属性 prototype, 这个属性指向了一个对象
//2. 这个prototype属性,也就是这个对象,我们叫做原型 ; (原型对象)
// 这个原型属性是一个对象
//3. 通过构造函数创建的对象,可以直接访问这个构造函数的原型中的所有内容(属性和方法)
//4. 最常用的就是 : 给构造函数的原型添加一个方法

代码 :

function Person (name, age) {
  this.name = name
  this.age = age
}
​
// dir 或者  log
console.log(Person.prototype)
​
Person.prototype.type = 'human'
​
Person.prototype.sayName = function () {
  console.log(this.name)
}
​
var p1 = new Person(...)
var p2 = new Person(...)
​
console.log(p1.sayName === p2.sayName) // => true  解决了内容浪费的问题

这时所有实例的 type 属性和 sayName() 方法,其实都是同一个内存地址,指向 prototype 对象,因此就提高了运行效率。

 

构造函数、实例、原型三者之间的关系 (★★★)

构造函数 (Person):构造函数就是一个函数,配合new可以新建对象。

实例 (p1, p2):通过构造函数实例化出来的对象我们把它叫做构造函数的实例。一个构造函数可以有很多实例。

原型 (Person.prototype) :每一个构造函数都有一个属性prototype,这个属性就叫做原型对象。通过构造函数创建出来的实例能够直接使用原型上的属性和方法。

 

构造+实例p,打印Person,有prototype属性,画图分配空间,newp,访问原型 p1亦是

注意:方法是给原型加,不是给构造函数加,方法是原型里的方法

继承关系:

实例对象p, 从Person.prototype里访问属性和方法,,这就叫继承 ; (拿过来用)

也就是说 :以后p想要找某个属性或者某个方法,,如果自己没有,,试着去看下原型里是否有

思考:内置对象中,有很多的方法,这些方法存在哪里?

var arr = [] , arr.push() Array.prototype;

var str = 'abc' str.indexOf() => String.prototype

__proto__ (★)

实例对象p和原型对象的关系呢?

通过构造函数创建的对象,自带一个__proro__属性,这个属性指向了构造函数的prototype属性,也就是原型对象。

获取原型对象:

  • 通过构造函数.prototype可以获取

  • 通过实例.__proto__可以获取(隐式原型)

  • 它们指向了同一个对象构造函数.prototype === 实例.__proto__

  • 又因为是浅白色,,这种是私有属性,,不可遍历的,,,,,不要用它来添加属性和方法,,只负责来检测它的原型即可

  console.log(p.__proto__ === Person.prototype);

关系确立

1. 构造函数 是 妈妈,,妈妈只负责生孩子,,创建对象p
2. 原型对象是 爸爸,,,,实例对象能够继承原型对象的属性和方法

constructor属性 (☆)

默认情况下,原型对象中值包含了一个属性:constructor,constructor属性指向了当前的构造函数。

 

原型链

属性查找原则

构造函数实例化的对象 p , 能够访问原型对象里的全部属性和方法

  • 如果是获取操作

  • 沿着 __proto__ 一直往上找

    1. 会先在自身上查找,如果没有
    2. 则根据__proto__对应的原型去找,如果没有
    3. 一直找到Object.prototype,如果没有,那就找不到了。
  • 如果是修改操作

    //1. 只会修改对象自身的属性,
    //2. 如果自身没有这个属性,那么就会添加这个属性,并不会修改原型中的属性。

原型链概念

任何一个对象,都有原型对象,原型对象本身又是一个对象**,所以原型对象也有自己的原型对象,这样一环扣一环就形成了一个链式结构,我们把这个链式结构称为原型链。

__ proto __

//1. var s = new Strudent();
//2. var o = new Object();
//3. var arr = new Array();;
//4. var date = new Date();
//5. Math

总结:Object.prototype是原型链的尽头,Object.prototype的原型是null。

画图的本质 :

1. 通过打印 : p.__proto__ (原型对象)  来找
2. 找到  p.__proto__ (原型对象里的) constructor 的属性
3. 找到构造函数 其他的就解决了
​
​
  //var date = new Date();
  //  date ==> date.__proto__(Dat
  • 9
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值