一、面向对象
1、什么是对象?
- 现实生活中:
- 世间万物皆对象
- 编程中:
- 对单个实物的抽象
- 对象是一个容器,封装了属性property和方法method
- 对象是一个集合,包含了数据集和功能集
- 对象是一个无序属性的集合
2、面向对象
没有属性会报错 没有方法 undefined
- 是一种编程开发思想。它将真实世界各种复杂的关系,抽象为一个个对象,然后由对象之间的分工与合作,完成对真实世界的模拟
3、面向对象的特征
封装、继承、多态
二、创建对象的四种方式
1、字面量
var book = {
price:30,
name:"JavaScript",
knowledge:function(){
console.log(this.name + "赋予我们知识")
},
}
console.log(book.price)//30
book.knowledge() //JavaScript赋予我们知识
2、new Object()
var car = new Object()
car.name = "比亚迪";
car.stop = function(){
console.log(this.name + '可以驻车!')
}
console.log(car)//{name: '比亚迪', stop: ƒ}
car.stop()//比亚迪可以驻车!
3、工厂模式
var createCar = function (color,name,stop) {
var car = new Object()
car.color = color;
car.name = name;
car.stop = stop;
return car//必须要返回
}
var c1 = createCar("黑色","奥迪",function () {
console.log(this.name + "可以在楼下停车")
})
console.log(c1)//{name: '奥迪', color: '黑色', stop: ƒ}
c1.stop()//奥迪可以在楼下停车
4、构造函数
function Person(name,age){
this.name = name
this.age = age
this.study = function() {
console.log(this.name + "喜欢学习")
}
}
var p1 = new Person("小花",10)
console.log(p1)//Person {name: '小花', age: 10, study: ƒ}
p1.study()//小花喜欢学习
三、构造函数和实例化对象的关系
1、实例对象是由构造函数new实例化创建出来的
- 创建一个新对象
- this指向这个新对象
- 返回构造函数中的代码
- 返回新对象
var Cup = function (brand) {
this.brand = brand
}
var cup = new Cup("Lucky")
console.log(cup);//Cup {brand: 'Lucky'}
console.log(cup.constructor)
2、任何对象都有constructor属性,实例化对象的constructor属性指向构造函数
任何对象的constructor属性都是一个构造函数
- js中的对象:自定义对象(car/phone)、DOM对象(div/p)、BOM对象(window/console)、内置对象
// 1、自定义对象
var car = new Object()
console.log(car.constructor)//ƒ Object() { [native code] }
// 2、p标签
var pText = document.getElementById('text')
console.log(pText.constructor) //ƒ HTMLParagraphElement()
// 3、浏览器历史记录
console.log(window.history.constructor)//ƒ History() { [native code] }
// window.history = new History()
// 4、日期
console.log(new Date().constructor) //ƒ Date()
// 5、函数
function a() {}
console.log(a.constructor);//ƒ Function() { [native code] }
四、判断对象
obj instanceof Object
- 如果返回true是对象,返回false不是对象
false null undefined ‘11.2’ 34都是false
var car = {}
var arr = []
var fn = function () {}
console.log(car instanceof Object)//true
console.log(arr instanceof Object)//true
console.log(fn instanceof Object)//true
console.log(12.4 instanceof Object)//false
console.log('23.4' instanceof Object)//false
五、构造函数内存问题
内存的生命周期
- 1、内存的开辟
- 变量的定义:var a
- 函数声明:function a ( ) { }
- 2、内存的使用
- 运算…
- 变量的操作
- 函数的调用
- 3、内存的销毁:JavaScript拥有内存自主回收机制
- 浏览器关闭
- 函数调用后:局部的
构造函数内存有存在浪费问题如何解决
1、将公共的属性定义为全局的
//age定义为全局的-----------------------------
var age = 18
var study = function () {
console.log(this.name+'喜欢学习js')
}
function Person(name,age,sex,study){
this.name = name
this.age = age
this.sex = sex
this.study = study
}
/*var p1 = new Person('小花', 18, '女生', function () {
console.log(this.name + '喜欢学习js')
})
console.log(p1)//Person {name: '小花', age: 18, sex: '女生', study: ƒ}
p1.study()//小花喜欢学习js
*/
//年龄改为age-----------------------------
var p1 = new Person('小花', age, sex, study)
var p2 = new Person('小明', age, sex, study)
console.log(p1)//Person {name: '小花', age: 18, sex: '女生', study: ƒ}
console.log(p2)//Person {name: '小明', age: 18, sex: '女生', study: ƒ}
p1.study()//小花喜欢学习js
p2.study()//小明喜欢学习js
2、原型
原型的作用:
1、节省内存空间
2、实现数据共享(继承)
原型、构造函数、实例化对象三者关系
- 1、任何一个函数都有prototype属性,本身是一个对象
b function fun1() {}
console.log(fn1) //fn1() {}
console.log(fn1.prototype)
console.log(fn1.prototype instanceof Object) //true
console.log(typeof fn1.prototype) //object
- 2、构造函数也有prototype属性,本身是一个对象,我们称之为原型
function Car(name) {
this.name = name
}
Car.prototype.color = "白色"
Car.prototype.playMusic = function () {
console.log("可以播放音乐")
}
var car1 = new Car('比亚迪')
console.log(Car.prototype)
-
3、原型上的属性和方法都可以被实例化对象所继承 (重点)
console.log(car1.color) //白色
-
4、任何一个对象都有constructor属性,实例化对象的constructor属性指向构造函数
var Cup = function (brand) {
this.brand = brand
}
var cup = new Cup("aaa")
console.log(cup.constructor);
- 5、原型也是对象也有constructor属性,原型对象的constructor属性指向构造函数
console.log(Car.prototype.constructor)
console.log(Car.prototype.constructor == Car) //true
- 6、任何一个对象都有
__proto__
属性,实例对象的__proto__
属性指向构造函数的原型
console.log(car1.__proto__)
总结:
![image-20240221152627237](https://img-blog.csdnimg.cn/img_convert/edaf5860f6b04b74111dfd09408fefbf.png)
六、原型链
1、原型链:
- 在
javascript
中每个对象都会有一个__proto__
属性,当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么它就会去__proto__
里去找这个属性,这个__proto__
又会有自己的__proto__
2、原型链最终指向null
3、实例化对象的属性查找规则:
先从构造函数中查找,有就返回,没有就从原型链上查找,有就返回,没有就返回undefined
构造函数-----原型(undefined)------Object原型
function A() { }
A.prototype.n = 1
var b = new A()
A.prototype = {
n: 2,
m: 3
}
var c = new A()
console.log(b.n)//1
console.log(b.m)//undefined 构造函数原型中没有m
console.log(c.n)// 2
console.log(c.m)// 3
- 1、任何一个对象都有
__proto__
属性,实例对象的__proto__
属性指向构造函数的原型
function Cup(brand,capacity) {
this.brand = brand
this.capacity = capacity
}
var cup = new Cup('蒙清','200ml')
console.log(cup.capacity)//200ml
console.log(cup.__proto__ === Cup.prototype);//true
//1、任何一个对象都有__proto__属性,实例对象的__proto__属性指向构造函数的原型
console.log(cup.__proto__ === Cup.prototype) //true
- 2、原型也是对象也有
__proto__
属性,原型对象的__proto__
指向Object构造函数的原型
function Cup(brand) {
this.brand = brand
}
Cup.prototype.capacity = '800ml'
var cup = new Cup('蒙清')
console.log(cup.capacity)//800ml
//2、原型也是对象也有__proto__属性,原型对象的__proto__指向Object构造函数的原型
console.log(Cup.prototype.__proto__ === Object.prototype) //true
- 3、
Object.prototype
也是对象也有__proto__
属性,Object.prototype的__proto__
指向null
function Cup(brand) {
this.brand = brand
}
Object.prototype.capacity = '600ml'
var cup = new Cup('蒙清')
console.log(cup.capacity)//600ml
//3、Object.prototype也是对象也有__proto__属性Object.prototype的__proto__指向null
console.log(Object.prototype.__proto__)//null
4、额外的补充:
- 局部变量转变成全局
function fn1(aa) {
var num = 67
aa.num = num
}
fn1(window)
console.log(num)//67
七、改变this指向的方法
相同点:
- (b.)可以改变this的指向,如果没有参数,this指向window
- (c.)可以改变this的指向,如果有一个参数,this指向该参数
1、call()
(a.)可以进行函数的调用
var name = '小花'
function fn1() {
console.log('我是函数声明')
}
fn1()//我是函数声明
fn1.call()//我是函数声明
(b.)可以改变this的指向,如果没有参数,this指向window
var name = "小花"
var obj1 = {
name: '小明',
getName: function () {
console.log(this.name)
},
}
obj1.getName.call()//小花
(c.)可以改变this的指向,如果有一个参数,this指向该参数
var name = "小花"
var obj2 = {
name: '小刚',
getName: function () {
console.log(this.name)
},
}
obj1.getName.call(obj2)//小刚
(d.)可以改变this的指向,如果有多个参数,this指向第一个参数,剩下的是个参数列表(构造函数继承的案例)
2、apply()
(a.)可以进行函数的调用
(b.)可以改变this的指向,如果没有参数,this指向window
(c.)可以改变this的指向,如果有一个参数,this指向该参数
(d.)可以改变this的指向,如果有多个参数,第一个参数是null或者window,第二个参数是数组
console.log(Math.max(30, 40, 50)) //50
console.log(Math.max.apply(null, [30, 40, 50])) //50
console.log(Math.max.apply(window, [30, 40, 50])) //50
3、bind()
(a.)不可以进行函数的调用
(b.)可以改变this的指向,如果没有参数,this指向window
var name = "小花"
function fn1() {
console.log('我是函数生命')
}.bind()
fn2()//小花
(c.)可以改变this的指向,如果有一个参数,this指向该参数
var name = '小花'
fn2()//小花
var obj2 = {
name: '小刚',
getName: function () {
console.log(this.name)
},
}
var obj3 = {
name: '小丽',
getName: function () {
console.log(this.name)
}.bind(obj2)//小刚
}
八、函数中this指向
如果是实例对象调用,this指向实例化对象
如果是原型对象调用,this指向原型对象
function Cup(name) {
this.name = name
this.drink = function () {
console.log(this.name + "可以用来喝水")
}
}
Cup.prototype.name = "我是原型"
var cup = new Cup("小米水杯")
cup.drink()//中的this指向小米水杯
console.log(Cup.prototype.name)//输出我是原型