首页
统计
关于
正则表达式手册
Search
1
React中编写css的几种方式
48 阅读
2
rollup.js的个人理解
41 阅读
3
【整理】Nginx基础知识
37 阅读
4
前端工程化的思考
36 阅读
5
package.json的配置参考
35 阅读
默认分类
服务器端
前端工程化
react
vue
nodejs
js+
html&css
问题集录
临时
dylin
gu
登录
/
注册
Search
标签搜索
问题
前端工程化
基础知识
css
数据库
docker
nginx
rollup.js
react
golang
js
性能优化
js基础
dylin
累计撰写
21
篇文章
累计收到
1
条评论
首页
栏目
默认分类
服务器端
前端工程化
react
vue
nodejs
js+
html&css
问题集录
临时
dylin
gu
页面
统计
关于
正则表达式手册
搜索到
3
篇与
的结果
2024-06-05
js的事件循环机制下,记录一个意外错误
js的事件循环机制是前端的基础概念。下面我们先看两段代码:setTimeout(()=>{ console.log("children2") Promise.resolve().then(()=>{ console.log("children3") }) },0) new Promise(function(resolve,reject){ console.log("children4") setTimeout(function(){ console.log("children5") resolve("children6") },0) }).then(res=>{ console.log("children7") setTimeout(function(){ console.log(res) },0) }) console.log("start") 上面的代码输出:children4、start、children2、children3、children5、children7、children6async function async1() { console.log("async1 start"); await async2(); console.log("async1 end"); } async function async2() { console.log("async2"); } console.log("script start"); setTimeout(function () { console.log("setTimeout"); }, 0); async1(); new Promise(function (resolve) { console.log("promise1"); resolve(); }).then(function () { console.log("promise2"); }); console.log("script end");上面的代码输出:script start、async1 start、async2、promise1、script end、async1 end、promise2、setTimeout第二道题时,我出现一个疑惑,当await 后面跟的不是一个 Promise 对象(而是一个同步值或已经解决的 Promise),那么await 后面的代码会被放入微任务队列吗?验证代码:async function example() { console.log('Start'); await Promise.resolve(); // 立即解决的 Promise console.log('After await'); } console.log('Before async call'); example(); console.log('After async call start'); // 输出顺序: // Before async call // After async call start // Start // After await上面的代码表明:如果 await 后面跟的不是一个异步操作,虽然await 不会真正“等待”任何东西,但它仍然会将后续代码放入微任务队列中。结论:无论 await 后面跟的是否是一个真正需要等待的异步操作,它都会导致后续代码被放入微任务队列中执行。
2024年06月05日
9 阅读
0 评论
0 点赞
2024-01-23
【基础】js表达式和运算符
迭代器和生成器JavaScript中的迭代器和生成器都是ES6中引入的重要特性,迭代器和生成器都实现了迭代器协议,它们具有相似的使用方法和不同的用途和使用场景。前提、迭代协议迭代协议规定了一个对象必须实现 next()方法,该方法返回一个对象,该对象包含两个属性:value:表示下一个要返回的元素的值。done:一个布尔值,如果迭代器已经遍历完集合中的所有元素,则为 true;否则为 false。迭代器创建迭代器在JavaScript中,你可以通过以下几种方式创建迭代器:默认迭代器:某些内置对象(如数组、字符串、Map和Set等)具有默认的迭代器,可以通过调用它们的Symbol.iterator方法获取。 const arr = [1, 2, 3]; const iterator = arrSymbol.iterator; console.log(iterator.next()); // { value: 1, done: false } console.log(iterator.next()); // { value: 2, done: false } console.log(iterator.next()); // { value: 3, done: false }console.log(iterator.next()); // { value: undefined, done: true }可迭代对象:任何实现了Symbol.iterator方法的对象都是可迭代对象。你可以通过定义一个带有Symbol.iterator方法的对象来创建自定义的可迭代对象。 const myIterable = { data: [1, 2, 3], [Symbol.iterator]() { let index = 0; return { next: () => { if (index < this.data.length) { return { value: this.data[index++], done: false }; } else { return { value: undefined, done: true }; } } }; } }; const iterator = myIterable[Symbol.iterator](); console.log(iterator.next()); // { value: 1, done: false } // ...生成器函数:生成器函数(使用function*定义的函数)返回的是一个迭代器对象,该对象也实现了迭代器协议。 function* myGenerator() { yield 1; yield 2; yield 3; } const iterator = myGenerator(); console.log(iterator.next()); // { value: 1, done: false } // ...使用迭代器迭代器通常与for...of循环一起使用,因为for...of循环会自动调用迭代器的next()方法,直到done属性为true。 const arr = [1, 2, 3]; for (const value of arr) { console.log(value); // 1, 2, 3 }在这个例子中,arr是一个数组,它有一个默认的迭代器。for...of循环会调用这个迭代器,并逐个处理数组中的元素。总之,迭代器是JavaScript中一个强大的工具,它允许你以灵活和高效的方式处理集合中的元素。通过实现迭代器协议,你可以创建自己的可迭代对象,并使用for...of循环或其他迭代方法来遍历它们。生成器在JavaScript中,生成器(Generators)是一种可以暂停和恢复执行的函数。它们允许你使用function*语法定义一个生成器函数,并使用yield关键字在函数执行过程中暂停和恢复。生成器特别适用于需要逐步生成值或处理异步操作的场景。下面是一个简单的例子,展示了如何定义和使用生成器:定义生成器函数 function* numberGenerator() { console.log('Start'); yield 1; console.log('Resume at 2'); yield 2; console.log('Resume at 3'); yield 3; console.log('End'); }使用生成器函数生成器函数返回一个生成器对象,这个对象有一个next()方法,用于控制生成器的执行。每次调用next()方法,生成器函数会执行到下一个yield语句,并返回该语句的值。 const gen = numberGenerator(); console.log(gen.next().value); // 输出: 1, 控制台输出: Start console.log(gen.next().value); // 输出: 2, 控制台输出: Resume at 2 console.log(gen.next().value); // 输出: 3, 控制台输出: Resume at 3 console.log(gen.next().done); // 输出: true, 控制台输出: End迭代生成器你也可以使用for...of循环来迭代生成器,这样更简洁: for (const value of numberGenerator()) { console.log(value); // 插入一些异步操作或其他逻辑 }处理异步操作生成器在处理异步操作时特别有用,通常与Promise和co库(或其他类似的库)一起使用。下面是一个简单的例子,展示了如何使用生成器处理异步操作: function fetchData(url) { return new Promise((resolve) => { setTimeout(() => { resolve(`Data from ${url}`); }, 1000); }); } function* asyncGenerator() { const data1 = yield fetchData('http://example.com/1'); console.log(data1); const data2 = yield fetchData('http://example.com/2'); console.log(data2); } // 使用一个辅助函数来处理生成器的异步执行(这里我们手动实现一个简单的版本) function runGenerator(gen) { const it = gen(); function next(value) { const result = it.next(value); if (!result.done) { result.value.then(next); } } next(); } runGenerator(asyncGenerator);在这个例子中,生成器asyncGenerator在每次yield时都会等待一个Promise解决,然后继续执行。runGenerator函数负责处理这种异步流程。需要注意的是,在现代JavaScript开发中,async/await语法已经变得非常流行,并且通常被用作处理异步操作的首选方法。生成器在处理某些特定场景时仍然很有用,但对于大多数异步编程任务,async/await通常更为简洁和直观。迭代器和生成器对比一、定义与功能迭代器 :迭代器是一个对象,它实现了迭代器协议,允许你按顺序逐个访问集合中的元素。迭代器对象具有一个 next()方法,该方法每次调用时都会返回集合中的下一个元素,直到遍历完所有元素。迭代器主要用于遍历可迭代对象(如数组、字符串、Map、Set等),提供了一种统一的遍历机制。生成器 :生成器是一种特殊的函数,它能够在执行过程中暂停并恢复执行。生成器函数使用 function*语法定义,并通过 yield关键字来产生值。生成器函数返回的是一个迭代器对象,该对象也实现了迭代器协议,因此可以使用 next()方法来控制生成器的执行。生成器的主要优势在于能够按需生成一系列值,而不是一次性返回所有值,这对于处理大量数据或异步操作非常有用。二、使用场景与特点迭代器 :适用于简单遍历可迭代对象的场景。迭代器提供了一种标准化的遍历机制,使得不同数据结构可以使用相同的语法进行遍历。迭代器在遍历过程中不会占用过多内存,因为它按需访问元素。生成器 :适用于需要按需生成值的场景,如大数据处理、异步编程等。生成器可以暂停和恢复执行,这使得它能够在等待异步操作完成时释放控制权,从而提高程序的响应性和性能。生成器还可以用于创建无限序列或惰性求值的数据结构。三、性能与应用迭代器 :由于迭代器只是按需访问元素,因此在处理大量数据时具有较高的性能。迭代器是JavaScript中遍历可迭代对象的标准方式,因此广泛应用于各种场景。生成器 :生成器在处理复杂数据或异步操作时具有显著优势,因为它能够暂停和恢复执行,从而避免阻塞主线程。生成器还可以与其他异步处理机制(如Promises、async/await等)结合使用,以实现更高效的异步编程。总结:JavaScript中的迭代器和生成器虽然都实现了迭代器协议,但它们在使用场景、功能特点和性能方面还是有区别的。迭代器主要用于简单遍历可迭代对象,而生成器则适用于需要按需生成值的复杂场景。在选择使用迭代器还是生成器时,应根据具体的应用需求和性能考虑来决定。
2024年01月23日
31 阅读
0 评论
0 点赞
2024-01-22
js逆向
JavaScript逆向工程(ReverseEngineering)是指分析和理解已编译或已部署的JavaScript代码的过程,以便了解其工作原理、找到漏洞、进行修改或复制其功能。这个过程通常用于安全研究、调试、性能优化或破解某些软件。注意: 逆向工程在某些情况下可能涉及法律问题,尤其是当用于破解版权保护的软件时。确保你的行为符合当地法律和行业准则。以下是一些JavaScript逆向工程的基本步骤和技巧:1. 收集信息确定目标 :确定你要逆向的JavaScript代码的位置。这可以是网页中的 <script>标签、外部JavaScript文件或嵌入在HTML中的内联脚本。工具准备 :准备必要的工具,如浏览器开发者工具(如Chrome DevTools)、文本编辑器(如VS Code)、JavaScript解析器或反编译器(如UglifyJS、JSNice)。2. 获取代码使用浏览器开发者工具 :在浏览器中打开目标网页,使用开发者工具查看和下载JavaScript文件。网络请求拦截 :使用工具如Fiddler、Wireshark或浏览器的网络监视功能拦截和保存JavaScript文件的网络请求。3. 分析代码格式化代码 :如果代码是压缩或混淆的,使用工具如Prettier、Beautify或在线JavaScript格式化工具将代码格式化,使其更易读。理解代码逻辑 :逐行阅读代码,理解其逻辑、函数、变量和数据流。调试 :在浏览器中设置断点,使用开发者工具的调试功能逐步执行代码,观察变量值和程序行为。4. 逆向特定功能查找入口点 :确定你感兴趣的特定功能的入口点,如事件监听器、定时器回调或特定的函数调用。跟踪执行路径 :从入口点开始,跟踪代码的执行路径,理解它是如何处理输入、执行逻辑并产生输出的。提取逻辑 :一旦理解了特定功能的逻辑,你可以尝试将其提取出来,以便在其他地方重用或分析。5. 修改或复制功能手动修改 :如果你需要修改代码的功能,可以在开发者工具中直接编辑代码,然后观察效果。自动化工具 :对于更复杂的修改,你可以编写脚本来自动化这个过程,或使用工具如Tampermonkey/Greasemonkey来创建用户脚本。重建项目 :如果目标是完全复制功能,你可能需要重建整个逻辑,包括HTML、CSS和JavaScript,以确保在新的环境中正确工作。6. 法律和道德考虑版权法 :确保你的逆向工程活动不违反任何版权法。通常,逆向工程用于合法的调试、兼容性分析或安全评估是合法的。隐私和保密 :尊重用户的隐私和数据的保密性,不要泄露敏感信息。道德准则 :遵循道德准则,不要滥用逆向工程技能进行恶意活动。示例工具Chrome DevTools :用于查看、调试和修改网页上的JavaScript代码。Firefox Developer Tools :与Chrome DevTools类似,但提供了不同的调试和性能分析工具。Prettier :用于代码美化和格式化。JSNice :用于分析和理解混淆的JavaScript代码。Tampermonkey/Greasemonkey :用于创建和管理用户脚本,以修改网页行为。通过遵循这些步骤和技巧,你可以更有效地进行JavaScript逆向工程。然而,始终要牢记法律和道德约束,确保你的活动合法且正当。JavaScript逆向时,常用hook方法在逆向分析JavaScript代码时,开发者经常使用一些用于hook(钩子)的技术来监视或修改程序的行为。以下是一些常用的hook技术及其示例代码。01、dom操作在JS逆向脚本中,DOM操作是最常用的一种Hook方式。通过修改DOM元素的属性和样式,我们可以实现对网页的控制和修改。// 修改DOM元素的属性 document.getElementById('elementId').setAttribute('attrName', 'attrValue'); // 修改DOM元素的样式 document.getElementById('elementId').style.property = 'value';02、Cookie操作Cookie Hook 用于定位 Cookie 中关键参数生成位置,以下代码演示了当 Cookie 中匹配到了 __dfp 关键字, 则插入断点:<script> (function () { 'use strict'; var cookieTemp = ''; Object.defineProperty(document, 'cookie', { set: function (val) { if (val.indexOf('__dfp') != -1) { debugger; } console.log('Hook捕获到cookie设置->', val); cookieTemp = val; return val; }, get: function () { return cookieTemp; }, }); })(); (function () { 'use strict'; var org = document.cookie.__lookupSetter__('cookie'); document.__defineSetter__('cookie', function (cookie) { if (cookie.indexOf('__dfp') != -1) { debugger; } org = cookie; }); document.__defineGetter__('cookie', function () { return org; }); })(); </script>03、事件监听操作事件监听也是JS逆向油猴脚本中常用的一种Hook方式。通过监听网页上的事件,我们可以触发自定义的操作和行为。<script> // 监听按钮点击事件 document.getElementById('buttonId').addEventListener('click', function () { // 自定义操作和行为 }); </script>04、AJAX拦截操作AJAX拦截也是JS逆向油猴脚本中常用的一种Hook方式。通过拦截网页上的AJAX请求,我们可以实现对数据的控制和修改。<script> // 拦截AJAX请求 XMLHttpRequest.prototype._send = XMLHttpRequest.prototype.send; XMLHttpRequest.prototype.send = function () { // 自定义操作和行为 this._send.apply(this, arguments); }; </script>05、函数替换操作函数替换也是JS逆向油猴脚本中常用的一种Hook方式。通过替换网页上的函数,我们可以实现对函数的控制和修改。<script> // 替换原有函数 var originalFunction = window.functionName; window.functionName = function () { // 自定义操作和行为 originalFunction.apply(this, arguments); }; </script>06、Header操作Header Hook 用于定位 Header 中关键参数生成位置,以下代码演示了当 Header 中包含 Authorization 关键字时,则插入断点:<script> (function () { var org = window.XMLHttpRequest.prototype.setRequestHeader; window.XMLHttpRequest.prototype.setRequestHeader = function (key, value) { if (key == 'Authorization') { debugger; } return org.apply(this, arguments); }; })() </script>07、URL操作URL Hook 用于定位请求 URL 中关键参数生成位置,以下代码演示了当请求的 URL 里包含 login 关键字时,则插入断点:<script> (function () { var open = window.XMLHttpRequest.prototype.open; window.XMLHttpRequest.prototype.open = function (method, url, async) { if (url.indexOf("login") != 1) { debugger; } return open.apply(this, arguments); }; })(); </script>08、JSON.stringify操作JSON.stringify() 方法用于将 JavaScript 值转换为 JSON 字符串,在某些站点的加密过程中可能会遇到,以下代码演示了遇到 JSON.stringify() 时,则插入断点:<script> (function() { var stringify = JSON.stringify; JSON.stringify = function(params) { console.log("Hook JSON.stringify ——> ", params); debugger; return stringify(params); } })(); </script>09、JSON.parse操作JSON.parse() 方法用于将一个 JSON 字符串转换为对象,在某些站点的加密过程中可能会遇到,以下代码演示了遇到 JSON.parse() 时,则插入断点:(function() { var parse = JSON.parse; JSON.parse = function(params) { console.log("Hook JSON.parse ——> ", params); debugger; return parse(params); } })();10、eval操作JavaScript eval() 函数的作用是计算 JavaScript 字符串,并把它作为 脚本代码来执行。如果参数是一个表达式,eval() 函数将执行表达式。如果参数是 Javascript 语句,eval() 将执行 Javascript 语句,经常被用来动态执行 JS。以下代码执行后,之后所有的 eval() 操作都会在控制台打印输出将要执行的 JS 源码:(function() { // 保存原始方法 window.__cr_eval = window.eval; // 重写 eval var myeval = function(src) { console.log(src); console.log("=============== eval end ==============="); debugger; return window.__cr_eval(src); } // 屏蔽 JS 中对原生函数 native 属性的检测 var _myeval = myeval.bind(null); _myeval.toString = window.__cr_eval.toString; Object.defineProperty(window, 'eval', { value: _myeval }); })();11、Function操作以下代码执行后,所有的函数操作都会在控制台打印输出将要执行的 JS 源码:(function() { // 保存原始方法 window.__cr_fun = window.Function; // 重写 function var myfun = function() { var args = Array.prototype.slice.call(arguments, 0, -1).join(","), src = arguments[arguments.length - 1]; console.log(src); console.log("=============== Function end ==============="); debugger; return window.__cr_fun.apply(this, arguments); } // 屏蔽js中对原生函数native属性的检测 myfun.toString = function() { return window.__cr_fun + "" } Object.defineProperty(window, 'Function', { value: myfun }); })();
2024年01月22日
28 阅读
0 评论
0 点赞