原型 prototype
原型上存放函数
原型解释
- 原型的单词是
prototype
, 原型的这个名字是行业内共同认可的名字。 - 原型本质是一个对象,理解为
JavaScript
自动帮我们添加的 - 原型是
JavaScript
自动帮我们在定义构造函数
的时候添加的 - 所有构造函数的实例,共享一个原型
- 原型上一般是挂载函数
原型 proto
-
实例的
proto
属性 等于 构造函数的prototype
p1.__proto__ === Person.prototype // true
-
不过由于不同浏览器的兼容性问题,我们
要
使用的时候,都只会使用 构造函数的prototype
-
实例的 proto 只是为了方便我们开发的时候查看数据,是不会手动修改和操作它的。
原型对象 - 三角关系图
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>原型对象 - 三角关系</title>
</head>
<body></body>
<script>
// 自定义构造函数: 给对象做分类, 便于管理
// 对象: 数据(属性) 和 数据操作(方法)
function Student(name, age) {
this.name = name;
this.age = age;
}
// JS世界中: 构造函数, js是男的
// JS不允许单身出现: 一定会分配一个女的
// 将这种 函数(一般指构造函数) 一定有一个对象: 原型对象
// 找到函数的原型对象: 函数名.prototype
console.log(Student.prototype);
// 默认的原型对象中: 只有一个属性 constructor,指向构造函数(一夫一妻制)
console.log(Student.prototype.constructor); // f Student
// 再次证明: 老公的老婆的老公是 老公
console.log(Student.prototype.constructor === Student); // true
// 原型对象的价值: 用于管理 方法
// Student.prototype.属性名 = '属性值' // 一般不会添加普通数据
// console.log(Student.prototype)
// 实际只给原型对象添加方法( 挂载原型方法 : 将函数放到原型对象里面)
Student.prototype.study = function () {
console.log(this.name + "正在学习");
};
// 产生孩子: new
const s1 = new Student("张三", 29);
console.log(s1);
// 对象内部:只有属性(构造函数给的), 但是可以找到构造函数对应的原型对象: 里面的内容, 对象都可以无条件访问
console.log(s1.study);
s1.study(); // study内部的this指向s1
// 孩子找妈妈: 孩子对象.__proto__(谷歌支持: 不是所有浏览器都支持: 有兼容性)
console.log(s1.__proto__ === Student.prototype); // true
// 总结
// 自从有了原型对象
// 1. 构造函数的属性:如果是方法, 放到原型对象中: 原型对象只有一个: 方法内存只占一份
// 2. 原型对象是一个对象: 属性方法是内部的内容, 不受全局污染: 安全
</script>
</html>
原型的关系
所有的构造函数都是Function的实例
Array 和 Person 和 Date 等都是 Function的实例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body></body>
<script>
// 原型关系: 三角关系(爸爸 妈妈 孩子)
// 所有函数都有Function创建: new Function()
function Student(name, age) {
this.name = name;
this.age = age;
}
// 问题1: Student由 Function创建的
// 分析
// Student是Function的孩子
// Function是构造函数
// 函数一定有原型对象
// 证明
// Function有原型对象
console.log(Function.prototype); // f 函数: 函数跟对象一样, 都是复合数据类型
// Function的原型对象能找到Function?
console.log(Function.prototype.constructor === Function); // true
// 自定义构造函数Student此时是孩子(对象) : 有妈妈
console.log(Student.__proto__ === Function.prototype); // true
// 构造函数: 也是孩子, 也存在原型三角关系
</script>
</html>
原型链
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body></body>
<script>
// 已有结论
// 1. 对象: 可以无条件访问原型对象里面的内容
// 2. 原型对象: 由Object产生, 指向Object.prototype: 顶级原型对象
// 一个自定义构造函数的实例(new得到的对象) 可以访问构造函数自己的原型方法
// 自己的原型对象: 指向Object的原型对象
// 这种链条关系: 称之为原型链
// 原型链的作用: 就是JS如何实现面向对象中最重要的一个特性: 继承
// 只要是原型链上的内容: 对象就可以无条件访问
function Student(name, age) {
this.name = name;
this.age = age;
}
// 给Studnent挂载原型方法
Student.prototype.study = function () {
console.log(this.name + "正在学习");
};
const s = new Student("安琪拉", 18);
// console.log(s)
// 1. 访问自己: 自己有不求人
console.log(s.name, s.age);
// 2. 访问原型对象: 自己妈妈
s.study();
console.log(s.constructor); // 等价于: s.__proto__.constructor
// 3. 访问顶级原型对象: 自己外婆
console.log(s.toString());
// 继承的优点: 代码可以复用(别人有的, 直接使用即可)
// 需求: 项目中有一个say的功能: 所有数据都可以调用
// console.log(new Number(1))
// Object.prototype是顶级原型对象: 所有对象最终都继承Object.prototype
Object.prototype.say = function () {
console.log(this);
};
let num = 1;
let str = "abc";
let bl = true;
let s2 = new Student("仲未", 200);
num.say();
str.say();
bl.say();
s2.say();
</script>
</html>