首页
统计
Search
1
TypeScript学习笔记
5 阅读
2
《被讨厌的勇气》读后感
5 阅读
3
从零开始的Vue学习
3 阅读
4
摘抄
3 阅读
5
【极客时间】玩转Git三剑客笔记
3 阅读
年度总结
学习笔记
读后感
动漫汇总
日常记录
登录
Search
标签搜索
大数据
git
加密
Vue
CTF
TypeScript
React
Augenstern
累计撰写
10
篇文章
累计收到
0
条评论
首页
栏目
年度总结
学习笔记
读后感
动漫汇总
日常记录
页面
统计
搜索到
10
篇与
Augenstern
的结果
2025-12-23
记一次服务器迁移
起因起初手头上有一台阿里云99元/年的云服务器,,但使用起来非常卡顿,经常宕机,让人难以忍受。正好在论坛内,看到有服务器代理商的双十一优惠,一眼看中了2C2G 新加坡 30M带宽 1T/月 有国内线路优化的服务器,于是一次性购买了三年。一开始使用体验不错,域名不需要备案可以直接解析,docker镜像拉取速度极快,网站访问速度可以接受,但好景不长,一段时间后,国内访问速度极慢,和腾讯云的工单客服battle半天,只说新加坡运营商的线路问题,不确定何时解决,要么改用香港优选流量,要么迁移至国内服务器。思考之后,我决定把服务器的各项应用迁移至国内服务器,虽然使用了docker部署,但是迁移起来还是遇到了一些困难,下面我会记录迁移的各个步骤以便后续再次迁移使用。具体操作一、服务器数据文件备份原服务器防火墙策略从腾讯云管理平台导出防火墙策略,管理端口开放情况docker持久化数据从原服务器上下载各持久化数据,上传到新服务器对应目录,其中包含了Mysql数据库数据1panel已安装应用数据备份下载1panel已安装应用二、防火墙策略开通将之前导出的防火墙策略Excel导入新的服务器管理面板处导入即可。三、应用安装/迁移运维面板 -- 1panel安装直接选择在线安装方式,执行以下命令,按照提示一步一步完成安装。bash -c "$(curl -sSL https://resource.fit2cloud.com/1panel/package/v2/quick_start.sh)"配置安装完成后,需要进行以下的配置证书申请开启面板SSL修改SSH默认端口,且开启仅密钥登录应用利用之前备份文件还原已安装应用/opt/1panel/apps/openrestyuptime-kuma个人博客 -- Typechodocker run -d --name=typecho-blog -p 2234:80 -v /data/docker_typecho_data:/data -e PHP_TZ=Asia/Shanghai --restart=always 80x86/typecho:latest个人云盘 -- Cloudrevedocker run -d --name cloudreve -p 5212:5212 -p 6888:6888 -p 6888:6888/udp -v /data/docker_cloudreve_data:/cloudreve/data cloudreve/cloudreve:latest数据库 -- Mysql8.0docker run -it --name=mysql8.0 -p 5555:3306 -e MYSQL_ROOT_PASSWORD=xxxxxx -e TZ=Asia/Shanghai -v /data/docker_mysql_data:/var/lib/mysql -d --restart=always mysql:8.0导航页 -- Sun-Paneldocker run -d --restart=always -p 3002:3002 -v /data/docker_sun-panel_data/conf:/app/conf -v /var/run/docker.sock:/var/run/docker.sock --name sun-panel hslr/sun-panel:latest四、OpenResty代理应用类型panel反向代理blog反向代理cloud反向代理nav反向代理www静态网站status一键部署五、EdgeOne加速1、准备一个已备案域名2、将域名纳入EO管理3、添加子域名,并在DNS添加EO解析4、申请Https证书
2025年12月23日
1 阅读
0 评论
0 点赞
2025-12-03
React Hook学习
参考链接: React 内置 HookHook简单介绍 定义: 以use开头的函数 作用: Hook有助于在组件中使用不同的React功能 使用: Hook比普通函数更为严格,只能在的组件(或其他 Hook)的 顶层 调用Hook 分类:State HookContext HookRef HookEffect Hook性能 Hook其他 Hook自定义 HookState Hook状态帮助组件,用于“记住”用户的输入信息useState :声明可以直接更新的状态变量示例:function MyButton(){ const [count,setCount] = useState(0); function handleClick(){ setCount(count+1); } return( <button onClick={handleClick}> Clicked {count} times </button> ) }useReducer:在reducer函数中声明带有更新逻辑的state变量reducer函数 :将组件的所有状态更新逻辑整合到一个外部函数中,这个函数叫做reduceruseReducer钩子接受参数:一个reducer函数一个初始的state返回内容:一个有状态的值一个dispatch函数(派发用户操作给reducer)示例: {tabs}{tabs-pane label="App.js"}import { useReducer } from 'react'; import AddTask from './AddTask.js'; import TaskList from './TaskList.js'; import tasksReducer from './tasksReducer.js'; export default funtion TaskApp(){ const [tasks, dispatch] = useReducer(tasksReducer, initialTasks); function handleAddTask(text){ dispatch({ type:'added', id:nextId++, text:text, }); } function handleChangeTask(task){ dispatch({ type:'changed', task:task }); } function handleDeleteTask(taskId){ dispatch({ type:'deleted', id:taskId, }); } return ( <> <h1>布拉格的行程安排</h1> <AddTask onAddTask={handleAddTask} /> <TaskList tasks={tasks} onChangeTask={handleChangeTask} onDeleteTask={handleDeleteTask} /> </> ); }{/tabs-pane}{tabs-pane label="tasksReducer.js"}export default function tasksReducer(tasks, action) { switch (action.type) { case 'added': { return [ ...tasks, { id: action.id, text: action.text, done: false, }, ]; } case 'changed': { return tasks.map((t) => { if (t.id === action.task.id) { return action.task; } else { return t; } }); } case 'deleted': { return tasks.filter((t) => t.id !== action.id); } default: { throw Error('未知 action:' + action.type); } } } {/tabs-pane}{/tabs}Context Hook上下文帮助组件 从祖先组件接收信息,而无需将其作为 props 传递useContext 读取订阅上下文示例:import { createContext, useContext } from 'react'; const ThemeContext = createContext(null); export default function MyApp(){ return ( <ThemeContext.Provider value="dark"> <Form/> <ThemeContext.Provider> ); } function Form(){ return ( <Panel title="Welcome"> <Button>Sign up </Button> <Button>Log in </Button> </Panel> ); } function Panel({title,children}){ const theme = useContext(ThemeContext); const className = 'panel-' + theme; return( <section className = {className}}> <h1>{title}</h1> {children} </section> ); } funciton Button({children}){ const theme = useContext(ThemeContext); const className = 'button-' + theme; return( <button className={className}> {children} </button> ); }注意:通常情况下,useContext()只会调用上层provider,当然通过合并的方式可以实现嵌套调用Ref Hookref 允许组件 保存一些不用于渲染的信息,比如 DOM 节点或 timeout ID。与状态不同,更新 ref 不会重新渲染组件。useRef 声明ref,可以保存任何值,但常用于保存DOM节点示例:import { useRef } from 'react'; export default function Counter() { let ref = useRef(0); function handleClick() { ref.current = ref.current + 1; alert('You clicked ' + ref.current + ' times!'); } return ( <button onClick={handleClick}> 点击!{ref.current} </button> ); } 与useState不同的是,ref不会触发重新渲染,所以JSX中显示{ref.current}不会变化useImperativeHandle 自定义从组件中暴露ref,不常用Effect HookEffect 允许组件 连接到外部系统并与之同步。这包括处理网络、浏览器、DOM、动画、使用不同 UI 库编写的小部件以及其他非 React 代码useEffect 将组件连接到外部系统外部系统 :有些组件需要与网络、某些浏览器 API 或第三方库保持连接,当它们显示在页面上时。这些系统不受 React 控制,所以称为外部系统示例:import {useState,useEffect} from 'react'; import {createConnection} from './chat.js'; function ChatRoom({roomId}){ const [serverUrl,setServerUrl] = useState('https://localhost:1234'); useEffect(()=>{ const connection = createConnection(serverUrl,roomId); connection.connect(); return ()=>{ connection.disconnection(); }; },[serverUrl,roomId]); // ... }需要向 useEffect 传递两个参数:一个 setup 函数 ,其 setup 代码 用来连接到该系统。它应该返回一个 清理函数(cleanup),其 cleanup 代码 用来与该系统断开连接。一个 依赖项列表,包括这些函数使用的每个组件内的值性能 Hook使用性能hook可以跳过计算和不必要的重新渲染来优化性能useMemo 缓存计算代价昂贵的计算结果useMemo(calculateValue, dependencies) calculateValue:要缓存计算值的函数 dependencies:所有在 calculateValue 函数中使用的响应式变量组成的数组示例: {tabs}{tabs-pane label="App.js"}import { useState } from 'react'; import { createTodos } from './utils.js'; import TodoList from './TodoList.js'; const todos = createTodos(); export default funtion App(){ const [tab,setTab] = useState('all'); const [isDark,setIsDark] = useState(false); return( <> <button onClick={()=>setTab('all')}>All</button> <button onClick={()=>setTab('active')}>Active</button> <button onClick={()=>setTab('completed')}>Completed</button> <br/> <label> <input type="checkbox" checked={isDark} onChange={e=>setIsDark(e.target.checked)}> Dark mode </input> </label> <hr/> <TodoList todos={todos} tab={tab} theme={isDark?'dark':'light'}/> </> ); } {/tabs-pane}{tabs-pane label="TodoList.js"}import { useMemo } from 'react'; import { filterTodos } from './utils.js' export default function TodoList({ todos, theme, tab }) { const visibleTodos = useMemo( () => filterTodos(todos, tab), [todos, tab] ); return ( <div className={theme}> <p><b>Note: <code>filterTodos</code> is artificially slowed down!</b></p> <ul> {visibleTodos.map(todo => ( <li key={todo.id}> {todo.completed ? <s>{todo.text}</s> : todo.text } </li> ))} </ul> </div> ); } {/tabs-pane}{tabs-pane label="utils.js"}export function createTodos() { const todos = []; for (let i = 0; i < 50; i++) { todos.push({ id: i, text: "Todo " + (i + 1), completed: Math.random() > 0.5 }); } return todos; } export function filterTodos(todos, tab) { console.log('[ARTIFICIALLY SLOW] Filtering ' + todos.length + ' todos for "' + tab + '" tab.'); let startTime = performance.now(); while (performance.now() - startTime < 500) { // 在 500 毫秒内不执行任何操作以模拟极慢的代码 } return todos.filter(todo => { if (tab === 'all') { return true; } else if (tab === 'active') { return !todo.completed; } else if (tab === 'completed') { return todo.completed; } }); } {/tabs-pane}{/tabs}useCallback 将函数传递给优化组件之前缓存函数定义const cachedFn = useCallback(fn, dependencies) fn:想要缓存的函数 dependencies:有关是否更新 fn 的所有响应式值的一个列表示例:function ProductPage({ productId, referrer, theme }) { // 在多次渲染中缓存函数 const handleSubmit = useCallback((orderDetails) => { post('/product/' + productId + '/buy', { referrer, orderDetails, }); }, [productId, referrer]); // 只要这些依赖没有改变 return ( <div className={theme}> {/* ShippingForm 就会收到同样的 props 并且跳过重新渲染 */} <ShippingForm onSubmit={handleSubmit} /> </div> ); }useMemo与useCallback联系useMemo 经常与 useCallback 一同出现,区别在于useMemo 缓存函数调用的结果 useCallback 缓存函数本身// 在 React 内部的简化实现 function useCallback(fn, dependencies) { return useMemo(() => fn, dependencies); }示例:import { useMemo, useCallback } from 'react'; function ProductPage({ productId, referrer }) { const product = useData('/product/' + productId); const requirements = useMemo(() => { //调用函数并缓存结果 return computeRequirements(product); }, [product]); const handleSubmit = useCallback((orderDetails) => { // 缓存函数本身 post('/product/' + productId + '/buy', { referrer, orderDetails, }); }, [productId, referrer]); return ( <div className={theme}> <ShippingForm requirements={requirements} onSubmit={handleSubmit} /> </div> ); }其他 Hook使用 useDebugValue 自定义 React 开发者工具为自定义 Hook 添加的标签。使用 useId 将唯一的 ID 与组件相关联,其通常与可访问性 API 一起使用。使用 useSyncExternalStore 订阅外部 store。使用 useActionState 允许你管理动作的状态.自定义Hook自定义hook
2025年12月03日
1 阅读
0 评论
0 点赞
2025-10-24
摘抄
{card-default label="刘震云" width=""}这个世界我们只来一次,百年之后,没你也没我 我们拼搏一生,带不走一砖一瓦 我们执着一生,带不走一丝爱恨情仇,人生苦短 所以吃你想吃的饭,见你想见的人,看你喜欢的风景,做你喜欢的事 人生本来就是一次减法,来日并不方长 有钱把日子过好,没钱把心情过好,时间扑面而来 我们终将释怀 平静的过,健康的活着 开心地笑,适当地忙碌 就很好 不要去责怪你生命中的任何人,合得来就好好相处,多多关怀,合不来就保持距离,装装糊涂 人在世上总会遇见形形色色的人,好的人给了你快乐 坏的人给了你经历,最差的人给了你教训,最好的人给了你成长 所有的相遇绝非偶然 来者要惜,去者要放 {/card-default}{card-default label="白日梦想家" width=""}认识世界,克服困难。洞悉所有,贴近生活。寻找真爱,感受彼此。这就是生活的意义。{/card-default}
2025年10月24日
3 阅读
0 评论
0 点赞
2025-10-17
TypeScript学习笔记
TypeScript入门笔记教程地址:官方文档:TypeScript 菜鸟教程:TypeScript入门教程简单介绍1、TypeScript由微软公司开发,是一种开源的编程语言2、TypeScript是JavaScript的超集,拓展了JavaScript的语法,因此,TS也是兼容JS代码的,只会对TS代码进行编译安装有两种主要的方式来获取TypeScript工具:通过npm(Node.js包管理器)安装Visual Studio的TypeScript插件这里采用npm的方式进行安装npm install -g typescript查看版本tsc -V 初始化一个项目tsc --init 基础语法数据类型布尔值let isDone: boolean = false;数字let decLiteral: number = 6; //十进制 let hexLiteral: number = 0xf00d; //十六进制 let binaryLiteral: number = 0b1010; //二进制 let octalLiteral: number = 0o744; //八进制字符串let name: string = "bob"; name = "smith";字符串除用"或'表示外,还可以使用模板字符串,可以定义多行文本和内嵌表达式,字符串由反引 号`包围,并且以${ expr }这种形式嵌入表达式let name: string = `Xiaohu`; let age: number = 37; let sentence: string = `Hello, my name is ${name}. I'll be ${age+1} years old next month;` console.log(sentence); //显示结果 Hello, my name is Xiaohu. I'll be 38 years old next month;SymbolSymbol 是 唯一且不可变 的数据类型,通常用作对象属性的键// Symbol 类型注解 const sym1: symbol = Symbol(); const sym2: unique symbol = Symbol("key"); // unique symbol 类型 // 作为对象属性 const obj = { [sym2]: "123" // 使用 unique symbol }; console.log(obj[sym2]); // "123"数组两种定义方式第一种在元素类型后面添加[]let list: number[] = [1, 2, 3];第二种使用数组放心,Array<元素类型>let list: Array<number>元组元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同let x: [string, number]; x = ['hello', 10]; // 正确 x = [10, 'hello']; // 错误当访问一个越界的元素,会使用 联合类型 替代x[3] = 'world'; x[4] = 100; console.log(x[5].toString()); //以上都是可以的, 字符串和数字都属于(string | number)类型,'string' 和 'number' 都有 toString x[6] = true; // Error, 布尔不是(string | number)类型联合类型一个变量是多个数据类型中的某一个,可以使用联合类型, 或 的关系function getArg(param: string | number) { return param.length }交叉类型一个变量是多个数据类型的总和,可以使用交叉类型, 与 的关系interface Person { name: string; age: number; } interface Employee { company: string; employeeId: number; } // BusinessPerson 必须同时拥有 Person 和 Employee 的所有属性 type BusinessPerson = Person & Employee;枚举enum类型是对JavaScript标准数据类型的一个补充,使用枚举类型可以为一组数值赋予友好的名字enum Color {Red,Green,Blue} let c:Color = Color.Green; console.log(c); //显示1默认情况下,从0开始为元素编号,也可以手动的指定成员的数值;枚举类型也可以通过值找到对应名字enum Color {Red=1,Green=2,Blue=4} //Green和Blue 不赋值,则默认从2开始 let colorName:string = Color[4]; console.log(colorName); // 显示BlueAnyAny表示任意类型,但不同在于Object只允许赋值,而不能调用其中的方法,即使对象内部真的有对应的方法let notSure: any = 4; notSure.ifItExists(); // 正常 notSure.toFixed(); // 正常 let prettySure: Object = 4; prettySure.toFixed(); // 报错,提示Object没有对应方法Void表示没有任何类型,比如在函数没有返回值时,返回voidfunction warnUser(): void { console.log("This is my warning message"); }void 只能赋undefined和nulllet unusable: void = undefined;Null 和 UndefinedTypeScript里,undefined和null两者各自有自己的类型分别叫做undefined和null,是所有类型的子类型(默认情况);--strictNullChecks标记,null和undefined只能赋值给void和它们各自Nevernever类型表示的是那些永不存在的值的类型,never类型是任何类型的子类型,也可以赋值给任何类型;然而,没有类型是never的子类型或可以赋值给never类型(除了never本身之外), 即使 any也不可以赋值给never。// 返回never的函数必须存在无法达到的终点 function error(message: string): never { throw new Error(message); } // 推断的返回值类型为never function fail() { return error("Something failed"); } // 返回never的函数必须存在无法达到的终点 function infiniteLoop(): never { while (true) { } }Objectobject表示非原始类型,也就是除number,string,boolean,symbol,null或undefined之外的类型接口TypeScript的核心原则之一是对值所具有的shape进行类型检查。 它有时被称做“鸭式辨型法”或“结构性子类型化”。 在TypeScript里,接口的作用就是为这些类型命名和为你的代码或第三方代码定义契约普通接口interface LabelledValue{ label:string; } function printLabel(labelledObj:LabelledValue){ console.log(labelledObj.label); } let myObj = {size:10,label:"Size 10 Object"}; printLabel(myObj);LabelledValue接口就好比一个名字,用来描述上面例子里的要求。它代表了有一个label属性且类型为string的对象。需要注意的是,我们在这里并不能像在其它语言里一样,说传给printLabel的对象实现了这个接口。我们只会去关注值的外形。 只要传入的对象满足上面提到的必要条件,那么它就是被允许的。还有一点值得提的是,类型检查器不会去检查属性的顺序,只要相应的属性存在并且类型也是对的就可以。可选属性带有可选属性的接口与普通的接口定义差不多,只是在可选属性名字定义的后面加一个?符号,可选属性的好处之一是 可以对可能存在的属性进行预定义 ,好处之二是 可以捕获引用了不存在的属性时的错误interface SquareConfig { color?: string; width?: number; }只读属性一些对象属性只能在对象刚刚创建的时候修改其值,可以在属性名前用readonly来指定只读属性属性用readonly,变量用constinterface Point { readonly x: number; readonly y: number; } }函数类型接口也可以描述函数类型interface SearchFunc{ (source:string,subString:string):boolean; } let mySearch: SearchFunc; mySearch = function(source: string, subString: string) { let result = source.search(subString); if (result == -1) { return false; } else { return true; } } //对于函数类型的类型检查来说,函数的参数名不需要与接口里定义的名字相匹配 mySearch = function(src: string, sub: string): boolean { let result = src.search(sub); if (result == -1) { return false; } else { return true; } }数组类型数组类型具有一个index类型表示索引的类型,还有一个相应的返回值类型表示通过索引得到的元素的类型interface StringArray { [index: number]: string; } let myArray: StringArray; myArray = ["Bob", "Fred"];interface NumberDictionary { [index: string]: number; length: number; // 可以,length是number类型 name: string // 错误,`name`的类型不是索引类型的子类型 }实现接口与Java中的接口一致,TypeScript也能够用它来明确的强制一个类去符合某种契约interface ClockInterface { currentTime: Date; setTime(d: Date); } class Clock implements ClockInterface { currentTime: Date; setTime(d: Date) { this.currentTime = d; } constructor(h: number, m: number) { } }类静态部分与实例部分实例部分 :当你使用 new 创建一个类的实例时,实例上拥有的属性和方法。静态部分 :类本身(构造函数)上拥有的属性和方法。当你用一个接口去约束一个类时(使用 implements 关键字),这个接口 只会检查类的实例部分,而不会检查静态部分 。当你用 构造器签名 (用来描述构造函数类型的一种特殊语法)去定义一个接口并试图定义一个类去实现这个接口时会得到一个错误,因为当一个类实现了一个接口时,只对其实例部分进行类型检查。 constructor存在于类的静态部分,所以不在检查的范围内。interface ClockConstructor { new (hour: number, minute: number); } class Clock implements ClockConstructor { currentTime: Date; constructor(h: number, m: number) { } }因此,我们应该直接操作类的静态部分。 看下面的例子,我们定义了两个接口, ClockConstructor为构造函数所用和ClockInterface为实例方法所用。 为了方便我们定义一个构造函数 createClock,它用传入的类型创建实例。interface ClockConstructor { new (hour: number, minute: number): ClockInterface; } interface ClockInterface { tick(); } function createClock(ctor: ClockConstructor, hour: number, minute: number): ClockInterface { return new ctor(hour, minute); } class DigitalClock implements ClockInterface { constructor(h: number, m: number) { } tick() { console.log("beep beep"); } } class AnalogClock implements ClockInterface { constructor(h: number, m: number) { } tick() { console.log("tick tock"); } } let digital = createClock(DigitalClock, 12, 17); let analog = createClock(AnalogClock, 7, 32);因为createClock的第一个参数是ClockConstructor类型,在createClock(AnalogClock, 7, 32)里,会检查AnalogClock是否符合构造函数签名继承接口接口可以相互继承,也可以继承多个接口,创建出多个接口的合成接口interface Shape { color: string; } interface PenStroke { penWidth: number; } interface Square extends Shape, PenStroke { sideLength: number; } let square = <Square>{}; square.color = "blue"; square.sideLength = 10; square.penWidth = 5.0;接口继承类当接口继承了一个类类型时,它会继承类的成员但不包括其实现。当创建了一个接口继承了一个拥有私有或受保护的成员的类时,这个接口类型只能被这个类或其子类所实现(implement)class Control { private state: any; } interface SelectableControl extends Control { select(): void; } class Button extends Control implements SelectableControl { select() { } } class TextBox extends Control { select() { } } // 错误:“Image”类型缺少“state”属性。 class Image implements SelectableControl { select() { } } class Location { }类与Java中的类很类似,成员有属性、构造方法、方法class Greeter { greeting: string; constructor(message: string) { this.greeting = message; } greet() { return "Hello, " + this.greeting; } } let greeter = new Greeter("world");继承派生类通常被称作子类 ,基类通常被称作 超类class Animal { move(distanceInMeters: number = 0) { console.log(`Animal moved ${distanceInMeters}m.`); } } class Dog extends Animal { bark() { console.log('Woof! Woof!'); } } const dog = new Dog(); dog.bark(); dog.move(10); dog.bark();公共,私有与受保护的修饰符public:默认值,可以自由的访问类中定义的成员private:不能在声明它的类的外部访问;只用两个类中都有相同private成员,且来自同一处声明时,这两个类型才是兼容的,protected成员也一样protected:protected成员在派生类中仍然可以访问其他知识点1、readonly修饰符可以使用readonly关键字将属性设置为只读的。只读属性必须在声明时或构造函数里被初始化2、存取器TypeScript支持通过getters/setters来截取对对象成员的访问3、静态属性创建类的静态成员,这些属性存在于类本身上面而不是类的实例上4、抽象类abstract,抽象类做为其它派生类的基类使用函数普通函数和匿名函数// Named function function add(x, y) { return x + y; } // Anonymous function let myAdd = function(x, y) { return x + y; };this和箭头函数箭头函数能保存函数创建时的 this值,而不是调用时的值let deck = { suits: ["hearts", "spades", "clubs", "diamonds"], cards: Array(52), createCardPicker: function() { // NOTE: the line below is now an arrow function, allowing us to capture 'this' right here return () => { let pickedCard = Math.floor(Math.random() * 52); let pickedSuit = Math.floor(pickedCard / 13); return {suit: this.suits[pickedSuit], card: pickedCard % 13}; } } } let cardPicker = deck.createCardPicker(); let pickedCard = cardPicker(); alert("card: " + pickedCard.card + " of " + pickedCard.suit);泛型使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据Hello World不使用any类型是因为any会导致这个函数可以接收任何类型的arg参数,这样就丢失了一些信息:传入的类型与返回的类型应该是相同的function identity<T>(arg: T): T { return arg; }类型推论 :编译器会根据传入的参数自动地帮助我们确定T的类型let output = identity("myString"); 泛型约束<T extends Lengthwise>:这是泛型约束,表示类型 T 必须满足 Lengthwise 接口的要求interface Lengthwise { length: number; } function loggingIdentity<T extends Lengthwise>(arg: T): T { console.log(arg.length); return arg; }
2025年10月17日
5 阅读
0 评论
0 点赞
2025-06-17
《被讨厌的勇气》读后感
前言这是我第二次读完这本书,记得第一次读应该是23年那会儿,在地铁上,用微信读书看完了电子版。刚接触这本书时对我的冲击还是比较大的,里面的观点有点颠覆常识,但又让人觉得挺有道理的。可随着时间的流逝,很多东西都记不得了。前不久在B站刷到相关视频,就冲动买了一本,花了两周时间看完了(实际书的内容不算多,快的话一天就可以看完)。现趁着刚看完,把自己所接受到的东西写一写,当然这里也不是完全赞同书中内容,会放一些自己的思考。阿德勒心理学书中主要就是通过哲人和青年的对话来阐述阿德勒心理学,其中个人感觉读阿德勒心理学是非常刺痛的,它冷血地把人性进行解剖,将很多的责任或者原因归结到个人本身,而不是外界的条件,避免你下意识地找借口来逃避。勇气一词贯穿全书,人需要被讨厌的勇气,或者说直面这个客观的世界也是需要莫大的勇气。PS:弗洛伊德、荣格、阿德勒被称为心理学三巨头,前两位好像更加出名一点,梦的解析或者MBTI16型人格在互联网上传播更为广泛。“原因论”和“目的论”首先,阿德勒心理学的一个观点就是目的论——你是抱着某种目的让自己这样,书中否定了弗洛伊德的原因论——你现在的样子是由于过去的某一系列原因造成。乍一听,很反直觉。毕竟,这是一个讲逻辑讲因果的世界,人的种种行动都不可避免地受到各种因素的影响,但阿德勒心理学却说人都是抱有目的地让自己这样。不仅如此,人现在遇到的很多事情是痛苦的,但却被书中称为“善”,是对本人有利的。这不是很奇怪吗?但结合自己的经历和真实的内心想法,仔细想想,我确实是这样子的。生活中,我让自己痛苦的行为会让自己很舒服。拿我放弃考研举例子,如果从原因论来解释,可以解释通,我是一个心态不好的人,考研肯定会失败;我的父母年纪大了,读研还要花掉三年的时间,不如直接工作等等。也就是说,我放弃考研,是由多个因素造成的。责任不在于我。但是如果用目的论的角度,结果就比较直接了,我害怕考研的失败,害怕读研的辛苦,出于逃避的目的,所以产生了这一些所谓的原因。同时,当时的逃避,也为自己日后的心理安慰提供了方便,保留了一种可能性。当我咀嚼遗憾的时候,就可以相对轻松地想——只是我因为客观原因没有坚持而已,如果坚持下来也会有一个很不错的结果。目的论的好处相比于原因论,目的论是可以充分发挥人的主观能动性,也就是说排除掉一些客观无法改变的外界条件,人是可以自我改变的,并有极大的改变空间。相反,如果陷入原因论,即A->B,B->C,C->D ......,那么就有了一股决定论的意味,反而让人无法摆脱当前的痛苦,让人拥有了各种各样的推辞。目的论的缺点目的论同样也有危险。就是它过分强调了自身,而忽略了客观的世界。这个很容易让我联想到尼采所说的超人(overman),如果真的可以把所有的现状归结为自己的目的,那这个人的精神力量得多么的强大。事实上,我们需要认清,什么是可以改变的,什么是人无法决定的。盲目地将人置于高点,精神的崩溃是必然。认可欲求放弃对他人的认可欲求,其实就契合了本书的书名——被讨厌的勇气。我觉得自己一直活得很痛苦,因为我一直希望满足所有人的期待,得到周围所有人的认可。在亲戚邻居眼里,我努力优秀,在父母眼中,我孝顺懂事;在领导同事眼中,我认真踏实;但只有在无人的内心角落,才知道我是一个什么样的人,我懒惰、贪玩、会吃外卖,喜欢熬夜,一点也不自律,也会做很多不健康不积极的事情,只是无法坦率地在他人面前展现出来。我像是被众人架在火堆中烘烤,逼迫着展现出好的光泽,但我知道,终有一天,我将无法忍受这持久的炙烤,散发出焦糊的气味来。(多希望有那么一个人接受我的缺点,能让我展现出真实的自我,在一起轻松快乐,我也绝不会辜负她)。课题分离简单来说,课题分离就是做好自己的事情,既不去干涉别人的事,也不希望别人来干涉我。这与哲学上的斯多葛主义有异曲同工之妙,区分我们能控制什么与不能控制什么,来减少精神内耗。痛苦和焦虑主要源于我们试图去控制我们无法控制的事情,或者忽视了我们真正能够控制的东西如我们的内心和思想。理论很容易,但执行起来是非常的困难,就以书中孩子教育来举例,如果孩子贪玩,不好好学习,我相信绝大多数家长无法做到课题分离,即把学习这件事当成孩子自己的事情,而不去干涉。想要通过把马迁到河边,让马自己决定是否喝水,对于大部人人来说也是很难的,需要优秀的沟通能力和表达能力。我只做好我应该做的事情,别人怎么样,我不去管。这会让我们更容易专注在自己的事情上,而排除掉心中的杂念。自卑情结与优越情结自卑和优越并不是一体两面,而是在实际中可以相互转化。优越的人是最自卑的,他无法接受一个不完美的自己,所以内心就开始欺骗,幻想出自己的优越性来;自卑的人也是最优越的,因为他自卑产生的根源就是自大地觉得自己应该完美,或者说在某个方面应该不比某些人差。我自己就是一个自卑(自大)的人,别人收获幸福时,即使是自己的朋友,也难免会产生嫉妒的心理。命运共同体阿德勒心理学也被称为个体心理学,但其并不是想让每个人从世界、社会、公司、家庭中独立出去,变成一个自私、无情的人。但如果简单来想,无论是课题分离,亦或是放弃认可欲求,都不是在说,人要自私,要只想着自己,而不必在乎他人?别人怎么样,我不管(课题分离),别人怎么看我,我不管(放弃认可欲求)。事实上,这种是自私自利之人所理解世界的方式,我们并非完全从社会生活中脱离出去。萨特说“他人即地狱”,阿德勒说“一切烦恼全部来自于人际交往”,可是人作为社会性群居动物,无法与他人彻底分割,总是会产生某种联结。在我看来,阿德勒的心理学在让我们独立的同时,也在呼吁结合,我们希望减少人际上的烦恼和痛苦,但也无法放弃交际。课题分离是对他人的尊重,放弃认可欲求是让自己更积极主动。我们灵活地在自我和社会中切换,一切都是为了自己,一切为了社会,一切为了命运的共同体,这些并不冲突矛盾。活在当下我所接触到的很多哲学观点都在阐述这一个道理,人生的意义在于活在当下,我知道要活在当下,每次难过压抑时,我把手放在胸前,感受心脏砰砰跳动,我就会感慨,此刻的我还活着,还好好地活着。可是,我也只有这一小段时间里是在当下,随后我还是会遗憾或者后悔过去,担心或者幻想未来。我会在大脑中模拟着过去没有发生的事情,模拟着未来可能发生的事情(即使这个事情的可能性非常小),随之痛苦、担忧、恐惧就接踵而至了。但换个角度说,这种处理方式,也符合了之前的目的论,完全自洽,我让自己痛苦了也就让自己轻松了。其他思考工作之后看了不少的哲学视频和哲学书籍,了解到很多的观点来指导人生,但生活还是会迷茫,会困惑,无法按照“正确”的方式来对待遇到的各种事情,也就是很难做到知行合一。有时候,我就会想,是否知道的越多,了解的越多,人反倒就会很痛苦呢?我和我姐说这些,她会觉得人生很简单,反倒是我把它想复杂了。我大概能懂她对生活的态度,但我又觉得我不想像她一样糊涂地活着。哲学是一把双刃剑,它一边让人觉得清晰,一边让人觉得痛苦,在拯救人的同时也慢慢地将这个人杀死。
2025年06月17日
5 阅读
0 评论
0 点赞
1
2