盲点知识 迈不过友情╰ 2022-05-09 12:04 226阅读 0赞 # 注意 `new` 运算符的优先级 # function Foo() { return this; } Foo.getName = function () { console.log('1'); }; Foo.prototype.getName = function () { console.log('2'); }; new Foo.getName(); // -> 1 new Foo().getName(); // -> 2 通过这段代码可以看出:`new Foo()` 的优先级高于 `new Foo`. 对于代码1 来说:是将 `Foo.getName` 当成一个构造函数来执行,执行构造函数所以输出为1. 对于代码2来说:通过 `new Foo()` 创建了一个Foo的实例,通过实例访问其原型链上的 方法所以输出为2. # 注意非匿名的立即执行函数 # var foo = 1; // 有名立即执行函数 (function foo(){ foo = 1; console.log(foo); })(); // 执行这段代码会输出什么呢? // -> ƒ foo() { foo = 10 ; console.log(foo) } // 再去访问 foo 的值 foo // -> 1 当JS执行器遇到非匿名的立即执行函数时,会创建一个辅助的特定对象,然后将函数名称作为这个对象的属性,因此行数内部才可以访问到 `foo` ,但这个值是只读的,所以对其重新赋值不会生效,所以打印结果还是这个函数,并且外部的值也没有发生改变。 # 关于对象的深拷贝 # * 可以使用 `JSON.stringify` 和 `JSON.parse` 这个两个方法 优点:简单 缺点:会忽略掉 `undefined` ; 不能序列化函数 ; 不能解决循环引用的对象 function clone(obj) { return JSON.parse(JSON.stringify(obj)); } * 使用递归循环赋值的方式 优点:可以处理 `undefined`、函数等各种情况 缺点:实现相对麻烦,效率不高 function clone(obj) { if(!obj || typeof obj !== 'object') { return; } var _obj = obj.constructor === Object ? {} : []; for(let key in obj) { if(typeof obj[key] === 'object') { _obj[key] = clone(obj[key]); } else { _obj[key] = obj[key]; } } return _obj; } // 或者 function clone(obj) { if(!obj || typeof obj !== 'object') throw new TypeError('params typeError'); let _obj = obj.constructor === Object ? {} : []; Object.getOwnPropertyNames(obj).forEach(name => { if(typeof obj[name] === 'object') { _obj[name] = clone(obj[name]); } else { _obj[name] = obj[name]; } }); return _obj; } * 使用内置 `MessageChannel` 对象 优点:是内置函数中处理深拷贝性能最快的 缺点:不能处理函数(会报错) function clone(obj) { return new Promise(resolve => { let {port1, port2} = new MessageChannel(); port2.onmessage = ev => resolve(ev.data); port1.postMessage(obj); }); } clone(obj).then(console.log); # 关于`async/await` , `promise` 异步执行顺序 # 想解决这个问题,就必须知道 `await` 做了什么? > 刚开始以为 `await` 会一直等待表达执行的执行结果,之后才会执行后面的代码。 **实际上 `await` 是一个让出线程的标志(遇到 `await` 会立即返回一个 `padding` 状态的promise)**。await后面的函数会先执行一遍,然后就会跳出整个 `async` 函数来执行后面js代码。等本轮事件循环执行完又跳回到 `async` 函数中等待await后面表达式的返回值,如果返回值为非 `promise` 则继续执行async后面的代码,否则将 `promse` 加入队列。 且看一道面试题(分析代码执行 顺序): async 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"); OK,那接下来具体分析执行过程: 首先输出 **"script start"** ,然后立即将定时器加入异步事件队列。执行 **async1()** ,输出 **"async1 start"** ,进入 **async2()** ,输出 **"async2"** ,跳出整个 **async1()** 函数来执行后面js代码,执行promise执行器中的内容,输出 **"promise1"** ,执行resolve()回调,将then函数中的内容加入异步事件队列,接着输出 **"script end"** 。回到 **async1()** 的await等待 **async2()** 函数的返回值,因为返回值是一个promise实例,将promise加入异步事件队列。此时的同步代码执行完毕,轮询并从队列拿出代码放入主线程执行,所以输出 **"promise2"** ,继续执行 **async1()** 中的后续内容,输出 **"async1 end"** ,最后取出定时器中的内容并执行,输出 **"settimeout"** 。 综上所述: script start async1 start async2 promise1 script end promise2 async1 end settimeout 那么再看一个例子应该会简单很多: function testFunc() { console.log("testFunc..."); // 2 return "testFunc"; } async function testAsync() { console.log("testAsync..."); // 7 return Promise.resolve("hello testAsync"); } async function foo() { console.log("test start..."); // 1 const v1 = await testFunc(); connsole.log('hello world.'); // 5 console.log(v1); // 6 testFunc const v2 = await testAsync(); console.log(v2); // 9 hello testAsync } foo(); var promise = new Promise(resolve => { console.log("promise start.."); // 3 resolve("promise"); }); promise.then(val => console.log(val)); // 8 promise console.log("test end..."); // 4 # 防抖和节流 # * 防抖:如果用户多次调用且间隔小于wait值,那么就会被转化为一次调用。 * 节流:多次执行函数转化为,每隔一定时间(wait)调用函数 。 一个简单的防抖函数: function debounce(func, wait) { let timer = null; return function(...params) { // 如果定时器存在则清除 if(timer){ clearTimeout(timer); } // 重新开始定时执行 timer = setTimeout(() => { func.apply(this, params); }, wait); } } 缺点:只能在最后执行,不能立即被执行,在某些情况下不适用。 改进... function debounce(func, wait, immediate) { let timer, context, args; // 定时器 let later = function() { return setTimeout(() => { timer = null; if(!immediate) { func.apply(context, args); } }, wait); } return function(...params) { if(!timer) { timer = later(); // immediate 为 true,则立即执行 // 否则 缓存上下文 和 参数 if(immediate) { func.apply(this, params); } else { context = this; args = params; } } else { clearTimeout(timer); timer = later(); } } } 一个简单的节流函数: // 节流函数 // 快速的多次执行,转化为等待wait时间再去执行 function throttle(func, wait) { var timer = null; var context = null; return function(...args) { context = this; if(!timer) { timer = setTimeout(function() { timer = null; func.apply(context, args); }, wait); } } } // 如果想让第一次调用立即执行也非常简单 仅需要将 func.apply(context, args) 提到定时器外边即可。 节流函数除了可以使用定时器实现以外,当然也可以有其他方式: // 第一次调用会被立即执行 function throttle(func, wait) { var prev = 0; var context = null; return function(...args) { var now = +new Date(); context = this; if(now -prev > wait) { func.apply(context,args); prev = now; } } } # call、apply和bind # 怎么去模拟一个call函数呢? 思路:call一个非常重要的作用就是改变上下文环境也就是this,我们可以给用户传入的上下文对象上添加一个函数,通过这个上下文对象去执行函数,然后将这个函数删除,返回结果就可以了。 Function.prototype.myCall = function(context, ...args) { context = context || window; // 给上下文对象上添加这个函数 context.fn = this; // 通过这个上下文对象去执行函数 let result = context.fn(...args); // 将这个函数删除 delete context.fn; return result; } call既然都实现了,那么apply也是类似的,只不过传入的参数是一个数组而已。 Function.prototype.myApply = function(context, arr) { context = context || window; arr = arr || []; let type = {}.toString.call(arr).slice(8,-1); if(type !== 'Array') throw new TypeError('CreateListFromArrayLike called on non-object'); context.fn = this; let result = context.fn(...arr); delete context.fn; return result; } 模拟bind函数,bind函数应该返回一个新的函数。 Function.prototype.myBind = function(context, ...args) { // 保存当前的函数 let func = this; return function F(...params) { if(this instanceof F) { return new func(...args, ...params); } return func.apply(context,[...args,...params]); } } # 数组降维 # function flattenDeep(arr) { if(!Array.isArray(arr)) return [arr]; return arr.reduce((prev,cur) => { return [...prev, ...flattenDeep(cur)]; },[]); } flattenDeep([1, [[2], [3, [4]], 5]]); # 栈的压入和弹出 # 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。 function IsPopOrder(pushV,popV){ if(pushV.length === 0) return false; var stack = []; // 模拟栈 for(var i = 0, j = 0; i < pushV.length;){ stack.push(pushV[i]); i += 1; // 压入栈的值需要被弹出 while(j < popV.length && stack[stack.length-1] === popV[j]){ stack.pop(); j++; if(stack.length === 0) break; } } return stack.length === 0; } # 利用栈模拟队列 # 思路: * 对栈A添加数据。 * 如果栈B为空,循环将栈A中内容弹出放入栈B,并弹出栈B最后一项 * 如果栈B不为空,则直接弹出栈B的最后一项 var stackA = []; var stackB = []; function push(node){ stackA.push(node); } function pop(){ if(!stackB.length){ while(stackA.length){ stackB.push(stackA.pop()); } } return stackB.pop(); } # Fetch和ajax之间的区别 # fetch * Fetch API是基于Promise设计的 * 容易同构(前后端运行同一套代码) * 语法简洁,更加语义化 * 原生支持率不高,可以用polyfill兼容IE8+浏览器 fetch(url).then(function(response){ return response.json(); }).then(function(data){ console.log(data); }).catch(function(err){ console.log(err); }); ajax * 设计粗糙,不关注分离原则 * 基于事件的异步模型,不够友好 var xhr = new XMLHttpRequest(); xhr.open('GET', url); xhr.responseType = 'json'; xhr.onload = function(){ console.log(xhr.response); } xhr.onerror = function(){ console.log('error'); } xhr.send(); # Fetch常见坑 # * fetch请求默认是不带cookie的,需要设置 `fetch(url, {credentials: 'include'})` * 服务器返回400,500错误码时不会reject,只有网络错误导致不能完成时,才会reject。 * IE8, 9 的 XHR 不支持 CORS 跨域。 # 归并排序 # 将一个完整的数组分成两部分,分别对其排序,然后将两部分merge在一起即可。 function merge(left, right) { var temp = []; while(left.length && right.length) { if(left[0] < right[0]) temp.push(left.shift()); else temp.push(right.shift()); } return temp.concat(left,right); } function mergeSort(arr) { if(arr.length === 1) return arr; var mid = (arr.length/2)|0; var left = arr.slice(0,mid); var right = arr.slice(mid); return merge(mergeSort(left), mergeSort(right)); } # 箭头函数的this原理 # `this` 指向固定化,并不是因为箭头函数内部有绑定 `this` 的机制,实际原因是箭头函数没有自己的 `this` ,导致内部的this就是外层代码的 `this` ,也正是因为没有 `this` ,所以箭头函数不能用作构造函数。 # js相关尺寸 # ![iCtsdx.png][] # BFC原理 # * 在BFC垂直方向元素边距会发生重叠 * 不会与浮动元素的box重合 * 独立的容器,里外互不影响 * 浮动元素参与计算 # 自定义事件 # var content = document.querySelector('.content'); // 自定义事件 var evt = new Event('custom'); var customEvt = new CustomEvent('customEvt', { // 通过这个属性传递参数 detail: { name: 'tom', age: 12 } }); content.addEventListener('custom', (e) => { console.log('自定义事件被触发,无参数...'); console.log(e); }); content.addEventListener('customEvt', (e) => { console.log('自定义事件被触发,有参数...'); console.log(e); console.log(e.detail); }); // 点击时触发这个自定义事件 content.addEventListener('click', (e) => { content.dispatchEvent(evt); content.dispatchEvent(customEvt); }); # 变量提升 # var foo = 3; // 不在同一个作用域 function hoistVariable() { // 内部变量提升导致 foo 的初始值为undefined // 所以 foo = 5; var foo = foo || 5; console.log(foo); // 5 } hoistVariable(); 上边的比较简单,看一个函数和变量同名,关于变量提升的小问题。 var a = 6; function b(){ console.log(a); // @1 var a = 4; function a(){ alert(4); } console.log(a); //@2 } b(); * 因为JavaScript中的函数是一等公民,函数声明的优先级 最高(高于变量提升),会被提升至当前作用域最顶端,所以在 `@1` 输出的是 `function a(){alert(4);}` * 接下来执行 `a=4;` 这一句,重新对 `a` 进行赋值。 * 函数已被提升,所以不考虑,所以在 `@2` 这里自然会输出 `4` 。 如果还不能理解?且看预编译后的代码: var a; a = 6; function b(){ var a; a = function a(){ // 函数先提升 alert(4); } console.log(a); // @1 a = 4; console.log(a); // @2 } b(); // 结果已经非常明了了 # POST和GET的区别 # * POST对请求参数的长度没有限制,而GET如果请求参数过长,会被浏览器截断。 * GET请求参数会直接暴露在URL上,所以不适合用来传递敏感信息。 * GET请求可以被浏览器主动缓存,而POST请求不可以,除非手动设置。 * GET请求在浏览器回退时是无害的,而POST会再次提交请求。 * GET请求产生的URL可以被浏览器缓存,而POST不可以。 # 通信类 # **1. 前后端如何通信?** * ajax * WebSocket * CORS **2. 如何创建ajax?** // 创建xhr对象 var xhr = XMLHttpRequest ? new XMLHttpRequest() : new window.ActiveXObject('Microsoft.XMLHTTP'); // GET 请求 xhr.open('GET',url,true); xhr.send(); // POST 请求 xhr.open('POST',url,true); // 表单数据 , 也可以提交json数据,相应的content-Type: application/json xhr.setRequestHeader('content-Type', 'application/x-www-from-urlencoded'); xhr.send(dataArr.join('&')); xhr.onload = function() { if(xhr.status === 200 || xhr.status === 304) { var data = xhr.responseText; // 拿到数据 } else { // 出问题了 } } **3. 跨域通信的几种方式?** * JSONP:利用 `script` 标签的跨域能力,服务返回一个js函数调用,数据作为函数的一个参数来传递。 var script = document.createElement('script'); script.type = 'text/javascript'; script.src = url; // 跨域地址 document.head.appendChild(script); //有能耐把我这辈子都安排了,不然少他妈扯淡。 setTimeout(function() { document.head.removeChild(script); script = null; }); // 接收数据 function jsonpCallback(data) { console.log(data); } * WebSocket:不受同源政策限制。 var ws = new WebSocket('wss://echo.websocket.org'); ws.onopen = function(e) { ws.send('hello...'); } ws.onmessage = function(e) { var data = e.data; } ws.onclose = function() { console.log('close...'); } * Hash:利用 `location.hash` 来传值。 缺点:数据直接暴露在url中,大小、类型都有限制。 1、父窗体可以把信息写在子窗体的href的hash上,子窗口通过监听hashchange事件获取信息。 2、子窗体改变父窗体的hash值,那么就要借助第三个子窗体,第三个子窗体是第二个子窗体的子窗体。(第三个子窗体要与父窗体同源) 3、第二个子窗体把信息设置在第三个子窗体的hash值上,然后第三个子窗体改变父窗体的hash值,从而实现跨域。 ![iPQsr6.png][] // 父窗体 var son = document.getElementByTagName('iframe'); son.src = son.src + '#' + data; // 子窗体 window.onhashchange = function() { var data = window.location.hash; } * postMessage :`语法:window.postMessage(msg,targetOrigin)` // 窗口A 发送 BWindow.postMessage('发送的数据', 'http://B.com'); // 窗口B 接收 window.addEventListener('message', (event) => { event.origin: // http://A.com event.source; // AWindow event.data; // '发送的数据' }); * CORS: 跨域资源共享。 fetch(url, { method: 'get', // 头信息配置 }).then(() => {}); # 安全类 # * CSRF,跨站请求伪造(Cross-site request forgery) ![iP1PXt.png][] 防御措施: Token验证(请求必须携带Token) Referer 验证(验证请求的来源是否可信) * XSS(cross-site scripting 跨站脚本攻击) 原理:注入脚本 防御措施:对用户的输入做验证 # 渲染机制类 # **1. 什么是DOCTYPE及作用?** 用来声明文档类型和DTD规范的。 DTD(document type definition)文档类型定义,是一系列的语法规则,用来声明XML或(X)HTML的文件类型,浏览器会使用它来决定文档类型,决定使用何种协议来解析,以及切换浏览器模式。 **2. 常见的doctype有哪些?** * HTML5 <!DOCTYPE html> * HTML4.01 Strict 严格模式 (不包含展示性或弃用的元素) * HTML4.01 Transitional 传统(宽松)模式(包含展示性或弃用的元素) # 页面性能类 # **提升页面性能的方式?** * 资源压缩合并,减少HTTP请求 * 非核心代码异步加载 异步加载方式: 1. 动态脚本加载 2. defer (HTML解析完顺序执行) 3. async (加载完立即执行) * 利用浏览器缓存 * 使用CDN * 预解析DNS <meta http-equiv="x-dnns-prefetch-control" content="on"> <link rel="dns-prefetch" href="//host_name_to_prefetch.com"> # 错误监控 # * 前端错误分类:代码(运行)错误 资源加载错误 * 错误捕获方式 运行错误捕获:(1)try...catch (2)window.onerror 资源加载错误 :(1)object.onerror(资源错误不冒泡) (2)performance.getEntries() (3)Error事件捕获(在事件流捕获阶段处理错误) * 跨域js运行错误也是可以捕获的,捕获的错误:script error * 上报错误原理 利用Image对象上报 // 利用Image标签上报错(简单、不需要借助其他库) (new Image()).src = 'http://www.baidu.com/test?error=xxx'; # 二分法查找 # function binarySearch(arr,val,leftIndex,rightIndex) { if(leftIndex > rightIndex){ return; } var midIndex = (leftIndex + rightIndex) / 2 | 0; var midVal = arr[midIndex]; if(val > midVal) { return binarySearch(arr,val,midIndex+1,rightIndex); }else if(val < midVal) { return binarySearch(arr,val,leftIndex,midIndex-1); }else{ return midIndex; } } # 连续最长不重复字符串 # 在一个字符串中找出连续的不重复的最大长度的字符串,解决这类问题的思路: * 利用循环叠加字符串,直到出现重复为止 * 每一次叠加,记录下来最大长度的字符串 // 连续最长不重复字符串 function getMaxLenStr(str) { var cur = []; var maxLenStr = ''; for(var i = 0; i < str.length; i++) { if(!cur.includes(str[i])) { cur.push(str[i]); } else { cur = []; // 置为空 cur.push(str[i]); } // 存储最大长度的字符串 if(maxLenStr.length < cur.length) { maxLenStr = cur.join(''); } } return maxLenStr; } getMaxLenStr('ababcabcde'); // abcde 和上面这道题有一样思路的是:求一个数组当中,连续子向量的最大和。 无非是将 对比字符串的长度 改为 对比值大小 function FindGreatestSumOfSubArray(arr) { let sum = arr[0]; let max = arr[0]; for(let i = 1; i < arr.length; i++) { if(sum < 0) { sum = arr[i]; }else{ sum += arr[i]; } // 记录最大值 if(max < sum) { max = sum; } } return max; } # 面试题:解码字符串并输出 # 阿里的一道面试题:给定一个编码字符,按编码规则进行解码,输出字符串 编码规则:`coount[letter]` ,将`letter`的内容`count`次输出,`count`是0或正整数,`letter`是区分大小写的纯字母。 实例: * const s= `3[a]2[bc]`; decodeString(s); // 返回 `‘aaabcbc’` * const s= `3[a2[c]]`; decodeString(s); // 返回 `‘accaccacc’` * const s= `2[ab]3[cd]ef`; decodeString(s); // 返回 `‘ababcdcdcdef’` 解题过程... * 思路: 使用栈这种数据结构,如果`push`的内容为`‘]’`,则循环`pop`字符,直到碰到`’[‘`,然后将`pop` 出来的字符串按规则整理后,重新`push`进栈中,最后将栈内的内容拼接成字符串输出即可。 * 代码: const s = '2[a2[c]]ef'; function decodeString(str) { let stack = []; // 存储字符串的栈 for (let i = 0; i < str.length; i++) { let cur = str[i]; if (cur !== ']') { stack.push(cur); } else { // 弹出 let count = 0; let loopStr = []; let popStr = ''; while ((popStr = stack.pop()) !== '[') { loopStr.unshift(popStr); } count = stack.pop(); // 添加结果 let item = ''; for (let i = 0; i < count; i++) { item += loopStr.join(''); } stack.push(...(item.split(''))); } } return stack.join(''); } console.log(decodeString(s)); // accaccef # 排序算法时间复杂度 # * 元素的`移动次数`与关键字的初始排列次序无关的是:基数排列。 * 元素的`比较次数`与初始序列无关是:选择排序。 * 算法的`时间复杂度`与初始序列无关的是:选择排序。 # BOM和DOM # BOM 即浏览器对象模型,BOM没有相关标准,**BOM的核心对象是window对象。** DOM即文档对象模型,DOM是W3C标准,**DOM的最根本对象是document(window.document),** 这个对象实际上是window对象的属性,这个对象的独特之处是唯一一个既属于BOM有属于DOM的对象。 ![1460000016498238_w_902_h_910][] # http和WebSocket的区别: # * 相同点: 都是建立于tcp连接之上,通过tcp协议来传输数据。 * 不同点: HTTP是一种单向的协议,即客户端只能向服务器端请求信息。request永远等于response,并且这个response是被动的,不能主动发起。一旦有一个任务超时,就会阻塞后续的任务(线头阻塞)。 HTTP协议是无状态的,如使用轮询、long poll都需要将身份鉴别信息上传。 WebSocket真正的全双工通信,只需要一次连接,这样就避免了HTTP的无状态性,服务器端可以主动推送消息到达客户端。 # http2.0 # * 二进制分帧 * 多路复用,这样就避免了线头阻塞 * 服务器端推送,客户端请求HTML,服务器可以主动推送js、css那些客户端可能会用到的东西,这样就避免了重复发送请求 * 头压缩 # O(n)复杂度去重 # function unique(arr) { let obj = {}; let ret = []; for(let i = 0; i < arr.length; i++) { let cur = `${typeof arr[i]}-${arr[i]}`; if(!obj[cur]) { ret.push(arr[i]); obj[cur] = true; } } return ret; } var arr = [1, '1', 3, 3, 4]; unique(arr); // [1, '1', 3, 4] # 判断是否相同 # function isSame(a, b) { if(a === b) return true; if(typeof a !== typeof b) return false; // 如果均为object类型,判断属性个数是否相同 if(typeof a === 'object' && typeof b === 'object') { let aLen = Object.getOwnPropertyNames(a).length; let bLen = Object.getOwnPropertyNames(b).length; if(aLen !== bLen) return false; } return Object.getOwnPropertyNames(a).every(key => { if(typeof a[key] === 'object') { return isSame(a[key], b[key]); } return a[key] === b[key]; }); } [iCtsdx.png]: /images/20220509/a1b32cce8538428080ec5f1cd5b05842.png [iPQsr6.png]: /images/20220509/8c40ec3938fa470a9a9245d0658174a1.png [iP1PXt.png]: /images/20220509/52603732d669454f9e65a7f4110438b0.png [1460000016498238_w_902_h_910]: /images/20220509/65beb47480b04f8e9ab097cc6d4fcaf8.png
相关 异常处理盲点:Java空指针异常实例 在Java中,空指针异常(NullPointerException)是一种常见的运行时异常,它发生在尝试使用`null`引用调用方法或访问对象的属性时。以下是一些可能导致空指针 向右看齐/ 2024年11月01日 13:39/ 0 赞/ 7 阅读
相关 异常处理盲点:Java 8异常链示例 在Java 8中,引入了新的try-catch语句结构,以及更强大的异常处理工具。这里有一个简单的示例: ```java import java.util.concurren 深藏阁楼爱情的钟/ 2024年09月23日 03:03/ 0 赞/ 60 阅读
相关 异常处理盲点:Java try-catch-finally用法示例 在Java编程中,`try-catch-finally`语句是用来处理可能出现的异常情况。以下是详细的使用方法示例: 1. **try** 块:这是可能会抛出异常的地方。 秒速五厘米/ 2024年09月11日 14:48/ 0 赞/ 41 阅读
相关 javaWeb实战项目图书管理系统--4.BaseServlet类中的知识盲点 一、代码 package com.sxl.web.servlet; import javax.servlet.ServletException; 红太狼/ 2024年03月23日 11:32/ 0 赞/ 29 阅读
相关 盲点打扫 记录自己需要学习,暂时没时间学的知识点。以便后期清理 打包必须数据库开启么? Http/https.webservice,socket,webSocket等的区别等 喜欢ヅ旅行/ 2023年10月10日 09:54/ 0 赞/ 33 阅读
相关 记录一些js 自己得盲点 做jser多年,依旧有很多不熟悉的东西,边看边记录吧 toString 把各种东西变成字符串,比如把数组变成字符串,把函数变成字符串,等等 把函数 青旅半醒/ 2022年08月11日 04:29/ 0 赞/ 169 阅读
相关 记录几个盲点 20170922 1.session sessionId 怎么传输 2.tomcat server.xml 干什么用的么用 3. event\{ int id, int time\} bo 女爷i/ 2022年06月08日 10:58/ 0 赞/ 175 阅读
相关 盲点知识 注意 `new` 运算符的优先级 function Foo() { return this; } Foo.getName = fu 迈不过友情╰/ 2022年05月09日 12:04/ 0 赞/ 227 阅读
相关 jquery中知识盲点(+) jquery中`css`方法是改变内联样式 事实证明`jquery`中`css`方法是改变内联样式 $("p").css("color","red"); 蔚落/ 2021年06月26日 16:06/ 0 赞/ 309 阅读
还没有评论,来说两句吧...