原型链与 this——还原对象与方法调用

本节目标

JS 的对象方法常通过「原型」共享。this 则指向「调用时的那个对象」——这是还原 obj.method() 时最易错的点。

// 运行环境:Node.js 16+(无需依赖)
// 运行:node jsr-l5.cjs

// 原型:Person 的所有实例共享 sayHi
function Person(name) { this.name = name }
Person.prototype.sayHi = function () {
  return 'Hi ' + this.name   // this 指向调用它的实例
}
const p = new Person('Tom')
console.log(p.sayHi())  // 'Hi Tom'(this === p)

// this 指向取决于「怎么调用」,不是「定义在哪」
const fn = p.sayHi
console.log(fn())        // 'Hi undefined'(this 丢了,指向全局/undefined)

// 混淆里常见:把方法挂到原型,调用时 this 才绑定
// 还原时你必须确认「调用点的那个对象」是谁,才能知道 this 取什么值

逆向要点:压缩代码常把方法挂在原型或某个对象上,调用处写成 a.b.c()。还原算法时,要追「this 此刻是哪个对象」,否则算出来的结果会差之千里(尤其涉及「实例上存的密钥」时)。

名词解释

原型链(Prototype Chain):JS 对象找属性时,如果自己没有,就顺着「原型」往上层对象找,一层层直到 null。它像「家族继承」:你找不到的东西,去你爸那找,再找不到去爷爷那找。方法挂在原型上,所有实例共享同一份,省内存。

this:函数执行时的「上下文对象」,即「这次是谁在调用我」。它不像普通变量在定义时定死,而是「调用时」才定。obj.method() 里 this 是 obj;裸调 method() 里 this 常是 undefined(严格模式)。逆向里算错 this 是结果对不上的常见原因。

课后练习

练习 1:const g = obj.fn; g() 和 obj.fn() 的 this 分别是什么?

答案:前者 this 是全局/undefined(裸调用,丢失绑定);后者 this 是 obj。所以还原「方法内部用到 this.xxx」时,必须确认调用方式,否则复现时取不到正确值。

练习 2:原型链对逆向「共享配置」有什么影响?

答案:如果密钥/配置挂在原型或某个单例对象上,所有用到它的方法都读同一份。你还原其中一个方法时,要记得去那个共享对象里取密钥,而不是当成本地变量。

总结

this 是 JS 里最被低估的坑,也是逆向复现时「结果差一位」的高发地。我的观点:还原任何「对象方法」时,第一件事不是读算法,而是先确定 this 是谁。很多初学者把 obj.method() 里读到的 this.key 当成「某个局部变量」,复现时就漏了这层绑定,算出来自然对不上。原型链则提醒你:方法用的数据可能不在「当前函数里」,而在「它挂的那个对象/原型」上。养成习惯——看到 xxx.yyy() 先问「xxx 此刻是什么」,再去读 yyy 的算法,逆向会稳很多。