您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
A JavaScript hook/reply ultility
当前为
此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.greatest.deepsurf.us/scripts/18715/661566/Hooks.js
// ==UserScript== // @name Hooks // @namespace [email protected] // @description A JavaScript hook/reply ultility // @author xymopen // @version 1.1.5 // @grant none // @license BSD 2-Clause // ==/UserScript== // @updateURL https://raw.githubusercontent.com/xymopen/JS_Misc/master/Hooks.js // I was finishing unit test and found there are some bugs about the logic /** * Hooks functions or properties, getters/setters * and methods of an object you are intrested in */ var Hooks = ( function () { "use strict"; var Functions = { /** * wrapper a function * @param {Function} target * @param {(Function, Object?, Arguments) => void} onApply */ apply: function apply( target, onApply ) { if ( "function" === typeof target && "function" === typeof onApply ) { var fn = function () { return onApply.call( this, target, this, arguments ); }; fn.prototype = target.prototype; return fn; } else { throw new TypeError(); } } }; /** * Hooks functions or properties, getters/setters * and methods of an object you are intrested in */ var Hooks = { /** * hook a property of an object * @param {Object} target - an object having or to have the property to be hooked * @param {String} propertyName - the name of the property to be hooked * @param {Function} onGet - the hook call when about to get the property * @param {Function} onSet - the hook call when about to set the property */ property: function property( target, propertyName, onGet, onSet ) { var descriptor, oldValue; if ( Object.prototype.hasOwnProperty.call( target, propertyName ) ) { descriptor = Object.getOwnPropertyDescriptor( target, propertyName ); if ( Object.prototype.hasOwnProperty.call( descriptor, "value" ) ) { oldValue = descriptor.value; delete descriptor.value; delete descriptor.writable; } else if ( Object.prototype.hasOwnProperty.call( descriptor, "get" ) ) { oldValue = descriptor.get.call( target ); } else { oldValue = undefined; } } else { descriptor = { configurable: true, enumerable: true, }; oldValue = undefined; } descriptor.get = function get() { return onGet.call( this, target, propertyName, oldValue ); }; descriptor.set = function set( newValue ) { oldValue = onSet.call( this, target, propertyName, oldValue, newValue ); }; Object.defineProperty( target, propertyName, descriptor ); }, /** * the hook call when about to get the property * @callback onGet * @param {object} target - the object having the property hooked * @param {string} propertyName - the name of the property hooked * @param {any} oldValue - the current value of the property */ /** * the hook call when about to set the property * @callback onSet * @param {object} target - the object having the property hooked * @param {string} propertyName - the name of the property hooked * @param {any} oldValue - the current value of the property * @param {any} newValue - the value about to be set to the property */ /** * alias of #property but fill the #onSet automatically * @function get * @param {Object} target - an object having or to have the property to be hooked * @param {String} propertyName - he name of the property to be hooked * @param {onGet} onGet - the hook call when about to get the property */ get: function get( target, propertyName, onGet ) { return Hooks.property( target, propertyName, onGet, function ( target, propertyName, oldValue, newValue ) { return Hooks.Reply.set( arguments ); } ); }, /** * alias of #property but fill the #onGet automatically * @function set * @param {Object} target - an object having or to have the property to be hooked * @param {String} propertyName - the name of the property to be hooked * @param {onSet} onSet - the hook call when about to set the property */ set: function set( target, propertyName, onSet ) { return Hooks.property( target, propertyName, function ( target, propertyName, oldValue ) { return Hooks.Reply.get( arguments ); }, onSet ); }, /** * hook a getter property of an object * @function getter * @param {object} target - an object having the getter property to be hooked * @param {string} propertyName - the name of the getter property to be hooked * @param {onGetter} onGetter - the hook replace the getter */ getter: function getter( target, propertyName, onGetter ) { var descriptor; if ( Object.prototype.hasOwnProperty.call( target, propertyName ) ) { descriptor = Object.getOwnPropertyDescriptor( target, propertyName ); if ( Object.prototype.hasOwnProperty.call( descriptor, "get" ) ) { descriptor.get = Functions.apply( descriptor.get, function ( getter, thisArg, args ) { return onGetter.call( this, target, propertyName, getter, thisArg, args ); } ); Object.defineProperty( target, propertyName, descriptor ); } } }, /** * the hook replace the getter * @callback onSetter * @param {object} target - the object having the getter property hooked * @param {string} propertyName - he name of the getter property hooked * @param {function} getter - the getter replaced * @param {object|undefined} thisArg - #this reference * @param {arguments} args - the arguments pass to the getter, should be #undefined */ /** * hook a setter property of an object * @function setter * @param {object} target - an object having the setter property to be hooked * @param {string} propertyName - the name of the setter property to be hooked * @param {onSetter} onSetter - the hook replace the setter */ setter: function setter( target, propertyName, onSetter ) { var descriptor; if ( Object.prototype.hasOwnProperty.call( target, propertyName ) ) { descriptor = Object.getOwnPropertyDescriptor( target, propertyName ); if ( Object.prototype.hasOwnProperty.call( descriptor, "set" ) ) { descriptor.set = Functions.apply( descriptor.set, function ( setter, thisArg, args ) { onSetter.call( this, target, propertyName, setter, thisArg, args ); } ); Object.defineProperty( target, propertyName, descriptor ); } } }, /** * the hook replace the setter * @callback onSetter * @param {object} target - the object having the setter property hooked * @param {string} propertyName - he name of the setter property hooked * @param {function} setter - the setter replaced * @param {object|undefined} thisArg - #this reference * @param {arguments} args - the arguments pass to the setter, should be a right value */ /** * hook a method of an object * @function method * @param {object} target - an object having or to have the method to be hooked * @param {string} methodName - the name of the method to be hooked * @param {onApply} onApply - the hook replace the method */ method: function method( target, methodName, onApply ) { var method = target[ methodName ]; function hook( method ) { return Functions.apply( method, function ( method, thisArg, args ) { return onApply.call( this, target, methodName, method, thisArg, args ); } ); }; if ( "function" === typeof method ) { target[ methodName ] = hook( method ); } else if ( !Object.prototype.hasOwnProperty.call( target, methodName ) ) { Object.defineProperty( target, methodName, { configurable: true, enumerable: true, set: function ( value ) { Object.defineProperty( target, methodName, { configurable: true, enumerable: true, value: typeof value === "function" ? hook( value ) : value, writable: true } ); }, get: function () { return undefined; } } ); } }, /** * the hook replace the method * @callback onApply * @param {object} target - the object having the method hooked * @param {string} methodName - the name of the method hooked * @param {object|undefined} thisArg - #this reference * @param {arguments} args - the arguments pass to the method */ }; Hooks.Reply = { get: function ( param ) { var target = param[ 0 ], propertyName = param[ 1 ], oldValue = param[ 2 ]; return oldValue; }, set: function ( param ) { var target = param[ 0 ], propertyName = param[ 1 ], oldValue = param[ 2 ], newValue = param[ 3 ]; return newValue; }, getter: function ( param ) { var target = param[ 0 ], propertyName = param[ 1 ], getter = param[ 2 ], thisArg = param[ 3 ], args = param[ 4 ]; return getter.apply( thisArg, args ); }, setter: function ( param ) { var target = param[ 0 ], propertyName = param[ 1 ], setter = param[ 2 ], thisArg = param[ 3 ], args = param[ 4 ]; setter.apply( thisArg, args ); }, method: function method( param ) { var target = param[ 0 ], methodName = param[ 1 ], method = param[ 2 ], thisArg = param[ 3 ], args = param[ 4 ]; return method.apply( thisArg, args ); }, }; return Hooks; } )();