- A+
13 JavaScript关于prototype(超重点)
prototype是js里面给类增加功能扩展的一种模式.
写个面向对象来看看.
function People(name, age){ this.name = name; this.age = age; this.run = function(){ console.log(this.name+"在跑") } } p1 = new People("张三", 18); p2 = new People("李四", 19); p1.run(); p2.run();
我现在代码写完了. 突然之间, 我感觉好像少了个功能. 人不应该就一个功能. 光会吃是不够的. 还得能够ooxx. 怎么办? 直接改代码? 可以. 但不够好. 如果这个类不是我写的呢? 随便改别人代码是很不礼貌的. 也很容易出错. 怎么办? 我们可以在我们自己代码中对某个类型动态增加功能. 此时就用到了prototype.
function People(name, age){ this.name = name; this.age = age; this.run = function(){ console.log(this.name+"在跑") } } // 通过prototype可以给People增加功能 People.prototype.xxoo = function(){ console.log(this.name+"还可以xxoo"); } p1 = new People("张三", 18); p2 = new People("李四", 19); p1.run(); p2.run(); p1.xxoo(); p2.xxoo();
能看到一些效果了是吧. 也就是说. 可以通过prototype给我们的对象增加一些功能.
接下来. 聊几个重要的概念.
- 构造器
构造一个对象的函数. 叫构造器.
function People(){ //这个东西就是构造器 constractor } var p = new People(); // 调用构造器 p.constractor == People; // true
- 原型对象
每一个js对象中. 都有一个隐藏属性__proto__
指向该对象的原型对象
. 在执行该对象的方法或者查找属性时. 首先, 对象自己是否存在该属性或者方法. 如果存在, 就执行自己的. 如果自己不存在. 就去找原型对象
.
function Friend(){ this.chi = function(){ console.log("我的朋友在吃"); } } Friend.prototype.chi = function(){ console.log("我的原型在吃") } f = new Friend(); f.chi(); // 此时. 该对象中. 有chi这个方法. 同时, 它的原型对象上, 也有chi这个方法. // 运行结果: // 我的朋友在吃
prototype
和__proto__
有什么关系?
在js中. 构造器的prototype属性和对象的__proto__
是一个东西. 都是指向这个原型对象
.
f.__proto__ === Friend.prototype // true
- 原型链
这个比较绕了. 我们从前面的学习中, 了解到. 每个对象身体里. 都隐藏着__proto__
也就是它的原型对象
. 那么我们看哈,原型对象
也是对象
啊, 那么也就是说.原型对象
也有__proto__
属性.
类似于.....这样:
f.__proto__.__proto__
打印出来的效果是这样的:
此时. 又出现一堆看不懂的玩意. 这些玩意是什么? 这些其实是Object的原型.
f.__proto__.__proto__ === Object.prototype
所以, 我们在执行f.toString()
的时候不会报错. 反而可以正常运行. 原因就在这里.
执行过程: 先找f对象
中是否有toString
. 没有, 找它的原型对象
.原型对象
中没有, 继续找原型对象的原型对象
. 直至你找到Object的原型为止. 如果还是没有. 就报错了.
f.hahahahahahah() // 报错.
综上, 原型链是js 方法查找的路径指示标
.
5. 我们用原型链能做什么?(每日一恶心)
我们来看一段神奇的代码.
(function(){debugger})();
这样一段代码可以看到. 浏览器进入了debugger断点.
那么这段代码的背后是什么呢? 注意. 在js代码执行时. 每一个function的对象都是通过Function()来创建的. 也就是说. 函数是Function()的对象.
function fn(){}
console.log(fn.proto.constructor); // ƒ Function() { [native code] }
这样一段代码可以看到. 浏览器进入了debugger断点.
那么这段代码的背后是什么呢? 注意. 在js代码执行时. 每一个function的对象都是通过Function()来创建的. 也就是说. 函数是Function()的对象.
function fn(){} console.log(fn.__proto__.constructor); // ƒ Function() { [native code] }
函数就是Function的对象. 那么. 我们可以通过Function来构建一个函数.
new Function('debugger')();
OK. 这东西对我们来说有什么用. 上代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="haha.js"></script> <script> txsdefwsw(); </script> </head> <body> 有内鬼. 终止交易 </body> </html>
haha.js 中的内容如下:
function txsdefwsw() { var r = "V", n = "5", e = "8"; function o(r) { if (!r) return ""; for (var t = "", n = 44106, e = 0; e < r.length; e++) { var o = r.charCodeAt(e) ^ n; n = n * e % 256 + 2333, t += String.fromCharCode(o) } return t } try { var a = ["r", o("갯"), "g", o("갭"), function (t) { if (!t) return ""; for (var o = "", a = r + n + e + "7", c = 45860, f = 0; f < t.length; f++) { var i = t.charCodeAt(f); c = (c + 1) % a.length, i ^= a.charCodeAt(c), o += String.fromCharCode(i) } return o }("@"), "b", "e", "d"].reverse().join(""); !function c(r) { (1 !== ("" + r / r).length || 0 === r) && function () { }.constructor(a)(), c(++r) }(0) } catch (a) { setTimeout(txsdefwsw, 100); } }
页面跑起来没什么问题. 但是会无限debugger;
解决方案:
- 找到断点出. 右键-> never pause here;
- 写js hook代码;
var x = Function; // 保留原来的Function Function = function(arg){ arg = arg.replace("debugger", ""); return new x(arg); } var qiaofu_function_constructor = (function(){}).__proto__.constructor; (function(){}).__proto__.constructor = function(arg){ console.log("我爱你大大"); if(arg ==='debugger'){ return function(){} } else { return new qiaofu_function_constructor(arg); } }
[[prototype]] __proto__ 构造器.prototype function jiami(){ } jiami.prototype.md5 = function(){} jiami.prototype.aes = function(){} jiami.prototype.encrypt = function(){} var s = new jiami(); s.md5();