【javaScript 原型精讲】

前言:本文用通俗语言 + 实战代码,拆解原型、constructor、对象原型、原型继承与原型链,带你吃透 JS 面向对象核心,轻松解决内存优化难题。

【javaScript 原型精讲】

一:构造函数

封装是面向对象思想中比较重要的一部分,js 面向对象可以通过构造函数实现的封装。

同样的将变量和函数组合到了一起并能通过 this 实现数据的共享,所不同的是借助构造函数创建出来的实例对象之间是彼此不影响的。

javascript 复制代码
function Star(uname, age) {
    this.uname = uname
    this.age = age
    this.sing = function () {
        console.log('我会唱歌')
    }
}

// 实例对象,获得了构造函数中封装的所有逻辑
const A = new Star('张三', 18)
const B = new Star('李四', 19)

构造函数方法很好用,但是存在浪费内存的问题

我们希望所有的对象使用同一个函数,这样就比较节省内存,那么我们就用到原型

二:原型

构造函数通过原型分配的函数是所有对象所共享的

JavaScript 规定,每一个构造函数都有一个 prototype 属性,指向另一个对象,所以我们也称为原型对象。

这个对象可以挂载函数,对象实例化不会多次创建原型上函数,节约内存。

我们可以把那些不变的方法,直接定义在 prototype 对象上,这样所有对象的实例就可以共享这些方法。

构造函数和原型对象中的 this 都指向实例化的对象。

javascript 复制代码
 function test() {
            console.log("Hello, World!");
        }
        console.dir(test.prototype)

控制台输出:

这时我们可以通过原型让所有的对象使用同一个函数

javascript 复制代码
function Star(uname, age) {
    this.uname = uname
    this.age = age
    // this.sing = function () {
    //     console.log('我会唱歌')
    // }
}
Star.prototype.sing = function () {
    console.log('我会唱歌')
}

const A = new Star('张三', 18)
const B = new Star('李四', 19)
console.log(A.sing === B.sing) // true

最终打印结果为 true,核心原因是:我们将sing 方法挂载在了 Star 构造函数的 prototype 原型对象上,而非构造函数内部。

  1. 当创建 A、B 两个实例对象时,不会再为每个实例单独生成一份 sing方法,有效避免了构造函数内部定义方法造成的内存冗余问题;
  2. 所有 Star 的实例对象,都会通过自身的 __proto__ 属性,统一指向 Star.prototype 原型对象,A.sing 和 B.sing 访问的是内存中同一个函数地址;
  3. 因此两个实例调用的是完全相同的方法,全等对比结果为 true,这也是原型实现方法共享、节省内存的核心体现。

三:constructor

每个原型对象里面都有个 constructor 属性(constructor 构造函数)

作用:该属性指向该原型对象的构造函数

javascript 复制代码
 function test() {
            console.log("Hello, World!");
        }
        const A = new test()
        console.log(Star.prototype.constructor );

控制台输出:

需要注意的是,如果有多个对象的方法,我们可以给原型对象采取对象形式赋值。

但是这样就会覆盖构造函数原型对象原来的内容,这样修改后的原型对象 constructor 就不再指向当前构造函数了。

此时,我们可以在修改后的原型对象中,添加一个 constructor 指向原来的构造函数。

javascript 复制代码
Star.prototype = {
            constructor: A,
            sing:function() {
                console.log("La la la");
            },
            dance:function() {
                console.log("Dancing...");
            }
        }

四:对象原型

对象都会有一个属性 __proto__,指向构造函数的 prototype 原型对象,之所以我们对对象可以使用构造函数 prototype 原型对象的属性和方法,就是因为对象有 __proto__ 原型的存在。

javascript 复制代码
 function test() {
            console.log("Hello, World!");
        }
        const A = new test()
        
       console.log(A.__proto__ === test.prototype) // true

__proto__ 是 JS 非标准属性

\[prototype\]\] 和 `__proto__` 意义相同 用来表明当前实例对象指向哪个原型对象 prototype `__proto__` 对象原型里面也有一个 constructor 属性,指向创建该实例对象的构造函数 ```javascript function test() { console.log("Hello, World!"); } const A = new test() console.log(A.__proto__.constructor === test) // true ``` ### 五:原型继承 在 JavaScript 里,没有真正意义上的类继承,我们的继承都是依靠原型实现的,这就是 JavaScript 最核心的原型继承。 简单说:让一个构造函数的原型,指向另一个构造函数的实例,就能实现方法和属性的继承。 核心思想 子构造函数的原型 = 父构造函数的实例 这样一来,子类实例就能通过 `__proto__` 找到父类原型上的所有方法,实现复用 + 继承。 ```javascript // 1. 父构造函数:人 function Person() { this.type = '人类'; } // 父方法放在原型上 Person.prototype.eat = function () { console.log('我会吃饭'); }; // 2. 子构造函数:学生 function Student(name) { this.name = name; } // 关键:实现原型继承 Student.prototype = new Person(); // 手动修正 constructor 指向(必须写!) Student.prototype.constructor = Student; // 给学生添加自己的独有方法 Student.prototype.study = function () { console.log('我会学习'); }; // 测试 const s1 = new Student('小明'); console.log(s1.type); // 人类(继承自 Person) s1.eat(); // 我会吃饭(继承自 Person 原型) s1.study(); // 我会学习(自己的方法) ``` ### 六:原型链 原型链是 JavaScript 查找属性 / 方法的规则,也是 JS 面向对象最底层的运行机制, 当你访问一个对象的属性 / 方法时: 先在对象自身找 找不到 → 去 `__proto__` 找(指向构造函数原型 prototype) 还找不到 → 继续去原型的 `__proto__` 找 直到 null 为止 这条一层层向上查找的链路,就是原型链。 标准原型链结构 ```javascript 实例对象 __proto__ → 构造函数原型 __proto__ → Object原型 __proto__ → null ``` 图解: ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/bc1ed45d8f7d4cc6bfe840dc0606449b.png) 最后: 如果我的内容对你有帮助,请点赞,评论,收藏,创作不易。大家的支持就是我坚持下去的动力! ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/926c19fd0e394cb49df2c45d3bb94ab6.jpeg)

相关推荐
卷帘依旧1 小时前
手写throttle
javascript
伯远医学2 小时前
Nat. Methods | 邻近标记技术:活细胞中捕捉分子互作的新利器
java·开发语言·前端·javascript·人工智能·算法·eclipse
不瘦80斤不改名2 小时前
JavaScript 基础语法完全指南
开发语言·javascript·ecmascript
peepeeman2 小时前
vue组件透传
前端·javascript·vue.js
a1117763 小时前
细胞结构实验室(react 开源)
前端·javascript·开源·html
Dxy12393102164 小时前
JS如何获取元素高度
开发语言·javascript·ecmascript
豹哥学前端4 小时前
5分钟搞懂事件委托
前端·javascript·面试
绝世唐门三哥4 小时前
ES6 --- import/export 全解析
开发语言·前端·javascript
yqcoder4 小时前
JavaScript 异步基石:Promise 完全指南
开发语言·前端·javascript