React16源码: React.Children源码实现
React.Children
1 ) 概述
- 这个API用的也比较的少,因为大部分情况下,我们不会单独去操作children
- 我们在一个组件内部拿到 props 的时候,我们有props.children这么一个属性
- 大部分情况下,直接把 props.children 把它渲染到我们的jsx 里面就可以了
- 很少有情况需要去操作一下这个children,但是一旦需要去操作这个children呢
- 直接使用react点children的API,而不是你直接去操作dom
- 大部分时候拿到的 children,可能是一个合理的react element,或者是一个数组
- React提供Children这个API去操作它,一定是有一个合理的原因的
2 )示例演示
import React from 'react'function ChildrenDemo(props) {console.log(props.children)console.log(React.Children.map(props.children, c => [c, c]))return props.children
}export default () => (<ChildrenDemo><span>1</span><span>2</span></ChildrenDemo>
)
- 上面这个代码非常简单,创建了一个组件叫 ChildrenDemo
- 里面有两个 span 作为children,在 props.children 里面,就可以拿到
- 第一个打印出来的就是 props.children
- 它就是两个 react element 节点
- 第二个打印的是 map 的返回值
- 我们通过react.children.map, 传入这个props.children 和一个callback
- 这个callback,返回的是一个数组, 这个数组里面,包含两个相同的节点
- 那这时候打印出来的是4个节点
- 也就是每个span都被克隆成2份,2个span是4份
- 前两个children 都是1,后两个都是2
- 再来改一下
console.log(React.Children.map(props.children, c => [c, [c, c]]))
- 它会输出六个节点
- 0, 1, 2,的children是 1
- 3, 4, 5 的 children 是2
- 也就是说 react.children的map function返回的是一个数组,它会继续把它展开
- 里面不管传了多少层嵌套的数组,最终都会展开成一层数组,即: 被拍平
- 拍平后有几个元素,map中的当前child就会被克隆成几份
- 这就是
React.Children.map
,跟普通原生的数组.map 的一个本质区别
3 )源码分析
定位到 React.js 中
const React = {Children: {map,forEach,count,toArray,only,},// ... 省略其他
};
- 这个对象里面有五个函数,跟原生数组操作非常的像
- 前两个是最重要的,就是map 和 forEach, 它和数组的意义是一样的
- 但它实际的操作可能跟数组的map和forEach会有一定的区别
- map是这些方法所有逻辑里面最复杂的一个,而 map 和 forEach 是差不多的
- 它们唯一的区别是一个有返回一个没有返回
- map是通过我们传入的一个方法之后,返回的一个新的数组
- 而forEach 中只在 null 的判断中返回,其实并非真实的返回值
再定位到 ReactChildren.js 中
/*** Copyright (c) Facebook, Inc. and its affiliates.** This source code is licensed under the MIT license found in the* LICENSE file in the root directory of this source tree.*/import invariant from 'shared/invariant';
import warning from 'shared/warning';
import {getIteratorFn,REACT_ELEMENT_TYPE,REACT_PORTAL_TYPE,
} from 'shared/ReactSymbols';import {isValidElement, cloneAndReplaceKey} from './ReactElement';
import ReactDebugCurrentFrame from './ReactDebugCurrentFrame';const SEPARATOR = '.';
const SUBSEPARATOR = ':';/*** Escape and wrap key so it is safe to use as a reactid** @param {string} key to be escaped.* @return {string} the escaped key.*/
function escape(key) {const escapeRegex = /[=:]/g;const escaperLookup = {'=': '=0',':': '=2',};const escapedString = ('' + key).replace(escapeRegex, function(match) {return escaperLookup[match];});return '$' + escapedString;
}/*** TODO: Test that a single child and an array with one item have the same key* pattern.*/let didWarnAboutMaps = false;const userProvidedKeyEscapeRegex = /\/+/g;
function escapeUserProvidedKey(text) {return ('' + text).replace(userProvidedKeyEscapeRegex, '$&/');
}const POOL_SIZE = 10;
const traverseContextPool = [];
function getPooledTraverseContext(mapResult,keyPrefix,mapFunction,mapContext,
) {if (traverseContextPool.length) {const traverseContext = traverseContextPool.pop();traverseContext.result = mapResult;traverseContext.keyPrefix = keyPrefix;traverseContext.func = mapFunction;traverseContext.context = mapContext;traverseContext.count = 0;return traverseContext;} else {return {result: mapResult,keyPrefix: keyPrefix,func: mapFunction,context: mapContext,count: 0,};}
}function releaseTraverseContext(traverseContext) {traverseContext.result = null;traverseContext.keyPrefix = null;traverseContext.func = null;traverseContext.context = null;traverseContext.count = 0;if (traverseContextPool.length < POOL_SIZE) {traverseContextPool.push(traverseContext);}
}/*** @param {?*} children Children tree container.* @param {!string} nameSoFar Name of the key path so far.* @param {!function} callback Callback to invoke with each child found.* @param {?*} traverseContext Used to pass information throughout the traversal* process.* @return {!number} The number of children in this subtree.*/
function traverseAllChildrenImpl(children,nameSoFar,callback,traverseContext,
) {const type = typeof children;if (type === 'undefined' || type === 'boolean') {// All of the above are perceived as null.children = null;}let invokeCallback = false;if (children === null) {invokeCallback = true;} else {switch (type) {case 'string':case 'number':invokeCallback = true;break;case 'object':switch (children.$$typeof) {case REACT_ELEMENT_TYPE:case REACT_PORTAL_TYPE:invokeCallback = true;}}}if (invokeCallback) {callback(traverseContext,children,// If it's the only child, treat the name as if it was wrapped in an array// so that it's consistent if the number of children grows.nameSoFar === '' ? SEPARATOR + getComponentKey(children, 0) : nameSoFar,);return 1;}let child;let nextName;let subtreeCount = 0; // Count of children found in the current subtree.const nextNamePrefix =nameSoFar === '' ? SEPARATOR : nameSoFar + SUBSEPARATOR;if (Array.isArray(children)) {for (let i = 0; i < children.length; i++) {child = children[i];nextName = nextNamePrefix + getComponentKey(child, i);subtreeCount += traverseAllChildrenImpl(child,nextName,callback,traverseContext,);}} else {const iteratorFn = getIteratorFn(children);if (typeof iteratorFn === 'function') {if (__DEV__) {// Warn about using Maps as childrenif (iteratorFn === children.entries) {warning(didWarnAboutMaps,'Using Maps as children is unsupported and will likely yield ' +'unexpected results. Convert it to a sequence/iterable of keyed ' +'ReactElements instead.',);didWarnAboutMaps = true;}}const iterator = iteratorFn.call(children);let step;let ii = 0;while (!(step = iterator.next()).done) {child = step.value;nextName = nextNamePrefix + getComponentKey(child, ii++);subtreeCount += traverseAllChildrenImpl(child,nextName,callback,traverseContext,);}} else if (type === 'object') {let addendum = '';if (__DEV__) {addendum =' If you meant to render a collection of children, use an array ' +'instead.' +ReactDebugCurrentFrame.getStackAddendum();}const childrenString = '' + children;invariant(false,'Objects are not valid as a React child (found: %s).%s',childrenString === '[object Object]'? 'object with keys {' + Object.keys(children).join(', ') + '}': childrenString,addendum,);}}return subtreeCount;
}/*** Traverses children that are typically specified as `props.children`, but* might also be specified through attributes:** - `traverseAllChildren(this.props.children, ...)`* - `traverseAllChildren(this.props.leftPanelChildren, ...)`** The `traverseContext` is an optional argument that is passed through the* entire traversal. It can be used to store accumulations or anything else that* the callback might find relevant.** @param {?*} children Children tree object.* @param {!function} callback To invoke upon traversing each child.* @param {?*} traverseContext Context for traversal.* @return {!number} The number of children in this subtree.*/
function traverseAllChildren(children, callback, traverseContext) {if (children == null) {return 0;}return traverseAllChildrenImpl(children, '', callback, traverseContext);
}/*** Generate a key string that identifies a component within a set.** @param {*} component A component that could contain a manual key.* @param {number} index Index that is used if a manual key is not provided.* @return {string}*/
function getComponentKey(component, index) {// Do some typechecking here since we call this blindly. We want to ensure// that we don't block potential future ES APIs.if (typeof component === 'object' &&component !== null &&component.key != null) {// Explicit keyreturn escape(component.key);}// Implicit key determined by the index in the setreturn index.toString(36);
}function forEachSingleChild(bookKeeping, child, name) {const {func, context} = bookKeeping;func.call(context, child, bookKeeping.count++);
}/*** Iterates through children that are typically specified as `props.children`.** See https://reactjs.org/docs/react-api.html#reactchildrenforeach** The provided forEachFunc(child, index) will be called for each* leaf child.** @param {?*} children Children tree container.* @param {function(*, int)} forEachFunc* @param {*} forEachContext Context for forEachContext.*/
function forEachChildren(children, forEachFunc, forEachContext) {if (children == null) {return children;}const traverseContext = getPooledTraverseContext(null,null,forEachFunc,forEachContext,);traverseAllChildren(children, forEachSingleChild, traverseContext);releaseTraverseContext(traverseContext);
}function mapSingleChildIntoContext(bookKeeping, child, childKey) {const {result, keyPrefix, func, context} = bookKeeping;let mappedChild = func.call(context, child, bookKeeping.count++);if (Array.isArray(mappedChild)) {mapIntoWithKeyPrefixInternal(mappedChild, result, childKey, c => c);} else if (mappedChild != null) {if (isValidElement(mappedChild)) {mappedChild = cloneAndReplaceKey(mappedChild,// Keep both the (mapped) and old keys if they differ, just as// traverseAllChildren used to do for objects as childrenkeyPrefix +(mappedChild.key && (!child || child.key !== mappedChild.key)? escapeUserProvidedKey(mappedChild.key) + '/': '') +childKey,);}result.push(mappedChild);}
}function mapIntoWithKeyPrefixInternal(children, array, prefix, func, context) {let escapedPrefix = '';if (prefix != null) {escapedPrefix = escapeUserProvidedKey(prefix) + '/';}const traverseContext = getPooledTraverseContext(array,escapedPrefix,func,context,);traverseAllChildren(children, mapSingleChildIntoContext, traverseContext);releaseTraverseContext(traverseContext);
}/*** Maps children that are typically specified as `props.children`.** See https://reactjs.org/docs/react-api.html#reactchildrenmap** The provided mapFunction(child, key, index) will be called for each* leaf child.** @param {?*} children Children tree container.* @param {function(*, int)} func The map function.* @param {*} context Context for mapFunction.* @return {object} Object containing the ordered map of results.*/
function mapChildren(children, func, context) {if (children == null) {return children;}const result = [];mapIntoWithKeyPrefixInternal(children, result, null, func, context);return result;
}/*** Count the number of children that are typically specified as* `props.children`.** See https://reactjs.org/docs/react-api.html#reactchildrencount** @param {?*} children Children tree container.* @return {number} The number of children.*/
function countChildren(children) {return traverseAllChildren(children, () => null, null);
}/*** Flatten a children object (typically specified as `props.children`) and* return an array with appropriately re-keyed children.** See https://reactjs.org/docs/react-api.html#reactchildrentoarray*/
function toArray(children) {const result = [];mapIntoWithKeyPrefixInternal(children, result, null, child => child);return result;
}/*** Returns the first child in a collection of children and verifies that there* is only one child in the collection.** See https://reactjs.org/docs/react-api.html#reactchildrenonly** The current implementation of this function assumes that a single child gets* passed without a wrapper, but the purpose of this helper function is to* abstract away the particular structure of children.** @param {?object} children Child collection structure.* @return {ReactElement} The first and only `ReactElement` contained in the* structure.*/
function onlyChild(children) {invariant(isValidElement(children),'React.Children.only expected to receive a single React element child.',);return children;
}export {forEachChildren as forEach,mapChildren as map,countChildren as count,onlyChild as only,toArray,
};
-
翻到最下面,看到
mapChildren as map
,这边 export 出去的是map
-
对应的,我们来看
mapchildren
这个方法/*** Maps children that are typically specified as `props.children`.** See https://reactjs.org/docs/react-api.html#reactchildrenmap** The provided mapFunction(child, key, index) will be called for each* leaf child.** @param {?*} children Children tree container.* @param {function(*, int)} func The map function.* @param {*} context Context for mapFunction.* @return {object} Object containing the ordered map of results.*/ function mapChildren(children, func, context) {if (children == null) {return children;}const result = [];mapIntoWithKeyPrefixInternal(children, result, null, func, context);return result; }
-
开始会调用一个方法叫
mapIntoWithKeyPrefixInternal
function mapIntoWithKeyPrefixInternal(children, array, prefix, func, context) {let escapedPrefix = '';if (prefix != null) {escapedPrefix = escapeUserProvidedKey(prefix) + '/';}const traverseContext = getPooledTraverseContext(array,escapedPrefix,func,context,);traverseAllChildren(children, mapSingleChildIntoContext, traverseContext);releaseTraverseContext(traverseContext); }
-
代码上是先处理了一下 escapedPrefix, 这个倒没什么,后面调用的方法和
forEachChildren
是差不多的 -
进入这里的
getPooledTraverseContext
方法 -
它先判断是否已有存在池中是否节点,如果有,则pop一个
-
并将传入的内容都挂载到这个pop出来的对象上面,用于记录
-
再经过一系列作用之后,执行到上面的
releaseTraverseContext
就是对对象进行清空 -
上面的过程涉及到了一个对象池的概念,也就是缓存池,用于节省操作的性能
- js是单线程语言,对大量对象进行操作,比如挂载和删除,可能会造成内存抖动的问题
- 可能导致浏览器内的页面性能很差
- 它设置Pool Size的大小是 10,是一个渐进的过程
- 一开始是空的,随着对象的创建会进行缓存,接着复用
-
总体来说,它会做一个非常重要的事情,就是到一个叫做
contextPool
的地方去获取一个 context -
接下去所有流程都是在这个函数里面调用了
traverseAllChildren
这个方法 -
调用完所有的方法之后,它会把这个context再返回到这个
contextPool
里面 -
调用的
traverseAllChildren
方法没有什么操作,本质上调了traverseAllChildrenImpl
的方法/*** Traverses children that are typically specified as `props.children`, but* might also be specified through attributes:** - `traverseAllChildren(this.props.children, ...)`* - `traverseAllChildren(this.props.leftPanelChildren, ...)`** The `traverseContext` is an optional argument that is passed through the* entire traversal. It can be used to store accumulations or anything else that* the callback might find relevant.** @param {?*} children Children tree object.* @param {!function} callback To invoke upon traversing each child.* @param {?*} traverseContext Context for traversal.* @return {!number} The number of children in this subtree.*/ function traverseAllChildren(children, callback, traverseContext) {if (children == null) {return 0;}return traverseAllChildrenImpl(children, '', callback, traverseContext); }
-
进入
traverseAllChildrenImpl
这个方法会判断我们的children是否是一个数组或者是一个iterator对象 -
这代表它们是多个节点是可以遍历的, 如果它是多个节点,它会去循环每一个节点
-
然后对每一个节点再重新调用这个
traverseAllChildrenImpl
这个方法, 也就是递归实现 -
最终要传入这个
traverseAllChildrenImpl
方法的children,是以单个节点的时候 -
才会去执行真正的
mapSingleChildIntoContext
方法, 在这个方法里面会调用 -
React.Children.map
传入的第二个参数,也就是那个map function -
它会传入上面遍历出来的最终的单个节点,返回想要的map结果的一个数据
-
拿到一个map数据之后,它会进行一个判断,是否是数组,如果不是数组
-
它会在result中插入克隆节点,并替换key,防止有相同的key出现
-
如果是数组的话,又会回过头来去调用这个
mapIntoWithKeyPrefixInternal
,到这里完成了一个大的递归 -
在这么一个递归的过程下去,最终是把里面返回的所有层级的数组都进行了一个展开
-
展开之后就变成了一个一维数组, 这就是它的一个整体的流程
-
-
然后再来对比一下
forEachChildren
/** * Iterates through children that are typically specified as `props.children`. * * See https://reactjs.org/docs/react-api.html#reactchildrenforeach * * The provided forEachFunc(child, index) will be called for each * leaf child. * * @param {?*} children Children tree container. * @param {function(*, int)} forEachFunc * @param {*} forEachContext Context for forEachContext. */ function forEachChildren(children, forEachFunc, forEachContext) {if (children == null) {return children;}const traverseContext = getPooledTraverseContext(null,null,forEachFunc,forEachContext,);traverseAllChildren(children, forEachSingleChild, traverseContext);releaseTraverseContext(traverseContext); }
- 可以看到它最后没有 return,这就是
forEachChildren
跟mapChildren
的本质区别
- 可以看到它最后没有 return,这就是
-
关于export 出去的
toArray
function toArray(children) {const result = [];mapIntoWithKeyPrefixInternal(children, result, null, child => child);return result; }
toArray
和mapChildren
唯一的区别就是 map function- 换句话说,它的map function,其实就是
child => child
- 它其实也会把数组展开,只是说没有map的过程
-
还有 export 出去的
onlyChild
function onlyChild(children) {invariant(isValidElement(children),'React.Children.only expected to receive a single React element child.',);return children; }
- 其实就是判断一下这个children是否是单个的合理的 react element 节点
- 如果是的话,就返回,不是的话,给出提醒
-
最后 export 出去的
countChildren
function countChildren(children) {return traverseAllChildren(children, () => null, null); }
- 内部调用
traverseAllChildren
, 本质上还是调用traverseAllChildrenImpl
- 最终返回的是统计后的值
subtreeCount
- 内部调用
-
最后还有一个 节点 key 相关的处理,主要核心实现是在
getComponentKey
也是个递归的处理- 打印出的每个节点上,都会有一个key,这个key的处理也是比较核心的
- 参考 ChildrenDemo中的 React.Children.map 中的回调
c => [c, [c,c]]
这里会总计打印出6个节点- 可以看到第一个节点是 .0/.0
- 然后第二个节点是 .0/.1:0
- 然后第三个节点是 .0/.1:1
- …
- 可以按照上述函数和顶层声明的两个变量
SEPARATOR
和SUBSEPARATOR
- 理解下这个打印出的结果
相关文章:
React16源码: React.Children源码实现
React.Children 1 ) 概述 这个API用的也比较的少,因为大部分情况下,我们不会单独去操作children我们在一个组件内部拿到 props 的时候,我们有props.children这么一个属性大部分情况下,直接把 props.children 把它渲染到我们的jsx…...

深度学习|4.1 深L层神经网络 4.2 深层网络的正向传播
4.1 深L层神经网络 对于某些问题来说,深层神经网络相对于浅层神经网络解决该问题的效果会较好。所以问题就变成了神经网络层数的设置。 其中 n [ i ] n^{[i]} n[i]表示第i层神经节点的个数, w [ l ] w^{[l]} w[l]代表计算第l层所采用的权重系数ÿ…...

印象笔记03 衍生软件使用
印象笔记03 衍生软件使用 Verse 以下内容来源于官方介绍 VERSE是一款面向未来的智能化生产力工具,由印象笔记团队诚意推出。 你可以用VERSE: 管理数字内容,让信息有序高效运转;搭建知识体系,构建你的强大知识库&am…...
R语言【CoordinateCleaner】——cc_gbif(): 根据通过 method 参数定义的方法,删除或标记地理空间中异常值的记录。
cc_gbif()是R语言包coordinatecleaner中的一个函数,用于清理GBIF(全球生物多样性信息设施)数据集的地理坐标。该函数可以识别潜在的坐标错误,并对其进行修正或删除。 以下是cc_gbifl()函数的一般用法和主要参数: cc_…...

模式识别与机器学习-集成学习
集成学习 集成学习思想过拟合与欠拟合判断方法 K折交叉验证BootstrapBagging随机森林的特点和工作原理: BoostingAdaBoost工作原理:AdaBoost的特点和优点:AdaBoost的缺点: Gradient Boosting工作原理:Gradient Boostin…...

vue简单实现滚动条
背景:产品提了一个需求在一个详情页,一个form表单元素太多了,需要滚动到最下面才能点击提交按钮,很不方便。他的方案是,加一个滚动条,这样可以直接拉到最下面。 优化:1、支持滚动条,…...

计算机网络第一课
先了解层级: 传输的信息称为协议数据单元(PDU),PDU在每个层次的称呼都不同,见下图:...

初识大数据,一文掌握大数据必备知识文集(12)
🏆作者简介,普修罗双战士,一直追求不断学习和成长,在技术的道路上持续探索和实践。 🏆多年互联网行业从业经验,历任核心研发工程师,项目技术负责人。 🎉欢迎 👍点赞✍评论…...

安全防御之授权和访问控制技术
授权和访问控制技术是安全防御中的重要组成部分,主要用于管理和限制对系统资源(如数据、应用程序等)的访问。授权控制用户可访问和操作的系统资源,而访问控制技术则负责在授权的基础上,确保只有经过授权的用户才能访问…...
Iceberg从入门到精通系列之二十:Iceberg支持的字段类型
Iceberg从入门到精通系列之二十:Iceberg支持的字段类型 Iceberg 表支持以下类型: 字段类型描述注释booleanTrue or falseint32 位有符号整数可以提升到longlong64 位有符号整数float32 位 IEEE 754 浮点可以提升到doubledouble64 位 IEEE 754 浮点decim…...

Unity坦克大战开发全流程——结束场景——通关界面
结束场景——通关界面 就照着这样来拼 写代码 hideme不要忘了 修改上一节课中的代码...
K8S三种发布方式和声明式资源管理
蓝绿发布 把应用服务集群标记位两个组,蓝组和绿组,先升级蓝组,先要把蓝组从负载均衡当中移除,绿组继续提供服务,蓝组升级完毕,再把绿组从负载均衡当中移除,绿组升级,然后都加入回负载…...

从千问Agent看AI Agent——我们很强,但还有很长的路要走
前言 最近双十一做活动买了台新电脑,显卡好起来了自然也开始大模型的学习工作了,这篇文章可能是该系列的第一弹,本地私有化部署千问agent,后面还会尝试一些其他的大模型结合本地知识库或者做行业垂直模型训练的,一步…...
Word2Vector介绍
Word2Vector 2013 word2vec也叫word embeddings,中文名“词向量”,google开源的一款用于词向量计算的工具,作用就是将自然语言中的字词转为计算机可以理解的稠密向量。在word2vec出现之前,自然语言处理经常把字词转为离散的单独的…...

书生·浦语大模型全链路开源体系----(1)
书生浦语大模型全链路开源体系 什么是大语言模型? 大语言模型是指具有大规模参数和强大语言理解能力的机器学习模型。这些模型通常使用深度学习技术,特别是递归神经网络(RNN)或变换器(Transformer)等架构…...
第四篇 行为型设计模式 - 灵活定义对象间交互
第四篇:行为型设计模式 - 灵活定义对象间交互 行为型设计模式关注对象之间的交互和职责分配,旨在定义对象间的高效、灵活的通信机制。以下是十一种常见行为型设计模式的详解及其应用场景。 1. 策略模式详解及其应用场景 详解: 策略模式定义…...

2023最新租号平台系统源码支持单独租用或合租使用
这是一款租号平台源码,采用常见的租号模式。目前网络上还很少见到此类类型的源码。 平台的主要功能如下: 支持单独租用或采用合租模式; 采用易支付通用接口进行支付; 添加邀请返利功能,以便站长更好地推广…...

数据库的连接
连接数据库 我们使用WinR输入cmd打开运行窗口 输入:sqlplus并回车 输入用户名和密码,我用的是Scott,密码我自己设置的123456,Scott默认的密码是tiger,回车 这种情况表示登录成功 在连接Scott成功的情况下创建一些数据,在我的资源里面有个Oracle数据基础可以下载,直接复制粘…...

第14课 利用openCV快速数豆豆
除了检测运动,openCV还能做许多有趣且实用的事情。其实openCV和FFmpeg一样都是宝藏开源项目,貌似简单的几行代码功能实现背后其实是复杂的算法在支撑。有志于深入学习的同学可以在入门后进一步研究算法的实现,一定会受益匪浅。 这节课&#…...
在前端利用Broadcast Channel实现浏览器跨 Tab 窗口通信的方法
Broadcast Channel 在前端,我们经常会用postMessage来实现页面间的通信,但这种方式更像是点对点的通信。对于一些需要广播(让所有页面知道)的消息,用postMessage不是非常自然。Broadcast Channel 就是用来弥补这个缺陷…...

visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...

376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命
在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...
C++.OpenGL (10/64)基础光照(Basic Lighting)
基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!
简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求,并检查收到的响应。它以以下模式之一…...
AGain DB和倍数增益的关系
我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...

c++第七天 继承与派生2
这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分:派生类构造函数与析构函数 当创建一个派生类对象时,基类成员是如何初始化的? 1.当派生类对象创建的时候,基类成员的初始化顺序 …...

恶补电源:1.电桥
一、元器件的选择 搜索并选择电桥,再multisim中选择FWB,就有各种型号的电桥: 电桥是用来干嘛的呢? 它是一个由四个二极管搭成的“桥梁”形状的电路,用来把交流电(AC)变成直流电(DC)。…...

Linux 内存管理调试分析:ftrace、perf、crash 的系统化使用
Linux 内存管理调试分析:ftrace、perf、crash 的系统化使用 Linux 内核内存管理是构成整个内核性能和系统稳定性的基础,但这一子系统结构复杂,常常有设置失败、性能展示不良、OOM 杀进程等问题。要分析这些问题,需要一套工具化、…...