劫持技术
1.逆向工程:劫持网络数据包,暴力解码窃取个人隐式数据。
2.系统内置功能的重写:既保留了官方函数的原有功能,在自己写的函数中调用官方函数又扩展了其他业务功能。
常见于vue等框架底层原理和代理。响应式框架中重写点语法,在操作对象成员时不仅可以在内存中改变给对象的成员还可以修改网页页面。
3.this关键字的引用劫持:让函数内部中this指向的对象为指定的对象。但是这个指定的对象可以不引用该函数来调用该函数使this指向它。
系统内置功能的重写
重写log函数的功能,即打印数据,又将数据发送给后台。
this关键字的引用劫持
call函数
call函数的参数
函数的第1个参数是this的指向对象,剩下的n个参数全都用逗号分隔,直接放到后面作为劫持的this所在的函数的实参赋值给该函数的形参。第
27作为实参给obj.say方法中形参arg1赋值,age变量先取值再把取出的值作为实参赋值给arg2。
apply函数
数组中第1个元素27作为实参给obj.say方法中形参arg1赋值,数组中第2个元素是一个对象作为实参赋值给arg2。
apply函数的参数
函数的第1个参数是this的指向对象,剩下的所有参数都必须放在一个数组里面,将数组中的所有元素依次作为实参赋值给劫持的this所在的函数的形参。传入空数组代表没有传入实参。
可用于求数组中全是数字作为元素的最大的数字
Math对象的max函数中没有this,0只是让Math对象的max函数运行把数组所有元素作为实参传入Math对象的max函数再返回传入参数最大值。arr是将数组中的所有元素作为实参传给Math.max()函数。
call和apply参数拓展
参数都为可选,不传参相当于直接调用函数。第1个参数当传参时则函数中的this对象指向传入的实参对象。传入为基本数据的String、Number、Boolean的this会指向该基本数据的包装对象。
非严格模式下:传入的参数为null,undefined,和不传参(undefined),函数中的this指向window对象。严格模式下:第一个参数为空,this指向为undefined。第一个参数非空,this是直接指向该参数,包括undefined null。
bind函数
定义式函数可以在设计函数的时候就指定this,定义式函数后面跟一个.bind()。无论谁调用这个函数其this指向对象都被固定为bind中的对象。
bind函数参数
bind的参数和call一样。
call/apply与bind的区别
执行
call/apply改变了函数的this上下文后马上执行调用该函数的函数
bind则是返回改变了上下文后的函数,不执行调用该函数的函数
返回值
call/apply 返回调用call或apply函数的函数的执行结果
bind返回调用bind函数的函数的拷贝,是浅拷贝会返回一个新函数,并指定了新函数的this指向,保存了调用bind函数的函数的参数。
function fn(){
console.log(this);//window
};
var obj={name:"jzx"};
var newFn=fn.bind(obj);
console.log(newFn);
console.log(typeof newFn);
console.log(newFn==fn);
fn();
newFn();
call,apply,bind优先级
优先级bind比apply和call高。
关于call函数的理解
1.所有的函数对象都有call方法,call方法在Function.prototype。所有的call函数都是唯一的就是引用在内存中函数对象的原型对象的Function.prototype中的call函数。;
2.哪个函数调用call方法就是哪个函数运行;
3.调用这个运行的函数的对象就是call函数的第1个参数。
call函数调用call函数理解
fn.call是函数对象有call方法可以调用call方法,则fn.call这个函数会运行。而fn.call这个函数就是函数对象的原型对象的Function.prototype中的call函数,而调用这个call函数的是对象fm,而这个对象fm又是函数,所以调用call函数的函数对象fm也会运行。简而言之,fn.call.call(fm)等价于fm.call,即fm这个函数会运行。
只要有函数调用了call函数,调用call函数的这个函数就会运行。所以fn.call.call.call.call(fm),无论多少call函数都是把前面最后一次调用call方法的看成一个整体而这个整体就是call函数,而这次调用这个call函数的就是fm则相当于fm.call,函数fm会运行。