leungkaming / blog2021 Goto Github PK
View Code? Open in Web Editor NEW知识总结、沉淀记录的地方。
知识总结、沉淀记录的地方。
// es5
// 创建一个类
function Person () {}
Person.prototype.nickName = 'ljm' // 给类的原型上添加属性,基于这类创建的实例都能访问到这个属性
// 创建实例
var person = new Person()
1. 关于实例
person.__proto__ === Person.prototype // true
person.nickName // 'ljm',person实例会默认从最近自身的类的原型上查找,即Person.prototype
person.constructor.name === 'Person' // 实例的构造函数对应是自身的类 => person实例不具备constructor属性,这个属性是属于自身的类的原型上查找的
2. 关于类
Person.prototype.constructor.name === 'Person' // true,左侧表达式的值恒等于类本身
Person.prototype.__proto__ === Object.prototype // true, 每个类的原型都可以看成是Object类的一个实例 => 一个实例的__proto__指向它的类的原型
Object.prototype.__proto__ === null // true, 意味着 原型链 最顶级就是Object
// 特异点
1. 类,也是一个是函数
Person.constructor.name === 'Function' // true, Person既是类,也可以看成是 Function类 的一个实例 => 实例的构造函数对应是自身的类
Object.constructor.name === 'Function' // true, Object既是类,也可以看成是 Function类 的一个实例 => 实例的构造函数对应是自身的类
2. 类的原型,也是一个实例
Person.__proto__ === Function.prototype // true, 上面提到过,Person既是类,也可以看成是函数的一个实例 => 它的类自然就是Function
Function.prototype.__proto__ === Object.prototype // true, 每个类的原型都可以看成是Object类的一个实例 => 一个实例的__proto__指向它的类的原型
一句话概括:基本数据类型(String, Number, Boolean, Null, Undefined)都是存储在栈内存;引用数据类型(Object, Array, Function)都是存储在堆内存。
useState
● 每次返回的都是最新state,同时每次更新state都会带着一次渲染;
● react会确保setState不会在组件重新渲染时发生变化,这就是为什么可以安全地从 useEffect 或 useCallback 的依赖列表中省略 setState;
● setState部分使用场景,例如:
useEffect
● 在不传入依赖数组项时,每次都会随render更新而调用;
● 每次在执行下一个effect前都会清除上次effect,即意味着下一个render前就会清除上次effect;
● useEffect会在render更新后通过异步被调用,所以里面放的都是跟layout无关的处理;
● 返回一个函数,则会在组件卸载时执行,等同于componentWillUnmount;
● 第二个参数传入空数组,则会在组件首次挂载和卸载时执行,等同于componentDidmount / componentWillUnmount;
● 第二个参数传入非空数组,则会在该变量发生改变时才执行,等同于componentDidUpdate;
useLayoutEffect
● 会在render更新后通过同步被调用;
● 不要在里面放会阻塞页面渲染的逻辑;
useContext
const context = React.createContext(null)
<Context.Provider value=context>
<Context.Consumer>
{(value) => <div>123</div>}
</Context.Consumer>
</Context.Provider>
● 等同于内部状态管理的消费者hook模式(class模式通过contextType );
● class:当 Provider 的 value 值发生变化时,它内部的所有消费组件都会重新渲染。从 Provider 到其内部 consumer 组件(包括 .contextType 和 useContext)的传播不受制于 shouldComponentUpdate 函数,因此当 consumer 组件在其祖先组件跳过更新的情况下也能更新;
● hook:当组件上层最近的 <MyContext.Provider> 更新时,该 Hook 会触发重渲染,并使用最新传递给 MyContext provider 的 context value 值。即使祖先使用 React.memo 或 shouldComponentUpdate,也会在组件本身使用 useContext 时重新渲染;
● 调用了 useContext 的组件总会在 context 值变化时重新渲染。如果重渲染组件的开销较大,你可以 通过使用 memoization 来优化(useMemo / useCallback)
useReducer
const initialState = {count: 0};
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
<button onClick={() => dispatch({type: 'increment'})}>+</button>
</>
);
}
● 底层原理是通过内部的useState,接受外部传入的action 和 reducer组装dispatch实现的,具体dispatch如:reducer(state, action);
● 在某些场景下,useReducer 会比 useState 更适用,例如:
useMemo
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b])
● 返回一个缓存值,在依赖参数不变的的情况返回的是上次第一次计算的值;在某个依赖项改变时才会计算返回新的缓存值;
● 起到了class组件中shouldComponentUpdate的作用,但缺点是内部引用的依赖发生变化时不会主动通知
● 传入的函数会在每次render渲染期间都会执行;
useCallback
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);
● useCallback(fn, deps) 相当于 useMemo(() => fn, deps)
● 返回一个缓存函数,传入的函数只有在某个依赖项改变时才会触发缓存函数更新,同时作用域内用到的变量才会取最新值;
● 内部本身就是一个作用域,在依赖不变的情况下,作用域内用到的变量也是上次的缓存值;
● 跟useMemo一样,useCallback会在每次渲染都执行;
useRef
● useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。
● 返回的 ref 对象在组件的整个生命周期内持续存在。
function TextInputWithFocusButton() {
const inputEl = useRef(null); // 初始化值为null
const onButtonClick = () => {
// `current` 指向已挂载到 DOM 上的文本输入元素
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" /> // ref只要以这种类型传入dom,则ref.current属性值为dom节点
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
● 当 ref 对象内容发生变化时,useRef 并不会通知你。即变更 .current 属性不会引发组件重新渲染。
● 如果想要在 React 绑定或解绑 DOM 节点的 ref 时运行某些代码,则需要使用回调 ref 来实现。
● 组件重新渲染后,变量会被重新赋值,可以用useRef缓存数据,这个数据改变后是不会触发组件重新渲染的,如果用useState保存数据,数据改变后会导致组件重新渲染,所以我们想悄悄保存数据,useRef是不二选择👊
// 可以充分利用好 “变更.current 属性不会引发组件重新渲染” 这个特性
// 优化前,text会一直随着输入框的内容变化而变化,如果当前组件体量大的话会造成反复渲染,影响性能
const [text, setText] = useState('');
const handleSubmit = useCallback(() => {
// ...
}, [text]);
return (
<form>
<input value={text} onChange={(e) => setText(e.target.value)} />
<OtherForm onSubmit={handleSubmit} />
</form>
);
// 优化后
const textRef = useRef('');
const [text, setText] = useState('');
const handleSubmit = useCallback(() => {
console.log(textRef.current);
// ...
}, [textRef]); // 1)首先,ref对象内容发生变化是不会有内部通知的
return (
<form>
<input value={text} onChange={(e) => {
const { value } = e.target;
setText(value)
textRef.current = value; // 2)其次,变更 .current 属性不会引发组件重新渲染
}} />
// 3)所以handleSubmit里的内容不会随变量text的变化而反复调用
<OtherForm onSubmit={handleSubmit} />
</form>
);
useImperativeHandle
● React.forwardRef 常与当前hook搭配使用。
// 子组件伪代码
function FancyInput(props, ref) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
console.log('自定义focus')
inputRef.current.focus();
}
}));
return <input ref={inputRef} ... />;
}
FancyInput = forwardRef(FancyInput);
// 父组件伪代码
class Container extends React.Component {
constructor(props){
super(props)
}
submit () {
this.inputRef.current.focus()
}
render () {
<div>
<FancyInput ref={this.inputRef} />
<button onClick={ this.submit.bind(this) }></button>
</div>
}
}
● 同步React.forwardRef的两个场景:
// 子组件伪代码
const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="FancyButton">
{props.children}
</button>
));
// 父组件伪代码
// 你可以直接获取 DOM button 的 ref:
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;
// 子组件伪代码
function logProps(Component) {
class LogProps extends React.Component {
componentDidUpdate(prevProps) {
console.log('old props:', prevProps);
console.log('new props:', this.props);
}
render() {
const {forwardedRef, ...rest} = this.props;
// 将自定义的 prop 属性 “forwardedRef” 定义为 ref
return <Component ref={forwardedRef} {...rest} />;
}
}
// 我们可以将其作为常规 prop 属性传递给 LogProps,例如 “forwardedRef”
// 然后它就可以被挂载到被 LogProps 包裹的子组件上。
return React.forwardRef((props, ref) => {
return <LogProps {...props} forwardedRef={ref} />;
});
}
// 父组件伪代码
const ref = React.createRef();
<FancyButton
label="Click Me"
handleClick={handleClick}
ref={ref} // 这里传入的ref会给子组件的forwardRef接收到
/>;
总结:
var value = 1
function foo () {
console.log(value)
}
function bar () {
var value = 2
foo()
}
bar() // 1
var scope = "global scope"; // 变量提升
function checkscope(){ // 函数预声明
var scope = "local scope";
function f(){
return scope;
}
return f();
}
checkscope(); // local scope
// 如何输出global scope
var scope = "global scope";
function checkscope(){
function f(){
return scope;
}
return f();
}
checkscope(); // global scope
var scope = "global scope"; // 变量提升
function checkscope(){ // 函数预声明
var scope = "local scope";
function f(){
return scope;
}
return f;
}
checkscope()(); // local scope,分析:不管返回函数还是返回值,函数checkscope里面的作用域已经存在scope,怎么嵌套调用,最终只会认里面的local scope。
上述代码示例的() 和 ()()两种情况,其实映射了变量销毁的知识点在里面,()调用后变量scope会跟着销毁,()()中第一次()并没有销毁scope,而是留在第二次()调用后才进行销毁。
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.