对js原型和原型链的理解

本文会解释产生原型和原型链的原因、作用、概念和使用方式。

概念

原型对象: 构造函数的prototype属性指向一个对象,该对象是由这个构造函数实例化出来的对象的原型对象。具有公共属性和方法的对象。

对象的原型:每个对象都有一个原型对象,可通过Object.getPrototypeOf()获取。

构造函数的prototype属性:每个函数都有一个prototype属性,指向一个对象,该对象的属性和方法会被构造函数创建的实例对象继承。

实例的__proto__属性:实例对象的__proto__属性指向其构造函数的prototype属性。

原型链:原型对象也有一个原型,以此类推形成原型链。基本思想是让一个引用对象继承另一个引用对象的属性和方法。

由来

产生原型和原型链是为了解决什么问题?

每个原始数据类型和对象都有对应的方法和属性,当我们反复实例一个对象时,每个实例对象都会对应各自的方法和属性,都是单独开辟空间进行存储的。而他们的方法和属性相同却不互通的。存储这些相同的方法和属性是很占用空间的。因此需要原型将这些相同的、共有的属性和方法单独存放起来。堪比垃圾回收机制中,可能有多个栈内存空间同时指向同一个堆内存空间,但不会出现一个栈内存空间同时指向多个堆内存空间。

垃圾回收机制(GC)

原始数据类型和对象的引用地址是在栈内存空间开辟一个空间来存储的。

对象引用地址的数据是在堆内存空间开辟一个空间进行存储。

二者由栈内存空间指向堆内存空间,两者一一对应。不会出现不同的栈内存空间指向同一个堆内存空间。若栈内存没有指向堆内存空间(没被标记),则堆内存空间的数据会判定为不用的数据,从而被清除。

作用 :是自动清理那些不再使用的内存,防止出现内存泄漏。核心是标记清除和引用计数。

标记清除:从根对象(全局对象)出发标记对象,清除未标记的内存。可解决循环引用,但执行时会短暂卡顿

引用计数:记录每个对象的引用次数,归零时回收。但不能处理循环引用,可能导致内存泄漏

V8引擎优化:分代回收和增量回收

注意:避免意外全局变量、及时清除定时器和监听器、谨慎使用闭包引用对象、清除无用的DOM引用

作用

为函数提供一个声明属性和方法的公共区域,使得这个函数的实例对象都能访问,从而减少内存消耗。 1.数据共享 当访问一个实例对象的属性和方法时,会先查找该实例对象本身是否具有该属性和方法,没有则沿着原型链向上查找,直到原型链顶端null,实现代码的复用。而且不同对象共享一个方法时,由于this指向不同,方法的行为也会不同。

2.实现继承

通过设置对象的原型,让一个对象可继承另一个对象的属性和方法。使得可以创建相同行为的对象,而无需定义相同的属性和方法。

3.节约内存

使用情况

new关键字的步骤

1.创建一个新对象

2.将构造函数的this指向这个新对象

3.将新对象的__proto__属性指向构造函数的prototype属性,即构造函数的原型对象

4.执行构造函数

5.返回this

js 复制代码
function Person(name) {
    this.name = name;
}
Person.prototype.eat = function () {
    console.log(this.name+"吃东西");
};
Person.prototype.sleep = function () {
    console.log(this.name+"睡觉");
}
var p1 = new Person("小明");
p1.eat();//小明吃东西
p1.sleep();//小明睡觉
var p2 = new Person("小华");
p2.eat();//小华吃东西
p2.sleep();//小华睡觉
console.dir(p1);
console.dir(p2);
console.dir(Person);
console.dir(p1);
console.log(typeof p1.__proto__);//object
console.log(typeof Person.prototype);//object
console.log(p1.__proto__ === Person.prototype);//true

eat()和sleep()被添加到Person()构造函数的原型prototype上,实例对象在自己的__proto__属性中找到并调用该公共方法和属性。

js 复制代码
 /*  
          1. 新对象都有一个属性 叫__proto__
          2. 构造函数都有一个属性 叫prototype
          3. 构造函数的原型对象上有一个属性 叫constructor 指向构造函数
          4. 所有的原型对象都是Object函数对象构造出来的(除Object本身的原型对象之外)
       */
        var person1 = new Person();
        console.log(person1.__proto__ === Person.prototype); // true
        console.log(Person.prototype.constructor === Person); // true
        console.log(Person.prototype.__proto__ === Object.prototype); // true
        console.log(Object.prototype.__proto__); // null

        console.log(person1.__proto__.__proto__ === Object.prototype); // true
        console.log(person1.__proto__.__proto__.__proto__ === null); // true

        // console.log(person1.toString());
        console.log(Person.prototype.toString);
        console.log(Person.prototype);
        console.log(Object.prototype);

        // 5. 直接量对象 都是Object函数对象构造出来的
        var obj = {};
        console.log(obj); // obj.__proto__  === Object.prototype
		
        function Person() {
            this.name = 'qwer';
        }
        // Person是一个函数 Person是一个对象
        Person.ss = '新增的ss属性';
        console.dir(Person);
        console.dir(Person.ss);

        var per1 = new Person();
        console.log(per1);

        // 1. 所有的函数都是Function函数对象构造的
        console.log(Person.__proto__ === Function.prototype); // true
        console.log(Function.prototype.__proto__ === Object.prototype); // true
        console.log(Function.prototype.__proto__.__proto__ === null); // true
        console.log(Person.__proto__.__proto__.__proto__ === null); // true

        // 2. Function顶层没有人构造 自己构造了自己
        console.log(Function.__proto__ === Function.prototype); // true
        // console.log(Function.prototype.__proto__ === Object.prototype);

        console.log(Function.__proto__.__proto__ === Object.prototype); // true

        console.log(Object.__proto__ === Function.prototype); // true
        // console.log(Function.prototype.__proto__ === Object.prototype);
        console.log(Object.__proto__.__proto__ === Object.prototype); // true
        console.log(Object.__proto__.__proto__.__proto__); // null
        console.log(Function.__proto__.__proto__.__proto__); // null
相关推荐
Mintopia34 分钟前
深度伪造检测技术在 WebAIGC 场景中的应用现状
前端·javascript·aigc
BUG_Jia35 分钟前
如何用 HTML 生成 PC 端软件
前端·javascript·html·桌面应用·1024程序员节
皓月Code37 分钟前
第二章、全局配置项目主题色(主题切换+跟随系统)
javascript·css·react.js·1024程序员节
MoonBit月兔1 小时前
MoonBit Pearls Vol.12:初探 MoonBit 中的 JavaScript 交互
开发语言·javascript·数据库·交互·moonbit
非凡ghost1 小时前
Tenorshare 4DDiG(数据恢复软件) 最新版
前端·javascript·后端
www_stdio1 小时前
深入理解JavaScript变量声明:var、let与const的全面解析
javascript
San301 小时前
AI 歌词生成器:使用 OpenAI 打造你的专属作词助手
javascript·人工智能·node.js
用户84298142418101 小时前
JavaScript数据类型
javascript
非凡ghost1 小时前
WinMute(自动锁屏静音软件) 中文绿色版
前端·javascript·后端
over6972 小时前
JavaScript变量声明:var、let、const的完整指南
javascript