面向对象是一种程序的设计思想,与之对应的编程思想叫做面向过程
**例如:**比如我想要用代码描述一个场景,有一只叫做xiaoA的猫,吃了一个苹果,又吃了一条鱼,然后有一只叫做xiaoB的猫,吃了一根香蕉
// 面向过程
function xiaoAEatApple() {
}
function xiaoAEatFish() {
}
function xiaoBEatBanana() {
}
xiaoAEatApple();
xiaoAEatFish();
xiaoBEatBanana();
// 面向对象
function Cat(name) {
this.name = name
}
Cat.prototype.eat = function(something) {
}
let xiaoA = new Cat('xiaoA')
let xiaoB = new Cat('xiaoB')
xiaoA.eat('apple')
xiaoA.eat('fish')
xiaoB.eat('banana')
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script>
// 普通方法
// let carA = {
// name: 'xiaoA',
// eat() {
// console.log('xiaoA eat something')
// }
// }
// let carB = {
// name: 'xiaoB',
// eat() {
// console.log('xiaoB eat something')
// }
// }
// let carC = {
// name: 'xiaoC',
// eat() {
// console.log('xiaoC eat something')
// }
// }
// 代码重复量多,需要封装
// 封装
// 使用工厂模式封装
// function createCat(name) {
// let obj = {}
// obj.name = name;
// obj.eat = () => {
// console.log(name + 'eat something')
// }
// return obj;
// }
// let catA = createCat(xiaoA)
// let catB = createCat(xiaoB)
// let catC = createCat(xiaoC)
// 使用面向对象的方式进行封装
function CreateCat(name) {
// 构造函数
this.name = name;
this.eat = () => {
console.log(this.name + 'eat something')
}
}
let catA = new CreateCat('xiaoA')
let catB = new CreateCat('xiaoB')
let catC = new CreateCat('xiaoC')
</script>
</head>
<body>
</body>
</html>
// this
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script>
// this
// 在函数执行的时候会在函数内部创建两个变量,arguments, this
// arguments是存储着实参的一个类数组变量
// this 指向函数的执行上下文 (谁调用这个函数, this就指向谁)
function aaa (a, b) {
console.log(arguments)
}
aaa(1, 2, 3, 4)
// 数组 var arr = {1, 2, 3, 4}
// 类数组对象 var arrObj = {0: 1, 1: 2, 2: 3, 3: 4, length: 4}
function bbb() {
console.log(this)
}
var objA = {
b: bbb,
c: {
d: bbb,
}
}
bbb(); // this 指向 window
objA.b() // this 指向 objA
objA.c.d(); // this 指向 objA.c
</script>
</head>
<body>
</body>
</html>
// call-apply
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script>
// call apply 用来动态改变this的指向
// function aaa() {
// console.log(this)
// }
// var objA = {
// b: aaa
// }
// aaa() // this 指向window
// objA.b() // this 指向objA
// aaa.call(objA); // call 函数将aaa内的this 从指向 window 改成了 指向objA
// objA.b.call(window); // call 函数将aaa内的this 从指向 objA 改成了 指向window
function aaa(name, age) {
// console.log(this)
this.name = name
this.age = age
}
var objA = {
b: aaa
}
aaa.call(objA, 'xiaoA', 23); // call 函数将aaa内的this 从指向 window 改成了 指向objA
console.log(objA.name, objA.age); // 打印 xiaoA 23
objA.b.call(window, ['xiaoB', 30]); // call 函数将aaa内的this 从指向 objA 改成了 指向window
console.log(window.name, window.age)
objA.b.call(window, 'xiaoB', 30); // call 函数将aaa内的this 从指向 objA 改成了 指向window
console.log(window.name, window.age)
objA.b.apply(window, ['xiaoB', 30]); // call 函数将aaa内的this 从指向 objA 改成了 指向window
console.log(window.name, window.age)
</script>
</head>
<body>
</body>
</html>
new 做了哪些操作
1.创建一个空对象
2.将构造函数的prototype属性赋值给新对象的__proto__属性
3.将构造函数的this指向新对象
4.执行构造函数的代码
5.将新对象返回
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script>
function CreateCat(name) {
this.name = name
}
let catA = new CreateCat('xiaoA')
console.log(catA.name)
/*
new 做了哪些操作
1.创建一个空对象
2.将构造函数的prototype属性赋值给新对象的__proto__属性
3.将构造函数的this指向新对象
4.执行构造函数的代码
5.将新对象返回
*/
// 闭包,自执行函数
var catB = (function() {
var obj = {
}
obj.__proto__ = CreateCat.prototype;
CreateCat.call(obj, 'xiaoB');
return obj
})()
console.log(catB.name)
</script>
</head>
<body>
</body>
</html>
在声明函数的时候,会自动创建一个prototype属性,我们管他叫做原型, 一般用来存放实例公用的方法
prototype:
是子类继承的父类的属性,也就是当调用子类构造函数时,总的来说,这里只能是继承一个具体的对象,不能是一个类(es6后会有所改变)
prototype内容:
__proto__内容
是类继承父类之后,子类对象中的父类属性,里面的属性是可以通过子类对象直接取的,不需要用__proto__。
这里检索逻辑是:
先检索子类的直接属性是否存在,然后再检索__proto__,然后就是俄罗斯套娃,一层一层套下去,到最后还是没有就返回 undefined
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script>
/*
new 做了哪些操作
1.创建一个空对象
2.将构造函数的prototype属性赋值给新对象的__proto__属性
3.将构造函数的this指向新对象
4.执行构造函数的代码
5.将新对象返回
*/
// 在声明函数的时候,会自动创建一个prototype属性,我们管他叫做原型, 一般用来存放实例公用的方法
function CreateCat(name) {
this.name = name;
}
// console.log('prototype:', CreateCat.prototype)
CreateCat.prototype.eat = function(something) {
console.log(this.name + ' eat ' + something)
}
var catA = new CreateCat('xiaoA')
catA.eat('fish')
/*
carA:
1. {} // 第一步创建新对象
2. {
__proto__: CreateCat.prototype
}
3. {
__proto__: CreateCat.prototype,
name: 'xiaoA'
}
4.执行构造函数的代码
5.return
*/
// 在JS里规定,访问对象属性的时候,如果对象下面没有这个属性,则去他下面的__proto__去寻找,如果没有,就一直向下寻找直到没有__proto__为止
console.log(catA)
// 类式继承
function A(name) {
this.name = name;
this.list = [1, 2, 3]
}
A.prototype.getName = () => {
console.log(this.name);
}
function SubA(name) {
this.subName = 'sub' + this.name;
}
SubA.prototype = new A()
var sa1 = new SubA('sa1');
console.log(sa1.list, sa1.name); // 打印出 [1, 2, 3] undefined
/*
new A() -> {
name: undefined,
list: [1,2,3],
__proto__: {
getName: fn,
constructor....
}
}
new SubA('sa1') -> {
subName: 'sub sa1',
__proto__: {
name: undefined,
list: [1,2,3],
__proto__: {
getName: fn,
constructor....
}
}
}
// 类式继承的问题
1.这种方法不支持父构造函数带参数
2.父构造函数里的方法和属性都会变成共有属性
*/
var sa1 = new SubA('sa1');
var sa2 = new SubA('sa2');
A.prototype.getName = function() {
console.log('fixed getName')
}
A.prototype.newFn = function() {
console.log('new Fn')
}
sa1.getName(); // 打印 fixed getName
sa2.newFn(); // 打印 new Fn
// 构造函数继承
function A(name) {
this.name = name;
this.list = [1, 2, 3]
}
A.prototype.getName = () => {
console.log(this.name);
}
function SubA(name) {
A.call(this, name)
this.subName = 'sub' + this.name;
}
var sa1 = new SubA('xiaoA');
console.log(sa1.name, sa1.subName); // 打印出 xiaoA subxiaoA
sa1.getName(); // 报错
/*
new SubA('xiaoA'); -> {
__proto__: {
constructor....
},
name: 'xiaoA',
list: [1, 2, 3],
subName: 'sub xiaoA'
}
// 构造函数继承问题
1.不能继承父构造函数的原型方法
*/
// 组合式继承
function A(name) {
this.name = name;
this.list = [1, 2, 3]
}
A.prototype.getName = () => {
console.log(this.name);
}
function SubA(name) {
A.call(this, name)
this.subName = 'sub' + this.name;
}
SubA.prototype = new A()
var sa1 = new SubA('xiaoA');
console.log(sa1.name, sa1.subName); // 打印出 xiaoA subxiaoA
sa1.getName(); // xiaoA
/*
new A() -> {
name: undefined,
list: [1, 2, 3],
__proto__: {
getName: fn
}
}
new SubA('xiaoA'); -> {
name: 'xiaoA',
list: [1, 2, 3],
subName: 'sub xiaoA',
__proto__: {
name: undefined,
list: [1, 2, 3],
__proto__: {
getName: fn
}
},
}
// 组合式继承问题
1.__proto__里的属性没有用
2.执行了两次父构造函数
问题点在于: SubA.prototype = new A()
*/
// 4.寄生组合式继承
function A(name) {
this.name = name;
this.list = [1, 2, 3]
}
A.prototype.getName = () => {
console.log(this.name);
}
function SubA(name) {
A.call(this, name)
this.subName = 'sub' + this.name;
}
// SubA.prototype = new A() // 优化这一句代码
function inheritPrototype(subClass, superClass) {
// 子构造函数 父构造函数
function F() {
};
F.prototype = superClass.prototype;
subClass.prototype = new F()
subClass.prototype.constructor = subClass; // 可有可无
}
inheritPrototype(SubA, A)
var sa1 = new SubA('xiaoA');
console.log(sa1.name, sa1.subName); // 打印出 xiaoA subxiaoA
sa1.getName(); // xiaoA
</script>
</head>
<body>
</body>
</html>
多态: 表示不同对象调用相同方法会产生不同结果
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script>
// 多态: 表示不同对象调用相同方法会产生不同结果
function Base() {
}
Base.prototype.initial = function() {
this.init()
}
function SubA() {
this.init = function () {
console.log('subA init')
}
}
function SubB() {
this.init = function () {
console.log('subB init')
}
}
SubA.prototype = new Base();
SubB.prototype = new Base();
var subA = new SubA()
var subB = new SubB()
subA.initial();
subB.initial();
</script>
</head>
<body>
</body>
</html>