标签:function log tput ict code targe 运行 一个 com
使用defineProperty
劫持数据属性的变化
// var a = 1;
a = 1;
// console.log(Object.getOwnPropertyDescriptor(window,‘a‘)); // 自定义的全局变量是可配置的
// console: { value: 1, writeable: true, enumerable: true, configurable: true }
function b () {
alert(‘a的值发生改变‘);
}
bindData(window, b); // Uncaught TypeError: Cannot redefine property: a;(如果a是通过var声明的)
function bindData(target, event) {
for (var k in target) { // 给全局对象的任意属性都进行变化检测
if (target.hasOwnProperty(k)) {
let descriptor = Object.getOwnPropertyDescriptor(window, k);
// Object.getOwnPropertyDescriptor(window, "TEMPORARY") => undefined
// 找出对象可配置的属性
if (descriptor && descriptor.configurable) { // configurable 为 true, 才可以使用 defineProperty()方法来修改属性描述符
(function () {
var v = target[k]; // 闭包
Object.defineProperty(target, k, {
get: function () {
return v;
},
set: function (newValue) {
v = newValue;
event.call(this);
}
})
})();
}
}
}
}
a = 2; // alert: a的值发生改变
另外,注意
// 可配置性决定是否可以使用delete删除属性,以及是否可以修改属性描述符的特性,默认值为true
// 1.设置configurable:false后,无法使用delete删除属性
// 2.一般地,设置configurable:false后,将无法再使用defineProperty()方法来修改属性描述符
// 使用var声明全局变量时,变量的configurable为false
var a = 1;
console.log(Object.getOwnPropertyDescriptor(window,‘a‘));
// console: { value: 1, writeable: true, enumerable: true, configurable: false }
delete window.a // false // 在严格模式下删除为configurable为false的属性,会提示类型错误TypeError
Object.defineProperty(window,‘a‘,{
configurable:true
});
// Uncaught TypeError: Cannot redefine property: a
// 有一个例外,设置Configurable:false后,只允许writable的状态从true变为false
// 函数泄漏全局变量的场景
/*
function A () {
// 在一个函数中多次用到了 for 循环, 为了节省变量, 都是用了 i
for (var i=0; i<5; i++) {
// ...
}
for (i=0; i<5; i++) {
// ...
}
for (i=0; i<5; i++) {
// ...
}
}
// 在某次分拆函数的时候, 忘记在新函数中对抽取出来的 for 循环中的变量进行重新定义
// 从而导致该变量成为泄漏的全局变量
function A () {
for (var i=0; i<5; i++) {
// ...
}
for (i=0; i<5; i++) {
// ...
}
}
function B () {
for (i=0; i<5; i++) { // 这里 i 成了泄漏的全局变量
console.log(i);
}
}
*/
// 通过数据劫持对泄漏的全局变量进行检测
(function () {
var value = window["i"];
Object.defineProperty(window, "i", {
get () {
return value;
},
set (newValue) {
debugger;
value = newValue;
},
enumerable: true,
configurable: true,
});
})();
// 更快的解决方式
// window.__defineSetter__(‘i‘, function(){ debugger })
// ‘use strict‘ 使用严格模式可以避免出现未定义的变量
function B () {
for (i=0; i<5; i++) {
console.log(i);
}
}
B(); // 运行 B 函数, i 变为全局变量; 可以被我们的 debugger 调用栈检测到
/*
// 如果在函数里对 i 进行声明, 那么就不会被检测
function B () {
for (var i=0; i<5; i++) { // 这里 i 被声明了
console.log(i);
}
}
*/
标签:function log tput ict code targe 运行 一个 com
原文地址:https://www.cnblogs.com/rencoo/p/11984595.html