JavaScript 对象三角恋关系&原型链

分类:

JavaScript

日期:

2022-5-19

标签:

JavaScript原型链

原型和继承是 Javascript 中非常重要的两大概念,Javascript 以原型链的形式,保证函数或对象中的方法、属性可以让向下传递,按照面向对象的说法,这就是继承。而 Javascript 通过原型链才得以实现函数或对象的继承。

构造函数、实例、原型对象之间的三角恋关系#

jslTr4.md.jpg

  1. 每个"构造函数"中都有一个默认的属性, 叫做 prototypeprototype 属性保存着一个对象, 这个对象我们称之为原型对象
  2. 每个"原型对象"中都有一个默认的属性, 叫做 constructorconstructor 指向当前原型对象对应的那个构造函数
  3. 通过构造函数创建出来的对象我们称之为"实例对象",每个"实例对象"中都有一个默认的属性, 叫做 __proto____proto__指向创建它的那个构造函数的"原型对象"
function Person(myName, myAge) {
this.name = myName;
this.age = myAge;
}
let obj1 = new Person('lnj', 34);
console.log(Person.prototype);
console.log(Person.prototype.constructor);
console.log(obj1.__proto__);

输出结果: js1deJ.jpg

Function 函数#

jslTr4.md.jpg

  1. JavaScript 中函数是引用类型(对象类型), 既然是对象,所以也是通过构造函数创建出来的,"所有函数"都是通过 Function 构造函数创建出来的对象
  2. JavaScript 中只要是"函数"就有 prototype 属性,"Function 函数" 的 prototype 属性指向"Function 原型对象"
  3. JavaScript 中只要"原型对象"就有 constructor 属性,"Function 原型对象"的 constructor 指向它对应的构造函数
  4. Person 构造函数是 Function 构造函数的实例对象, 所以也有 __proto__ 属性,Person 构造函数的 __proto__ 属性指向"Function 原型对象"
function Person(myName, myAge) {
this.name = myName;
this.age = myAge;
}
let obj1 = new Person('lnj', 34);
// console.log(Function);
// console.log(Function.prototype);
// console.log(Function.prototype.constructor);
// console.log(Function === Function.prototype.constructor); // true
// console.log(Person.__proto__);
console.log(Person.__proto__ === Function.prototype); // true

Object 函数#

jslbZ9.jpg

  1. JavaScript 函数是引用类型(对象类型), 所以 Function 函数也是对象
  2. "Function 构造函数"也是一个对象, 所以也有 __proto__ 属性,"Function 构造函数 "__proto__ 属性指向"Function 原型对象"
  3. JavaScript 中还有一个系统提供的构造函数叫做 Object,只要是函数都是"Function 构造函数"的实例对象
  4. 只要是对象就有 __proto__ 属性, 所以"Object 构造函数"也有 __proto__ 属性,"Object 构造函数"的 __proto__ 属性指向创建它那个构造函数的"原型对象"
  5. 只要是构造函数都有一个默认的属性, 叫做 prototype,prototype 属性保存着一个对象, 这个对象我们称之为"原型对象"
  6. 只要是原型对象都有一个默认的属性, 叫做 constructor,constructor 指向当前原型对象对应的那个"构造函数"
function Person(myName, myAge) {
this.name = myName;
this.age = myAge;
}
let obj1 = new Person('lnj', 34);
// console.log(Function.__proto__);
// console.log(Function.__proto__ === Function.prototype); // true
// console.log(Object);
// console.log(Object.__proto__);
// console.log(Object.__proto__ === Function.prototype); // true
// console.log(Object.prototype);
// console.log(Object.prototype.constructor);
// console.log(Object.prototype.constructor === Object); // true
// console.log(Object.prototype.__proto__); // null

函数对象关系#

jsl7qJ.jpg

  1. 所有的构造函数都有一个 prototype 属性, 所有 prototype 属性都指向自己的原型对象
  2. 所有的原型对象都有一个 constructor 属性, 所有 constructor 属性都指向自己的构造函数
  3. 所有函数都是 Function 构造函数的实例对象
  4. 所有函数都是对象, 包括 Function 构造函数
  5. 所有对象都有__proto__属性
  6. 普通对象的__proto__属性指向创建它的那个构造函数对应的 "原型对象"
  7. 所有对象的__proto__属性最终都会指向 "Object 原型对象"
  8. "Object 原型对象"的__proto__属性指向 NULL
function Person(myName, myAge) {
this.name = myName;
this.age = myAge;
}
let obj1 = new Person('lnj', 34);
console.log('1', Function.prototype.__proto__);
console.log('2', Person.prototype.__proto__);
console.log('3', Function.prototype.__proto__ === Person.prototype.__proto__);
console.log('4', Function.prototype.__proto__ === Object.prototype);
console.log('5', Person.prototype.__proto__ === Object.prototype);

输出结果: jsNrHU.jpg

原型链#

jsloMF.jpg

  1. 对象中__proto__组成的链条我们称之为原型链
  2. 对象在查找属性和方法的时候, 会先在当前对象查找,如果当前对象中找不到想要的, 会依次去上一级原型对象中查找,如果找到 Object 原型对象都没有找到, 就会报错
function Person(myName, myAge) {
this.name = myName;
this.age = myAge;
// this.currentType = "构造函数中的type";
// this.say = function () {
// console.log("构造函数中的say");
// }
}
Person.prototype = {
// 注意点: 为了不破坏原有的关系, 在给prototype赋值的时候,
// 需要在自定义的对象中手动的添加constructor属性, 手动的指定需要指向谁
constructor: Person,
// currentType: "人",
// say: function () {
// console.log("hello world");
// }
};
let obj1 = new Person('lnj', 34);
// obj1.say();
console.log(obj1.currentType);
// console.log(Person.prototype.constructor);

注意点: 为了不破坏原有的关系, 在给 prototype 赋值的时候, 需要在自定义的对象中手动的添加 constructor 属性, 手动的指定需要指向谁

属性注意点#

在给一个对象不存在的属性设置值的时候,不会去原型对象中查找,如果当前对象没有就会给当前对象新增一个不存在的属性

function Person(myName, myAge) {
this.name = myName;
this.age = myAge;
}
Person.prototype = {
constructor: Person,
currentType: '人',
say: function () {
console.log('hello world');
},
};
let obj = new Person('lnj', 34);
// console.log(obj.currentType); // "人"
// console.log(obj.__proto__.currentType); // "人"
// 注意点: 在给一个对象不存在的属性设置值的时候, 不会去原型对象中查找,
// 如果当前对象没有就会给当前对象新增一个不存在的属性
obj.currentType = '新设置的值';
console.log(obj.currentType); // 新设置的值
console.log(obj.__proto__.currentType); // "人"

总结#

  • 访问对象的一个属性,先在自身查找,如果没有,会访问对象的__proto__,沿着原型链查找,一直找到 Object.prototype.__proto__。

  • 原型链上一切皆对象,即都有__proto__属性,该属性的指向一个原型对象,

  • 构造函数都有 prototype 属性,指向自身构造函数的原型对象。

  • __proto__链条(原型链)的尽头是 Object.prototype.__proto__,为 null。

footer logo

© 2022 Designed with chakra ui. Powered by contentlayerjs and nextjs etc. All rights reserved

TwitterYouTubeGithub