Open FrankKai opened 4 years ago
举个例子: [1,2,3]我只想打印第一项的1。
// 这种写法报错
[1,2,3].forEach((item)=>{
if(item===2) break ;
console.log(item);
})
=> SyntaxError: Illegal break statement
[1,2,3].forEach((item)=>{
if(item===2) return ;
console.log(item);
})
=> 1 3 (这个三其实你并不是想打印出来)
上面这种写法常用与函数中的return。
function test() {
[1,2,3].forEach((item)=>{
if(item===2) return;
console.log(item);
})
}
=> 1 3(这个三其实你并不是想打印出来)
const arr = [1,2,3];
for(let i = 0;i<arr.length;i++){
if(arr[i]===2) break ;
console.log(arr[i]);
}
=> 1
const arr = [1,2,3];
for(let i = 0;i<arr.length;i++){
if(arr[i]===2) return ;
console.log(arr[i]);
}
=> SyntaxError: Illegal return statement
function test() {
const arr = [1,2,3];
for(let i = 0;i<arr.length;i++){
if(arr[i]===2) return;
console.log(arr[i]); // 1
}
}
let arr = [1,2,3];
for(let i of arr){
if(i===2) break ;
console.log(i); // 1
}
=> 1
[1,2,3].forEach((item)=>{
if(item===2) return ;
console.log(item);
})
=> 1, 3 等价于:
const arr = [1,2,3];
for(let i = 0;i<arr.length;i++){
if(arr[i]===2) continue;
console.log(arr[i]);
}
=> 1, 3
let protocols = [["http","https"], ['mqtts', 'tcp'],['ws', 'wss', 'https']]
let mqttProtocols = ['mqtt', 'mqtts', 'tcp', 'tls', 'ws', 'wss', 'wxs' , 'alis']
const validProtocols = protocols.filter((item)=>item.some((e)=>mqttProtocols.includes(e)))
JSON.stringify(validProtocols) // "[[\"mqtts\",\"tcp\"],[\"ws\",\"wss\",\"https\"]]"
const heart = [" ***** *****"," ******* *******", "******************", " **************", " **********", " ****"]
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function heart(){
let arr = [" ***** *****"," ******* *******", "******************", " **************", " **********", " ****"];
for(const item of arr){
console.log(`%c ${item}`, 'color: red');
await sleep(1000);
}
}
await heart();
console.log(~~ 6.45) // 6
console.log(6.45 >> 0) // 6
console.log(6.45 << 0) // 6
console.log(6.45 | 0) // 6
// >>>不可对负数取整
console.log(6.45 >>> 0) // 6
parseInt(6.45) // 6
parseInt(6.54) // 6
UI经常会给一个十六进制色,后面跟一个透明度。 而我们如果想调透明度是需要用rgba(x,y,z,a)的,其实这个a我们知道,但是x,y,z我们是不知道的。 下面这个方法可以很好实现转换。
function hexColorToRGB(hexColor, alpha){
let hexData = hexColor.split("");
if (hexData.length === 4) {
hexData = hexData.reduce((acc, cur) =>
cur === "#" ? [...acc, cur] : [...acc, cur, cur]
);
}
const rgbData = [];
let i = 1;
while(i < hexData.length){
const num = parseInt(`0x${hexData[i]}${hexData[i + 1]}`)
rgbData.push(num)
i = i + 2
}
if(alpha){
return `rgba(${rgbData[0]}, ${rgbData[1]}, ${rgbData[2]}, ${alpha})`
}
return `rgb(${rgbData[0]}, ${rgbData[1]}, ${rgbData[2]})`
}
hexColorToRGB("#0288D1")
hexColorToRGB("#ffffff", 0.16)
let promise = () => {
return new Promise((resolve, reject) => {
if (Math.random() > 0.5) {
resolve("foo");
} else {
reject("bar");
}
});
};
async function test() {
let a = await promise().catch((e) => console.log("catch", e));
console.log(a);
}
1.如果没有做catch处理,console.log("hello world")会执行到吗? 会的。
await promise()
console.log("hello world") // 打印出hello world
2.reject后面的代码console.log("baz")会执行吗? 会的。
let promise = () => {
return new Promise((resolve, reject) => {
reject("bar");
console.log("baz")
});
};
await promise()
let key = '';
let obj = {
[key? 'foo': 'bar']: 'value'
}
obj {bar: 'value'}
let key = '';
let obj = {
[key || 'bar']: 'value'
}
obj {bar: 'value'}
React中的浅比较是基于Object.is实现的。 那么Object与==、===有什么不同呢?
==在比较两边的值之前,会先进行强制转换。而Oject.is不会
===会将-0和+0当做相等的,将Number.NaN和NaN当做不相等的。而Oject会将其看做相当的
function shallowEqual(objA, objB) {
if (Object.is(objA, objB)) {
return true;
}
if (objA === null || typeof objA !== 'object' || objB === null || typeof objB !== 'object') {
return false
}
const keysA = Object.keys(objA)
const keysB = Object.keys(objB)
if (keysA.length !== keysB.length) {
return false
}
for (let i = 0; i < keysA.length; i++) {
if (!Object.prototype.hasOwnProperty.call(objB, keysA[i]) || !Object.is(objA[keysA[i]], objB[keysA[i]])) {
return false
}
}
return true;
}
若对象属性值的引用相同,则不再深入比较,认为其是相等的。 提升虚拟dom Diff算法性能。
let shared = {c: 1}
let obj = {
a: 1,
b: shared
}
let obj1 = {
a: 1,
b: shared
}
console.log(shallowEqual(obj, obj1)) // true
let obj2 = {
a: 1,
b: {c: 1}
}
let obj3 = {
a: 1,
b: {c: 1}
}
console.log(shallowEqual(obj2, obj3)) // false
不是。 ===比较2个对象的引用。 浅比较比较对象的属性值的引用。 例如下面的例子:===为false,浅比较为true。
let shared = {c: 1}
let obj = {
a: 1,
b: shared
}
let obj1 = {
a: 1,
b: shared
}
obj === obj1 // false
shallowEqual(obj1, obj1) // true
核心是引用和全部。 浅:引用。 深:all。
浅比较:引用比较 浅复制:复制引用 深比较:对象的所有属性值全都要比较一遍 深复制:对象的所有属性值全都是新的
浅:性能好 深:状态独立
// proxy watch
let onWatch = (obj, setBind, getLogger) => {
let handler = {
get(target, property, receiver) {
getLogger(target, property)
return Reflect.get(target, property, receiver);
},
set(target, property, value, receiver) {
console.log('set', value);
setBind(value);
return Reflect.set(target, property, value);
}
};
return new Proxy(obj, handler);
};
let obj = { a: 1 }
let value
let p = onWatch(obj, (v) => {
value = v
}, (target, property) => {
console.log(`Get '${property}' = ${target[property]}`);
})
// p.a = 2 // bind `value` to `2`
// p.a // -> Get 'a' = 2
let arr = [1,2,3]
let parr = []
let p1 = onWatch(arr, (v) => {
parr.push(v)
}, (target, property) => {
console.log(`Get '${property}' = ${target[property]}`);
})
// p1.push(1)
p1[0] = 9
p1
var set1 = ";,/?:@&=+$#"; // Reserved Characters
var set2 = "-_.!~*'()"; // Unreserved Marks
var set3 = "ABC abc 123"; // Alphanumeric Characters + Space
console.log(encodeURI(set1)); // ;,/?:@&=+$#
console.log(encodeURI(set2)); // -_.!~*'()
console.log(encodeURI(set3)); // ABC%20abc%20123 (the space gets encoded as %20)
console.log(encodeURIComponent(set1)); // %3B%2C%2F%3F%3A%40%26%3D%2B%24%23
console.log(encodeURIComponent(set2)); // -_.!~*'()
console.log(encodeURIComponent(set3)); // ABC%20abc%20123 (the space gets encoded as %20)
对于XMR方式的HTTP请求 GET,POST来说,encodeURI不会转码;,/?:@&=+$#字符,会把它们当做特殊字符。但是encodeURIComponent会转码,比如在输入邮箱的场景中,可能需要encodeURIComponent去对邮箱做转码,同时也需要服务端做响应的解码。
bind函数运行后,会生成一个新的函数。新函数内部的this,会指向为bind的第一个参数。
const module = {
x: 42,
getX: function() {
return this.x;
}
};
const unboundGetX = module.getX;
console.log(unboundGetX()); // The function gets invoked at the global scope
// expected output: undefined
const boundGetX = unboundGetX.bind(module);
console.log(boundGetX());
// expected output: 42
这个例子中,bind的第一个参数为module,因此调用module.getX.bind(module)时,getX函数内部的this才能指向module,否则module.getX(), this指向的是window。
koa框架的中间件实现原理,也运用到了bind函数:用于返回一个全新的dispatch函数并且入参i要初始化为i+1。
function compose (middleware) {
return function (context, next) {
return dispatch(0)
function dispatch (i) {
let fn = middleware[i]
if (!fn) return Promise.resolve()
return Promise.resolve(fn(context, dispatch.bind(null, i + 1)))
}
}
}
https://github.com/koajs/compose/blob/3ff7778e8d5c6dbc156a510b09df91aa2a7dded4/index.js#L42
还有一种情况:需要将 传入参数后的函数,作为prop传递 的情况。
例如
Foo({
callback: main.bind(null, ({ isRender: true })) // bind返回一个将{ isRender: true }数据传递了下去的新函数。
});
interface IFoo {
callback?: () => void;
}
function main(props?: { isRender?: boolean }) { ... }
A copy of the given function with the specified this value, and initial arguments (if provided). Calling the bound function generally results in the execution of its wrapped function.
let foo = (a, b) => {
console.log("a", a)
console.log("b", b)
}
let bindFoo = foo.bind(null, 1) // 注意,这返回的bindFoo,是一个只能接收1个参数,也就是b的函数
bindFoo(2)
// a 1 b 2
let foo = (a, b, c) => {
console.log("a", a)
console.log("b", b)
console.log("c", c)
}
let bindFoo = foo.bind(null, 1)
bindFoo(2, 3)
// a 1 b 2 c3
可以用来生成将后几个参数设为默认值的新函数
let foo = (a, b, c) => {
console.log("a", a);
console.log("b", b);
console.log("c", c);
}
let bindFoo = (input) => foo.bind(null, input, 1, 2);
bindFoo(42)(); // 假设 42 是你想绑定到 'a' 的值
let nestedProp = obj.first?.second;
=>
let temp = obj.first;
let nestedProp = ((temp === null || temp === undefined) ? undefined : temp.second);
let target = data?.map((item) => item?.name);
=>
let temp = data;
let target = (temp === null || temp === undefined)? undefined: temp.map((item) => item?.name)
let data = [{name: 'foo'}, {name: 'bar'}];
data?.map((item) => item?.name)
=>
let data = [{name: 'foo'}, {name: 'bar'}];
function optionalChain(src, operation) {
let temp = src;
if(temp === null || temp === undefined){
return undefined;
}
return eval(`${JSON.stringify(temp)}${operation}`);
}
optionalChain(data, '.map((item) => item?.name)');
<!DOCTYPE html>
<html lang="en">
<body>
<div id="parent">
parent
<div id="child">child</div>
</div>
</body>
<script>
// target是事件发生对象
// currentTarget是事件监听对象
const parent = document.getElementById("parent");
// 为parent绑定事件
// 点击child target是child, currentTarget是parent(这是因为事件冒泡)
// 点击parent target和currentTarget都是parent
parent.onclick = (e) => {
console.log(e.target);
console.log(e.currentTarget);
};
</script>
</html>
let p 1= new Promise((resolve)=>{
setTimeout(()=>{console.log(1);resolve()}, 1000)
})
let p2 = new Promise((resolve)=>{
setTimeout(()=>{console.log(2);resolve()}, 2000)
})
let p3 = new Promise((resolve)=>{
setTimeout(()=>{console.log(3);resolve()}, 3000)
})
let p4 = new Promise((resolve)=>{
setTimeout(()=>{console.log(4);resolve()}, 1000)
})
await Promise.race([Promise.all([p1, p2]), Promise.all([p3, p4])])
console.log(5);
// 1,4,2,5,3
JSON.stringify()后的结果,比console.log的内容少。
console.log 的时候 targetNode 还没有被添加到 edge 上。 因为 JOSN.stringify()打印的是对象的快照而不是引用,所以 JOSN.stringify()时没有打印出结果。 但是因为 console.log 打印的是引用,所以也会打印出 TargetNode 。
可以用 Proxy 劫持下 edge ,当 targetNode 被添加时,打印对象。
把下面例子里的 targetObject 换成 edge 试下。
const targetObject = {};
const proxy = new Proxy(targetObject, {
defineProperty(target, property, descriptor) {
console.log(`试图向属性 ${property} 添加值`);
// 允许正常添加名为 "targetNode" 的属性
const result = Reflect.defineProperty(target, property, descriptor);
// 打印被劫持对象的值和修改后的对象
console.log('被劫持对象的值:', targetObject);
console.log('修改后的对象:', proxy);
return result;
},
});
// 通过代理添加属性
proxy.targetNode = "some value"; // 试图向属性 targetNode 添加值
// 输出: 被劫持对象的值: { targetNode: 'some value' }
// 输出: 修改后的对象: { targetNode: 'some value' }
通过history.pushState清除url的query,通过location获取最新的url信息。
这要比通过window.location.href来清除url的query好的多,不会引起页面的刷新。另外说一句,更改window.location.pathname也会引起页面的刷新。
// 当前页面是http://yourdomain.com/page
var newUrl = '/newpage'; // 只能使用相对路径或与当前源相同的绝对路径
window.history.pushState({}, '', newUrl);
// 访问更新后的location对象
console.log(location.href); // http://yourdomain.com/newpage
console.log(location.pathname); // /newpage
console.log(location.hostname); // yourdomain.com
console.log(location.protocol); // http: