题
#
作用域和自由变量- 所有的自由变量的查找,是在函数定义的地方,向上级作用域查找 而不是在执行的地方!!!
if不算局部作用域?var a;if (true) { a = 90; var a = 100;}console.log(a); // 100
var a;function fn() { a = 90; var a = 100;}fn();console.log(a); // undefined
var a;if (true) { a = 5;
function a() {} a = 0; console.log(a)}console.log(a) // 0 5
var a¹; if (true) { function a²() {} // hoisted a² = 5; a¹ = a²; // at the location of the declaration, the variable leaves the block a² = 0; console.log(a²)}console.log(a¹);
https://stackoverflow.com/questions/58619924/confused-about-function-declaration-in/58620404#58620404
let ifor (i = 1; i <= 3; i++) { setTimeout(function () { console.log(i) }, 300)} // 4 4 4
let a = 100function test() { alert(a) // 100 a = 10 alert(a) // 10}test()alert(a) // 10
var var1 = 1function a() { console.log(var1) // 1 console.log(var2) // ReferenceError: var2 is not defined}
function b() { var var1 = 2 var var2 = 3 a() // 闭包 调用 a() 无法访问b()里面的变量}b()console.log(var1)
#
类型转换a == 1 && a == 2 && a == 3
#
var a = { _default: 0, // == 发生隐式转换 使其转为字符串 toString: function () { return ++this._default },}
if (a == 1 && a == 2 && a == 3) { console.log('winner')}
那如何使其在===
的情况下也成立呢
// getter -> 访问一个变量的时候进行拦截var _default = 0Object.defineProperty(window, 'a', { get() { return ++_default },})
if (a === 1 && a === 2 && a === 3) { console.log('winner')}
{} []
#
隐式转换 let len1 = ({} + {}).length // 类型转换 toString// ({}).toString() // => [object object]// '[object object][object object]'.length // => 30
let len2 = ([] + []).length // 类型转换 toString// [].toString() // => '' // 0
let len3 = function () {}.length // 形参个数 0
console.log(!!' ' + !!'' + !!false)// true + false + false => 1
window.a || (window.a = '1')console.log(window.a)// 1//()优先级高于 || 先赋值 这样前面的window.a就是真 直接返回了
[10, 20, 30].map(parseInt)
#
map
的参数和返回值parseInt
参数和返回值
[10, 20, 30].map(parseInt)// [ 10, NaN, NaN ]
;[10, 20, 30].map((item, index) => { return parseInt(item, index) // parseInt(10, 0) parseInt(20, 1) parseInt(30, 2)})
#
Thisconst User = { count: 1, getCount: function () { return this.count },}console.log(User.getCount()) // 1 this-->userconst func = User.getCountconsole.log(func()) // undefined
// 函数里面的this在执行的时候才知道指向谁 call apply bind指向绑定的对象console.log(func.call(User)) // 1
function foo() { console.log(a)}function bar() { var a = 3 console.log(this.a + a) foo()}var a = 2bar() // 5 2 // this指向 winbar.call({ a: 4 }) //7 2
#
Promisenew Promise((resolve) => { console.log(1); setTimeout(resolve, 0, "done"); // fn timer 传递给执行函数的其他参数}).then(console.log); // -> 这个的存在done才输出的
console.log("start"); // 1 start done
setTimeout(function () { console.log(1)}, 1000)
new Promise((resolve, reject) => { console.log(2) resolve()}).then(console.log(3))
console.log(4) // 2 3 4 1
setTimeout(function () { console.log(1)}, 0)new Promise(function executor(resolve) { console.log(2) for (var i = 0; i < 10000; i++) { i == 9999 && resolve() } console.log(3)}).then(function () { console.log(4)})console.log(5) // 2 3 5 4 1
var p = new Promise().then(f1,f2).then(f3,f4)
var p = new Promise((resolve, reject) => { reject(1);}).then(()=>{ console.log(1); return true},()=>{ console.log(2); // 2 //reject(1); return false;}).then((x)=>{ console.log(x) // false},()=>{ console.log(4)}) // 2 false
var p = new Promise((resolve, reject) => { reject(1);}).then(()=>{ console.log(1); return true},()=>{ console.log(2); // 2 reject(1); return false;}).then((x)=>{ console.log(x)},()=>{ console.log("reject成功调用") // reject成功调用})
setTimeout(function () { Promise.resolve().then(function () { console.log(8) }) console.log(2)}, 0)
setTimeout(function () { console.log(3)})
Promise.resolve() .then(function () { console.log(4) setTimeout(function () { console.log(7) }) }) .then(function () { console.log(5) })
console.log(6)
// 6 4 5 2 8 3 7// 同步 不用说 setTimeout 加入 宏任务队列 promise 微任务 6// 微任务输出4 同时将setTimeout 加入 宏任务队列 继续执行微任务 输出5 4 5 此时微任务空 宏任务3个// 执行第一个宏任务 2 8// 执行第二个宏任务 3// 执行第三个宏任务 7
#
日期格式化function formatDate(t, str) { var obj = { y: "", m: "", d: "", }; return str.replace(/([a-z]+)/gi, function ($1) { return obj[$1]; });}console.log(formatDate(new Date(1409894060000), "yyyy-MM-dd HH:mm:ss 星期w"));
node.contains( otherNode )
该Node.contains()方法返回一个Boolean值,该 值指示节点是否为给定节点的后代,即节点本身,其直接子代(childNodes)之一,子代的直接子代之一,等等。
// 查找两个节点的最近的一个共同父节点,可以包括节点自身// oNode1 和 oNode2 在同一文档中,且不会为相同的节点function commonParentNode(oNode1, oNode2) { return oNode1.contains(oNode2) ? oNode1 : commonParentNode(oNode1.parentNode, oNode2);}
function namespace(oNamespace, sPackage) { sPackage.split(".");}// 根据包名,在指定空间中创建对象console.log(namespace({ a: { test: 1, b: 2 } }, "a.b.c.d"));// {a: {test: 1, b: {c: {d: {}}}}}
// 而包名字符串是简单顺序的,所以可以直接 split 出来遍历,利用引用赋值的特性逐级跟进到包里面(可以把遍历用的 ns 想象成指针):function isPlainObject(value) { return Object.prototype.toString.call(value).slice(8, -1) == "Object";} // 判断对象
function namespace(oNamespace, sPackage) { var scope = sPackage.split("."); // ['a', 'b', 'c', 'd'] var ns = oNamespace; for (var i = 0; i < scope.length; ++i) { // 如果 scope[i]不是自身属性 或者 ns[scope[i]] 不是对象 if (!ns.hasOwnProperty(scope[i]) || !isPlainObject(ns[scope[i]])) { ns[scope[i]] = {}; } ns = ns[scope[i]]; } return oNamespace;}console.log(namespace({ a: { test: 1, b: 2 } }, "a.b.c.d"));// {a: {test: 1, b: {c: {d: {}}}}}
// ns// { a: { test: 1, b: 2 } }// a => { test: 1, b: 2 }// b => {}// c => {}// d => {}
// oNamespace// { a: { test: 1, b: 2 } }// a => { a: { test: 1, b: 2 } }// b => { a: { test: 1, b: { } } }// c => { a: { test: 1, b: { c: { } } } }// d => { a: { test: 1, b: { c: { d: { } } } } }
// 递归function namespace(oNamespace, sPackage) { var pointer = oNamespace; function fn(oNamespace, sPackage) { var list = sPackage.split("."); if (list[0] === "") { return; } if (oNamespace[list[0]] instanceof Object) { namespace(oNamespace[list[0]], list.slice(1).join(".")); } else { oNamespace[list[0]] = {}; namespace(oNamespace[list[0]], list.slice(1).join(".")); } } fn(oNamespace, sPackage); return pointer;}console.log(namespace({ a: { test: 1, b: 2 } }, "a.b.c.d"));
#
字符串操作- 语句分割
ss= s.split(" ");
以空格形式分割 返回新数组
return str.split(/\W/) //和正则一起使用
- 通过比较前后出现次数 来确定只出现过一次
arr.indexOf(elem) != arr.lastIndexOf(elem)
字符串反转
return str.split("").reverse().join("");
单词的首字母大写
arr[i] = arr[i].slice(0, 1).toUpperCase() + arr[i].slice(1); arr[i] = arr[i].charAt(0).toUpperCase() + arr[i].substr(1)
对多个空格的处理
urlSlug(" Winter Is Coming")应返回"winter-is-coming"。// 全局变量var globalTitle = "Winter Is Coming";
function urlSlug(title) { return title.split(/\W/) .filter(obj => { return obj !== ""; }).join('-').toLowerCase();}var winterComing = urlSlug(globalTitle); // 应为 "winter-is-coming"
const htmlEntities = { '&': '&', '<': '<',}// Using a regex, replace characters with it's corresponding html entityreturn str.replace(/([&<>"'])/g, (match) => htmlEntities[match])
#
数组操作不改变原始数组情况下
- 将两个数组合并并返回
arr1.concat(arr2)
const arr = [1, 2][].push.apply(arr, [3, 4]) // 4console.log(arr) // [1, 2, 3, 4]
- 向数组末尾添加元素
function append(arr, item) { return [...arr,item] // return arr.concat(item)}
- 将数组末尾元素删除
// return arr.slice(0, arr.length-1)return arr.slice(0, -1)
- 获取数组中最大的一项
Math.max.apply(null, arr);sort()
fn.apply(null, [].slice.call(arguments, 1))fn(...[].slice.call(arguments, 1))
在正则表达式中,利用()进行分组,使用斜杠加数字表示引用,\1就是引用第一个分组,\2就是引用第二个分组。将[a-zA-Z]做为一个分组,然后引用,就可以判断是否有连续重复的字母。
function containsRepeatingLetter(str) { console.log(str.match(/([a-zA-Z])\1/)); // [ 'll', 'l', index: 4, input: 'l311ll3t', groups: undefined ] return /([a-zA-Z])\1/.test(str);}
function containsRepeatingLetter(str) { for (let i = 0; i < str.length; i++) { if ( str[i] === str[i + 1] && str[i].charCodeAt(0) >= 65 && str[i].charCodeAt(0) <= 122 ) { return true; } } return false;}
#
判断字符串以字母开头,后面字母数字下划线,长度6-30const reg = /^[a-zA-Z]\w{5,29}$/
// ^[a-zA-Z] 匹配字母开头// \w{5,29}$ 匹配后面的5-29的字母数字或下划线 结尾
trim
方法,保证浏览器兼容性#
手写字符串String.prototype.trim = function () { return this.replace(/^\s+/, '').replace(/\s+$/, '')}// 原型 this 正则
#
字符转Base64-最优解(window.btoa,window.atob)
let encodedData = window.btoa("this is a example");console.log(encodedData); // dGhpcyBpcyBhIGV4YW1wbGU=
let decodeData = window.atob(encodedData);console.log(decodeData); // this is a example
#
[第 143 题:将'10000000000'形式的字符串,以每3位进行分隔展示'10.000.000.000',多种实现方式 #296]#
常规const splitStr = (str, point = 3, split = '.') => { let newStr = ''; const reverseStr = str.split('').reverse().join(''); for (const s in reverseStr) { newStr = (s !== '0' && s % point === 0) ? newStr + split + reverseStr[s] : newStr + reverseStr[s]; } return newStr.split('').reverse().join('');}
#
奇淫巧技// 德国以 . 分割金钱, 转到德国当地格式化方案即可10000000000..toLocaleString('de-DE')
// 寻找字符空隙加 .'10000000000'.replace(/\B(?=(\d{3})+(?!\d))/g, '.')
// 寻找数字并在其后面加 . '10000000000'.replace(/(\d)(?=(\d{3})+\b)/g, '$1.')
三个分割var f = '1232418318741';console.log(f.replace(/\d{1,3}(?=(\d{3})+$)/g, '$&,'));
const splitStr = (str) => { let res = ''; const reverseStr = str.split('').reverse().join(''); for (let i = 0; i < reverseStr.length; i++) { if (i % 3 === 2) { res += reverseStr[i] + ','; } else { res += reverseStr[i]; } } return res.split('').reverse().join('');};console.log(splitStr(f));
<a>
标签点击的时候弹出来对应的序号#
创建10个// let i, alet afor (let i = 0; i < 10; i++) { // 使得i变成块级作用域 a = document.createElement('a') a.innerHTML = i + '<br>' a.addEventListener('click', function (e) { e.preventDefault() alert(i) // i也是 一个自由变量要去父作用域获取 }) // click执行的时候 for遍历早已完成 i=10 i是全局作用域 ==> 使得i变成块级作用域 document.body.appendChild(a)}
块级作用域 立即执行函数
// FEAT: 生成随机字符串
const randomString = (n) => { const str = 'abcdefghijklmnopgrstuvwxyz9876543210'; const len = str.length; let res = ''; for (let i = 0; i < n; i++) { res += str.charAt(Math.floor(Math.random() * len)); } return res;};
console.log(randomString(5));