JavaScript高级——面向对象、原型与原型链
程序员文章站
2022-05-08 15:00:12
...
面向对象
- 什么是面向对象编程
- 面向对象不是一门技术,而是一种
解决问题的思维方式
- 面向对象的本质是对面向过程的一种封装
- 面向对象不是一门技术,而是一种
- 理解什么是对象
- 对象的本质是程序代码与现实世界沟通的一座桥梁。它有两种函数
- 对象:是一种数据类型(存储数据的容器),以键值对的形式存储数据
- 对象:对现实世界实物的一种抽象。
- 对象的本质是程序代码与现实世界沟通的一座桥梁。它有两种函数
对象创建模式
-
Object构造函数模式(内置构造函数)
先创建空Object对象,再动态添加属性、方法
适用场景:起始时不确定对象的内部数据
问题:语句太多
` /*
一个人:name:"Tom",age=12
*/
let p = new Object();
p.name = 'Tom';
p.age = 12;
p.setName = function () {
this.name = name;
}
-
对象字面量
使用{}创建对象,同时指定属性和方法
适用场景:起始时对象的内部数据是确定的
问题:如果创建多个对象有重复代码
let p = {
name: 'Tom',
age: 12,
setName: function (name) {
this.name = name;
}
}
let p2 = { //如果创建多个对象代码很重复
name: 'Bob',
age: 13,
setName: function (name) {
this.name = name;
}
}
-
工厂模式
通过工厂函数动态创建对象并返回
适用场景: 需要创建多个对象
问题: 对象没有一个具体的类型(是人还是动物), 都是Object类型
function createPerson(name, age) { //返回一个对象的函数===>工厂函数
let obj = {
name: name,
age: age,
setName: function (name) {
this.name = name;
}
}
return obj;
}
// 创建2个人
let p1 = createPerson('Tom', 12);
let p2 = createPerson('Bob', 13);
// p1/p2是Object类型
function createStudent(name, price) {
let obj = {
name: name,
price: price
}
return obj;
}
let s = createStudent('张三', 12000)
// s也是Object
-
自定义构造函数模式
自定义构造函数, 通过new创建对象
适用场景: 需要创建多个类型确定的对象
问题: 每个对象都有相同的数据, 浪费内存
function Person(name, age) {
this.name = name;
this.age = age;
this.setName = function (name) {
this.name = name;
}
}
let p1 = new Person('Tom', 22);
p1.setName('Jack');
console.log(p1.name, p1.age);
console.log(p1 instanceof Person);
function Student(name, price) {
this.name = name;
this.price = price;
}
let s = new Student('Bob', 13000);
console.log(s instanceof Student);
let p2 = new Person('JACK', 23);
console.log(p1, p2);
-
构造函数+原型的组合模式
自定义构造函数, 属性在函数中初始化, 方法添加到原型上
适用场景: 需要创建多个类型确定的对象
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.setName = function () {
this.name = name;
}
let p1 = new Person();
let p2 = new Person();
console.log(p1, p2);
new关键字工作原理
a.内置构造函数:[]:new Array() {}:new Object()
b.自定义构造函数: new Person()
(1)创建一个空对象:{}
(2)this指向这个对象
(3)执行对象的赋值代码
(4)自动返回这个对象 return this;
原型与原型链
原型对象(构造函数的工作原理)
- 原型:
任何构造函数在被创建的时候,系统都会自动帮我们创建一个与之对应的对象,称之为原型对象
- 同时解决内存浪费与全局变量污染的问题
- 谁可以访问原型对象中的成员(属性和方法)
- 构造函数自身:构造函数名.prototype
- 构造函数实例化的每一个对象:点语法直接访问
- 每个函数都有一个
prototype属性
, 它默认指向一个Object空对象
(即称为: 原型对象)- 原型对象中有一个属性constructor, 它指向函数对象
- 给原型对象添加属性(一般都是方法)
- 作用: 函数的所有实例对象自动拥有原型中的属性(方法)
<script>
// 每个函数都有一个prototype属性, 它默认指向一个Object空对象(即称为: 原型对象)
console.log(Date.prototype, typeof Date.prototype)
function Fun () {
}
console.log(Fun.prototype); // 默认指向一个Object空对象(没有我们的属性)
// 原型对象中有一个属性constructor, 它指向函数对象
console.log(Date.prototype.constructor===Date);
console.log(Fun.prototype.constructor===Fun);
//给原型对象添加属性(一般是方法) ===>实例对象可以访问
Fun.prototype.test = function () {
console.log('test()');
}
let fun = new Fun();
fun.test();
</script>
prototype
、__proto__
、constructor
- 每个函数function都有一个
prototype
,即显式原型(属性)
- 每个实例对象都有一个
__proto__
,可称为隐式原型(属性)
- 对象的隐式原型的值为其对应构造函数的显式原型的值
- 原型对象中有一个属性
constructor
, 它指向函数对象 - 总结:
- 函数的prototype属性: 在定义函数时自动添加的, 默认值是一个空Object对象
- 对象的__proto__属性: 创建对象时自动添加的, 默认值为构造函数的prototype属性值
- 程序员能直接操作显式原型, 但不能直接操作隐式原型(ES6之前)
原型链
-
原型链 :每一个对象都有__proto__属性指向自己的原型,而原型又是一个对象,也有自己的__proto__属性指向原型的原型,以此类推形成一种链式结构,称之为原型链(别称隐式原型链)。
-
对象访问原型链中成员的规则:
就近原则
对象访问成员的时候,优先访问自己的。自己没有就访问原型的,如果原型也没有,就访问原型的原型,以此类推直到原型链终点Null . 如果还找不到,如果是属性则获取undefined. 如果是方法则报错, 提示 ‘xxx’ is not a function.
面向对象的思维方式的三大特征
- 封装:将代码放入对象的方法中
- 继承:一个对象拥有另一个对象的所有成员(属性+方法)
(1)自己实现继承的3种方式
2.1 混入式继承:遍历父对象成员 添加给子对象
场景:用于单对象继承
2.2 替换原型:将父对象 作为子对象的构造函数的原型
场景:用于多对象继承
2.3 混合式:混入式 + 替换原型
场景:遍历父对象,添加给子对象的原型
(2)js是通过原型链来实现继承的 - 多态:一个对象在不同情况下的多种状态
javascript语言很少用到多态
instanceof运算符 : 检测一个构造函数prototype 在不在对象的原型链中。
语法: 实例对象 instanceof 构造函数
规则: 检测 右边构造函数的prototype 在不在左边对象的原型链中
true: 在 false:不在
let arr = [10,20,30];
/*
arr实例对象原型链 arr.__proto__ -> Array.prototype -> Object.prototype - > null
*/
console.log( arr instanceof Array);//true
console.log( arr instanceof Object);//true
/*
根据instanceof运算符规则: 左边object是一个对象, 右边object是一个函数
object对象原型链 object.__proto__ -> Function.prototype ->Object.prototype ->null
*/
console.log( Object.__proto__.constructor );//Function
console.log( Object.__proto__ === Function.prototype );//true
console.log( Object instanceof Object);//true
console.log( Object instanceof Function);//true
/*
根据instanceof运算符规则: 左边Functiont是一个对象, 右边Function是一个函数
function对象原型链 Function.__proto__ -> Fuction.prototype -> Object.prototype -> null
*/
console.log( Function.__proto__.constructor );//Function
console.log( Function.__proto__ === Function.prototype );//true
console.log( Function instanceof Function);//true
console.log( Function instanceof Object);//true