boxmoe_header_banner_img

Hello! 欢迎来到悠悠畅享网!

文章导读

js怎么获取原型上的方法


avatar
作者 2025年8月26日 14

获取对象原型上的方法最直接的方式是使用 Object.getprototypeof() 取得原型对象,再通过 object.getownpropertynames() 配合 Filter 筛选出函数类型的自有属性;2. 区分原型方法与实例方法的关键在于 hasownproperty() 检查,实例方法返回 true,原型方法则需沿原型链查找;3. 使用 for…in 时必须结合 hasownproperty() 防止遍历到继承属性,且无法获取不可枚举方法,而 object.getownpropertynames() 可覆盖所有自有属性;4. 避免修改内置对象原型,防止全局污染;5. 原型方法被所有实例共享,节省内存,而实例方法每个实例独有。

js怎么获取原型上的方法

JavaScript中要获取一个对象原型上的方法,最直接的方式是先拿到这个对象的原型,然后遍历原型上的属性。你可以通过

Object.getPrototypeOf()

方法或者非标准的

__proto__

属性来获取原型对象,接着再用

Object.getOwnPropertyNames()

for...in

循环(配合

hasOwnProperty

检查)来列出这些方法。

js怎么获取原型上的方法

解决方案

要获取原型上的方法,核心步骤是:首先获取到目标对象的原型对象,然后在这个原型对象上查找它“自己”定义的方法,而不是继承来的方法。

举个例子,我们有一个构造函数

Person

js怎么获取原型上的方法

function Person(name) {     this.name = name; }  Person.prototype.sayHello = function() {     console.log("Hello, my name is " + this.name); };  Person.prototype.walk = function() {     console.log(this.name + " is walking."); };  // 假设我们还给Object.prototype添加了一个方法(不推荐,但用于演示) // Object.prototype.globalMethod = function() { console.log("Global!"); };  const person1 = new Person("Alice");  // 1. 获取原型对象 const personPrototype = Object.getPrototypeOf(person1); // 或者使用 person1.__proto__; 但推荐使用 Object.getPrototypeOf(),因为它更标准。  console.log("--- 获取原型上的自有方法 ---"); // 2. 遍历原型对象上的自有属性(方法也是属性) // Object.getOwnPropertyNames() 会返回所有自有属性的名称,包括不可枚举的 const prototypeMethods = Object.getOwnPropertyNames(personPrototype).filter(name => {     // 确保是函数类型,并且是原型对象自身的属性,而不是继承自更上层原型链的     return typeof personPrototype[name] === 'function' && personPrototype.hasOwnProperty(name); });  console.log("原型上的方法名称:", prototypeMethods); // 应该输出 ['sayHello', 'walk']  // 如果你想获取方法本身,可以这样: prototypeMethods.forEach(methodName => {     console.log(`方法名: ${methodName}, 方法体:`, personPrototype[methodName]); });  // 另一种方法,使用 for...in 循环,但需要额外检查 hasOwnProperty console.log("n--- 使用 for...in 配合 hasOwnProperty ---"); for (let key in personPrototype) {     // 确保是原型对象自身的属性,而不是继承自 Object.prototype 等     if (personPrototype.hasOwnProperty(key) && typeof personPrototype[key] === 'function') {         console.log(`通过 for...in 找到的方法: ${key}`);     } }

这里

Object.getOwnPropertyNames()

配合

filter

是一种非常干净且推荐的方式,因为它直接获取了原型对象自身的所有属性名,然后我们再筛选出函数类型的。

for...in

循环会遍历原型链上所有可枚举的属性,所以必须配合

hasOwnProperty

来确保我们只拿原型对象自身的属性。

为什么我们需要获取原型上的方法?

有时候,我们确实需要探究一个对象背后,它那些“共享”的能力到底是什么。这不仅仅是为了满足好奇心,它在很多场景下都挺有用的。比如,你在调试一个复杂的库或者框架时,想知道一个特定类型的实例到底有哪些内置的行为,或者它从父类/原型那里继承了哪些方法。直接看实例本身可能只会看到它自己的属性,而那些共享的方法往往藏在原型链上。

js怎么获取原型上的方法

再比如说,你想对某个特定类型的所有实例,统一地进行一些“增强”或者“监控”。你不可能去遍历所有实例然后给它们挨个打补丁,更优雅的方式是直接修改它的原型。但在修改之前,你可能需要知道原型上已经有哪些方法了,避免覆盖或者冲突。这就像你拿到一份蓝图,想在上面加点东西,总得先看看蓝图上原本画了些啥吧。

还有一些高级的元编程(meta-programming)场景,比如你想实现一个通用的日志记录器,自动记录某个类所有方法的调用。这时候,你就需要动态地获取这个类原型上的所有方法,然后用代理(Proxy)或者AOP(面向切面编程)的思路去包装它们。这听起来有点复杂,但核心就是“获取原型方法”这个基础操作。

获取原型方法时常见的陷阱和注意事项有哪些?

这里面确实有些小坑,一不留神就可能掉进去。

首先,

__proto__

Object.getPrototypeOf()

的选择。虽然

__proto__

用起来很方便,但它曾经是一个非标准的属性,现在虽然在大多数浏览器和Node.JS环境中都支持了,但从规范性和兼容性角度来说,

Object.getPrototypeOf()

才是官方推荐和更稳妥的选择。尤其是当你在编写需要长期维护或者跨环境运行的代码时,坚持使用标准API总是没错的。

其次,

hasOwnProperty

的重要性。当我们遍历原型对象时,比如使用

for...in

循环,它会遍历原型链上所有可枚举的属性,不仅仅是当前原型对象自己的。这意味着,如果你不加

hasOwnProperty

检查,你可能会意外地获取到

Object.prototype

上的方法(比如

toString

,

valueOf

等)。这些通常不是我们想获取的“原型方法”,因为它们是所有对象都共有的。所以,

prototypeObject.hasOwnProperty(key)

这一步是至关重要的,它确保你只拿到当前原型对象“自己”定义的属性。

再者,不可枚举属性的问题

for...in

循环只会遍历可枚举的属性。如果原型上有一些方法被定义为不可枚举(比如使用

Object.defineProperty

并且

enumerable: false

),那么

for...in

就无法发现它们。而

Object.getOwnPropertyNames()

就能获取到所有自有属性的名称,包括可枚举和不可枚举的。所以,如果你需要获取所有原型上的方法,包括那些“隐藏”的,

Object.getOwnPropertyNames()

是更好的选择。

最后,一个大大的警告:不要轻易修改内置对象的原型。比如

Array.prototype

或者

String.prototype

。虽然技术上你可以这样做,但这样做会污染全局环境,可能导致与其他库或框架的冲突,或者在未来的JavaScript版本更新时出现不可预测的问题。这就像你在一个公共的交通枢纽里随意更改路标,虽然你觉得方便了自己,但可能会让其他人迷失方向。所以,获取原型方法通常是为了理解、分析或者在受控环境下进行操作,而不是为了肆意修改。

如何区分原型方法和实例方法?

区分原型方法和实例方法,其实就是看这个方法是直接定义在对象实例上,还是定义在它的原型链上。这在JavaScript里是个挺核心的概念,理解它能帮助你更好地掌握继承和内存管理。

一个实例方法,顾名思义,就是直接属于这个对象实例的。每次你创建一个新实例,如果这个方法是实例方法,那么每个实例都会有自己独立的一份这个方法的拷贝。比如:

function Car(make, model) {     this.make = make;     this.model = model;     // 这是一个实例方法     this.drive = function() {         console.log(`Driving the ${this.make} ${this.model}.`);     }; }  const myCar = new Car("Honda", "Civic"); const yourCar = new Car("Toyota", "Corolla");  myCar.drive(); // 输出: Driving the Honda Civic. yourCar.drive(); // 输出: Driving the Toyota Corolla.  // 检查:实例方法直接在实例上 console.log(myCar.hasOwnProperty('drive')); // true

而原型方法呢,它是定义在构造函数的

prototype

对象上的。所有由这个构造函数创建的实例,都会共享同一个原型方法。它们自己本身并没有这个方法的副本,而是通过原型链去“查找”并调用它。这大大节省了内存,因为方法只需要存储一份。

function Bike(brand) {     this.brand = brand; }  // 这是一个原型方法 Bike.prototype.ride = function() {     console.log(`Riding the ${this.brand} bike.`); };  const myBike = new Bike("Giant"); const yourBike = new Bike("Trek");  myBike.ride(); // 输出: Riding the Giant bike. yourBike.ride(); // 输出: Riding the Trek bike.  // 检查:原型方法不在实例上,而是在其原型上 console.log(myBike.hasOwnProperty('ride')); // false console.log(Object.getPrototypeOf(myBike).hasOwnProperty('ride')); // true

所以,最直接的区分方式就是使用

hasOwnProperty()

方法。如果你想检查一个对象

obj

是否有一个名为

methodName

的实例方法,你就调用

obj.hasOwnProperty(methodName)

。如果返回

true

,那它就是实例方法。如果返回

false

,但

obj.methodName

依然能被调用(因为它在原型链上),那么它就是原型方法。

可以这样来判断:

function checkMethodType(obj, methodName) {     if (obj.hasOwnProperty(methodName) && typeof obj[methodName] === 'function') {         return "实例方法";     }      let proto = Object.getPrototypeOf(obj);     while (proto) {         if (proto.hasOwnProperty(methodName) && typeof proto[methodName] === 'function') {             return "原型方法";         }         proto = Object.getPrototypeOf(proto);     }     return "不是方法或不存在"; }  console.log(checkMethodType(myCar, 'drive')); // 实例方法 console.log(checkMethodType(myBike, 'ride')); // 原型方法 console.log(checkMethodType({}, 'toString')); // 原型方法 (来自 Object.prototype) console.log(checkMethodType(myCar, 'brake')); // 不是方法或不存在

这个

checkMethodType

函数的逻辑就是:先看是不是自己的属性,如果不是,就沿着原型链往上找,直到找到或者原型链尽头。



评论(已关闭)

评论已关闭