1.面向对象编程
面向对象是把事务分解成为一个个对象,然后由对象之间分工与合作
面向对象的特性:
1.封装性 2.继承性 3.多态性
面向过程编程
优点:性能比面向对象高,适合跟硬件联系很紧密的东西,例如单片机就采用的面向过程编程。
缺点:没有面向对象易维护、易复用、易扩展
面向对象编程
优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系 统,使系统 更加灵活、更加易于维护
缺点:性能比面向过程低
案例说明
<body>
<div>div1</div>
<div>div2</div>
<div>div3</div>
<p>p1</p>
<p>p2</p>
<p>p3</p>
<p>p4</p>
<script>
let divList = document.querySelectorAll("div")
let pList = document.querySelectorAll("p")
let obj = {
setColor: function(list, color) {
for (let i = 0; i < list.length; i++) {
list[i].style.backgroundColor = color
}
},
setBorder: function(list, border) {
for (let i = 0; i < list.length; i++) {
list[i].style.backgroundColor = border
}
}
}
obj.setColor( divList, "red")
obj.setColor(pList, "cyan")
</script>
</body>

2.原型
构造函数通过原型分配的函数是所有对象所 共享的
JavaScript 规定,每一个构造函数都有一个 prototype 属性,指向另一个对象,所以我们也称为原型对象

3.给数组扩展求最大值方法,最小值方法和求和方法
<script>
const arr = [1, 2, 3]
Array.prototype.max = function () {
return Math.max(...this)
}
Array.prototype.min = function () {
return Math.min(...this)
}
console.log(arr.max())
console.log(arr.min())
console.log([2, 5, 9].max())
Array.prototype.sum = function () {
return this.reduce((prev, item) => prev + item, 0)
}
console.log([2, 5, 9].sum())
</script>
求最大值方法,最小值方法和求和方法
<script>
Array.prototype.getMax = function () {
return Math.max(...this)
}
let arr = [10, 20, 30]
let ret = arr.getMax()
console.log(ret);
Array.prototype.getMin = function () {
return Math.min(...this)
}
let arr2 = [10, 20, 90]
let ret2 = arr2.getMin()
console.log(ret2);
Array.prototype.getSum = function () {
return this.reduce(function (pre, item) {
return item + pre
}, 0)
}
let arr1 = [10, 20, 90]
let ret1 = arr1.getSum()
console.log(ret1);
</script>
4.对象原型
__proto__ 是JS非标准属性
[[prototype]]和__proto__意义相同
用来表明当前实例对象指向哪个原型对象prototype
__proto__对象原型里面也有一个 constructor属性,指向创建该实例对象的构造函数
对象都会有一个属性 __proto__ 指向构造函数的 prototype 原型对象,之所以我们对象可以使用构造函数 prototype
原型对象的属性和方法,就是因为对象有 __proto__ 原型的存在

5.原型对象
语法:
function Person() {
}
console.log(Person.prototype);
原型对象具体的作用,如下代码所示:
function Person() {
}
Person.prototype.sayHi = function () {
console.log('Hi~');
}
let p1 = new Person();
p1.sayHi();
构造函数 Person 中定义与原型对象中相同名称的方法,这时实例对象调用则是构造函中的方法 `sayHi
当访问对象的属性或方法时,先在当前实例对象是查找,然后再去原型对象查找,并且原型对象被所有实例共享。
function Person() {
this.sayHi = function () {
console.log('嗨!' + this.name);
}
}
Person.prototype.sayHi = function () {
console.log('Hi~' + this.name);
}
Person.prototype.name = '小明';
let p1 = new Person();
p1.sayHi();
let p2 = new Person();
p2.sayHi();

6.原型继承
function Person() {
this.eyes = 2
this.head = 1
}
function Woman() {
}
Woman.prototype = new Person()
Woman.prototype.constructor = Woman
Woman.prototype.baby = function () {
console.log('宝贝')
}
const red = new Woman()
console.log(red)
function Man() {
}
Man.prototype = new Person()
Man.prototype.constructor = Man
const pink = new Man()
console.log(pink)

// Person 构造函数
function Person() {
this.arms = 2
this.walk = function () {}
}
// Person 原型对象
Person.prototype.legs = 2
Person.prototype.eyes = 2
Person.prototype.sing = function () {}
Person.prototype.sleep = function () {}
// Chinese 构造函数
function Chinese() {
this.skin = 'yellow'
this.language = '中文'
}
// Chinese 原型对象
Chinese.prototype = new Person()
Chinese.prototype.constructor = Chinese
// 实例化
let c1 = new Chinese()
console.log(c1)
// 将Man与Woman共有设置在Human中
function Human(){
this.head = 1
this.eyes = 2
this.legs = 2
this.say = function(){console.log('hello')
this.eat = function(){}
}
// 对Human进行实例化,得到实例obj_M
let obj_M = new Human()
console.log(obj_M)
function Man(){
}
// 再使用obj_M对象,替换Man的默认原型
Man.prototype = obj_M
let oM1 = new Man()
oM1.say()
let oM2 = new Man()
oM2.say()
let obj_W = new Human()
function Woman(){
}
// 再使用obj_W对象,替换Woman的默认原型
Woman.prototype = obj_W
let oW1 = new Woman()
oW1.say()
/*
小结:
用户解释:
Human(父),Man与Woman(子)
如何实例继承:
使用父的实例对象,来替换子的默认原型
使用指导:
公共的保存到父上
独有保存到子
//父对象
let father = {
house:{
address : '深圳湾一号',
price: 20000000
},
car:{
brand : '劳斯莱斯幻影',
price:15000000
}
}
//子对象
//构造函数
function Son(name,age){
this.name = name
this.age = age
}
//原型继承: 把父对象 作为子对象构造函数的原型
Son.prototype = father
//可选 : 原型继承之后,由于父对象覆盖原来的 子对象构造函数原型, 就会导致constructor消失.
//解决办法: 手动添加。(对开发几乎没有影响,也可以不加)
Son.prototype.constructor = Son
//实例对象
let s1 = new Son('ikun',30)
let s2 = new Son('班长',20)
console.log(s1,s2)
7.原型链
每一个对象都有自己的原型, 而原型也是对象,也会有自己的原型,此次类推形成链式结构。称之为原型链。(原型链的终点是null)

function Person(){
}
let p1 = new Person();
console.log(p1.__proto__);
console.log(p1.__proto__.__proto__);
console.log(p1.__proto__.__proto__.__proto__);
console.log(Object.prototype === p1.__proto__.__proto__);
console.log(p1.__proto__.__proto__.constructor === Object);
小结:
原型链,就由原型对象形成的一个链条
.prototype 这个属性只有函数有
.__proto__ 所有对象都有(实例对象,函数,原型对象)
原型链-查找规则
原型链是找成员
当一个对象访问某个成员时,如果成员不存在,则会向上一级原型对象上找,
上一级原型对象上没有,再向上一级找,直到找到null
并且具有就近原则
function Person(){
this.age = 20;
}
Person.prototype.age = 22;
Person.prototype.__proto__.age = 24;
let p1 = new Person();
console.log(p1.age);
查找规则:
原型找成员
作用域链,找变量
function Person(name,age){
this.name = name
this.age = age
}
Person.prototype.type = '哺乳动物'
Person.prototype.country = '中国'
Person.prototype.eat = function(){
console.log(this.name + '吃东西')
}
let p1 = new Person('班长',20)
let p2 = new Person('ikun',20)
console.log(p1)
console.log( p1.name )
console.log( p1.age )
console.log( p1.type )
console.log( p1.girlFrined )
p1.eat()
p1.toString()
console.log( p1.__proto__.constructor )
console.log( Person.prototype === p1.__proto__ )
console.log( p1.__proto__.__proto__.constructor )
console.log( Object.prototype === p1.__proto__.__proto__ )
console.log( p1.__proto__.__proto__.__proto__ )

8.instanceof 函数
function Person() {}
let p1 = new Person()
function Mobile() {}
let m1 = new Mobile()
console.log(p1 instanceof Person);
console.log(p1 instanceof Mobile);
console.log(m1 instanceof Mobile);
案例
<script>
console.log(Object.prototype)
console.log(Object.prototype.__proto__)
function Person() {
}
const ldh = new Person()
console.log(ldh instanceof Person)
console.log(ldh instanceof Object)
console.log(ldh instanceof Array)
console.log([1, 2, 3] instanceof Array)
console.log(Array instanceof Object)
9. 构造函数
构造函数 公共的属性和方法 封装到Star构造函数里面
1.公共的函数写到构造函数里面
function Star(uname, age) {
this.uname = uname
this.age = age
}
Star.prototype.sing = function () {
console.log('唱歌');
}
const ldh = new Star('刘德华', 55)
const zxy = new Star('张学友', 58)
ldh.sing()
zxy.sing()
console.log(ldh.sing === zxy.sing);
构造函数的this
let that
function Star(uname) {
this.uname = uname
}
Star.prototype.sing = function () {
that = this
console.log('唱歌')
}
const ldh = new Star('刘德华')
ldh.sing()
console.log(that === ldh)
*1. 构造函数内部方法: 浪费内存资源
思考: p1和p2都有eat方法,而是函数体相同。为什么他们不是同一个函数?
function Person(name,age){
this.name = name
this.age = age
this.eat = function(){
console.log('eat');
}
}
let p1 = new Person('张三',18)
let p2 = new Person('李四',20)
console.log( p1,p2)
console.log( p1.eat == p2.eat )
因为每一次调用构造函数, 内部都会执行一次function,就会在堆中开辟一个新的空间。
虽然代码是一样的,但是地址不同。 就会导致每调用一次构造函数,多出一个函数堆空间。
导致内存资源浪费
**2. 使用全局函数解决内存浪费
思考题:p1的eat和p2的eat是不是同一个?
let eat = function() {
console.log("吃东西")
}
let learn = function() {
console.log("学习")
}
function Person(name, age) {
this.name = name
this.age = age
this.eat = eat
this.learn = learn
}
let p1 = new Person("张三", 18)
let p2 = new Person("李四", 20)
console.log(p1, p2)
console.log( p1.eat == p2.eat )
因为构造函数内部并没有重新function创建一个函数,而是拷贝eat的地址赋值。
无论你调用构造函数多少次,都是拷贝eat的地址
*** 3.使用对象 : 解决构造函数内存浪费 + 变量污染
let obj = {
eat: function() {
console.log("吃东西")
},
learn: function() {
console.log("学习")
}
}
function Person(name, age) {
this.name = name
this.age = age
this.eat = obj.eat
this.learn = obj.learn
}
let p1 = new Person("张三", 18)
let p2 = new Person("李四", 20)
console.log(p1, p2)

****使用对象后,构造函数可以直接调用对象里面的函数

原型对象----prototype
1.原型对象是什么? : 任何函数在声明的时候,系统会自动帮你创建一个对象,称之为原型对象
2.原型对象作用? : 解决 内存浪费 + 变量污染
function Person(name, age) {
this.name = name
this.age = age
}
console.log(Person.prototype)
Person.prototype = {
eat: function() {
console.log("吃东西")
},
learn: function() {
console.log("学习")
}
}
let p1 = new Person('张三',20)
console.log( p1 )
let p2 = new Person('李四',22)
console.log( p1.eat == p2.eat )
原型对象相关三个属性 : 描述 构造函数、原型对象、实例对象三者关系
prototype : 属于构造函数, 指向原型对象
作用 : 解决 内存浪费 + 变量污染
proto : 属于实例对象,指向原型对象
作用: 让实例对象访问原型中的成员
constructor : 属于原型对象,指向构造函数
作用: 可以让任何实例对象知道自己是谁创建的
例如: console.log( p1.__proto__.constructor )
function Person(name,age){
this.name = name
this.age = age
}
Person.prototype.eat = function(){
console.log('吃东西')
}
Person.prototype.learn = function(){
console.log('学习')
}
console.log( Person.prototype.constructor )
let p1 = new Person('张三',20)
console.log(p1)
p1.eat()
console.log( p1.__proto__.constructor )
console.log( Person.prototype === p1.__proto__ )

