学习underscore之比较两个元素是否相同

2023-11-06

underscore1.11.0 中判断两个参数相同的函数为isEqual 

isEqual 函数认为以下相等:

  1. 0 与 -0 不相等;
  2. NaN 与 NaN相等;
  3. /a/i 与 new RegExp(/a/i)相等;
  4. '5' 与 new String('5')相等;
  5. true 与 new Boolean(true)相等;
  6. Object(NaN) 与 Object(NaN)相等,new  Number(1) 与 new  Number(1)相等;
  7. new Date('2020-10-30') 与 new Date('2020-10-30')相等;
  8. new Boolean(false) 与 new Boolean(false)相等;
  9. [1, 2, 3] 与 [1, 2, 3]相等;
  10. {name: 'zxx', age: 18} 与 {name: 'zxx', age: 18}相等;
  11. ...

我们来一步步实现这个判断两个参数是否相等的函数

function eq(a, b) { ... }

判断+0 与 -0不相等

console.log(+0 === -0); // true

(-0).toString(); // '0'
(+0).toString(); // '0'

-0 < +0; // false
+0 < -0; // false

但两者还是不同:

1 / +0 // Infinity
1 / -0 // -Infinity

1 / +0 === 1 / -0; // false 

之所以会有+0 和 -0 是因为javascript采用了IEEE_754浮点数表示法,这是一种二进制表示法,其中最高位表示符号位(0表示正,1表示负),剩下的用于表示大小。

以下情况会产生-0

Math.round(-0.1) // -0
function eq(a, b) {
    if (a === b) {
        return a !== 0 || 1 / a === 1 / b;
    }  
    return false;
}
console.log(eq(0, 0));  // true
console.log(eq(0, -0)); // false

判断NaN与NaN相等

console.log(NaN === NaN); // false
function eq(a, b) {
    if (a !== a) {
        return b !== b;
    }
}
console.log(eq(NaN, NaN)); // true

第一版eq函数

// 第一版先用来过滤简单的类型比较,复杂类型使用deepEq函数进行处理
function eq(a, b) {
    // === 结果为true的区别出+0 和 -0
    if (a === b) return a !== 0 || 1 / a === 1 / b;

    // null === null 为true, 这里做判断是为了让有null的情况尽早退出函数
    if (a === null || b === null) return false;

    // 判断NaN
    if (a !== a) return b !== b;

    // 判断参数a类型,如果是基本类型这里直接返回false    
    var type = typeof a;
    if (type !== 'function' && type !== 'object' && typeof b != 'object') return false;
    return deepEq(a, b);
}

剩下的就是实现比较对象是否相等的deepEq函数了

对于RegExp、String对象,我们可以统一转成字符串进行比较:

var toString = Object.prototype.toString;
var reg = /a/i, reg1 = new RegExp(/a/i);
console.log(toString.call(reg));   // [object RegExp]
console.log(toString.call(reg1));  // [object RegExp]
console.log('' + reg === '' + reg1); // true

var str = '5', str1 = new String(5);
console.log(toString.call(str));   // [object String]
console.log(toString.call(str1));  // [object String]
console.log('' + str === '' + str1); // true

对于Number,我们转成数字进行比较:

var toString = Object.prototype.toString;
var num = Object(NaN), num1 = new Number(NaN);
// 对于NaN单独处理
console.log(+num !== +num, +num1 !== num1);  // true true

num = 0, num1 = new Number(-0);
// 0 与 -0
console.log(1 / +num === 1 / +num1);         // false

num = 1, num1 = new Number(1);
// 非0
console.log(+num === +num1);                // true                

对于Date、Boolean ,我们同样转成数值原始值进行比较:

var toString = Object.prototype.toString;
var date = new Date('2020-10-30'), data1 = new Date('2020-10-30');
console.log(+date === +date1);    // true
// 日期不正确会返回NaN
console.log(+new Date('2020-10-300') === +new Date('2020-10-300')); // false

var bool = true, bool1 = new Boolean(true);
console.log(+bool === +bool1);    // true

下面我们来实现一部分deepEq函数:

var toString = Object.prototype.toString;
function deepEq(a, b) {
    var className = toString.call(a);
    if (className !== toString.call(b)) return false;

    switch (className) {
        case '[object RegExp]':
        case '[object String]':
            return '' + a === '' + b;
        case '[object Number]':
            if (+a !== +a) return +b !== +b;
            return +a === 0 ? 1 / +a === 1 / b : +a === +b;
        case '[object Date]':
        case '[object Boolean]':
            return +a === +b;
    }
    // 其他类型的判断...
}

 先来看看构造函数实例:

function Person (name) {
    this.name = name;
}

function Animal (name) {
    this.name = name;
}

var person = new Person('hello');
var animal = new Animal('hello');

 

两者虽然都是{name: 'hello'}, 但是这两者属于不同构造函数的实例,此时,我们认为是不同的对象。

如果两个对象所属的构造函数对象不同,两个对象能相等吗?

var obj = Object.create(null);
obj.name = 'hello';
eq(obj, {name: 'hello'}); 

obj对象没有原型,也没有构造函数,但在实际应用中,只要两者有着相同的键值对,我们就认为相等。

我们来实现对于不同构造函数下的实例直接返回false:

function isFunction (obj) {
    return toString.call(obj) === '[object Object]';
}
function deepEq (a, b) {
    // 代码接上面
    var areArrays = className === '[object Array]';
    // 不是数组
    if (!areArrays ) {
        // 过滤函数的情况
        if (typeof a != 'object' || typeof b != 'object') return false;

        var aCtor = a.constructor, bCtor = b.constructor;
        // 构造函数都存在且都不是Object构造函数的情况下,aCtor 不等于 bCtor ,那这两个对象就不相等
        if (aCtor !== bCtor && !(isFunction(aCtor) && aCtor instanceof aCtor && isFunction(bCtor) && bCtor instanceof bCtor) && ('constructor' in a && 'constructor' in b)) {
          return false;
    }
    // ...
}

下面我们进行数组和对象的判断:

function deepEq (a, b){
    // 再接着上面的内容
    if (areArrays) {
        // 比较数组长度以确定是否需要进行深度比较
        length = a.length;
        if (length !== b.length) return false;
        // 深入比较内容,忽略非数字属性
        while (length--) {
            if (!eq(a[length], b[length])) return false;
        }
    } else {
        // 深入比较对象
        var _keys = Object.keys(a), key;
        length = _keys.length;
        // 在比较深度相等之前,判断两个对象包含相同数量的属性
        if (keys(b).length !== length) return false;
        while (length--) {
            // 深入比较每个元素
            key = _keys[length];
            if (!(b.hasOwnProperty(key) && eq(a[key], b[key]))) return false;
        }
    }
    return true;
} 

解决循环引用问题:

var a = {foo: null};
var b = {foo: null};
a.foo = a;
b.foo = b;

那underscore是如何解决这个问题的呢?答案是多传递两个参数aStack和bStack,用来存储a和b递归比较过程中的a和b的值:

var a = {foo: null};
var b = {foo: null};
a.foo = a;
b.foo = b;

function eq(a, b, aStack, bStack) {
    return deepEq(a, b, aStack, bStack)
}

function deepEq(a, b, aStack, bStack) {
    
    aStack = aStack || [];
    bStack = bStack || [];
    var length = aStack.length;
    while (length--) {
        if (aStack[length] === a) return bStack[length] === b;
    }

    // 将第一个对象添加到遍历对象的堆栈中
    aStack.push(a);
    bStack.push(b);

    var _keys = Object.keys(a), key;
    length = _keys.length;
    if (keys(b).length !== length) return false;
    while (length--) {
        key = _keys[length];

        console.log(a[key], b[key], aStack, bStack)

        if (!(b.hasOwnProperty(key) && eq(a[key], b[key], aStack, bStack))) return false;
    }
    // 从遍历对象的堆栈中移除第一个对象
    aStack.pop();
    bStack.pop();
    return true;
}

下面接着判断ArrayBuffer 、DataView类型

对于ArrayBuffer 、DataView首先需要判断兼容性:

在IE10-Edge13版本中,DataView实例toString为[object Object]

在IE11中, Map、WeakMap 、Set同样也是。

以下代码是判断ArrayBuffer 、DataView类型:

var toString = Object.prototype.toString;
function tagTester(name) {
    return function(obj) {
        return toString.call(obj) === '[object ' + name + ']';
    };
}
var isFunction = tagTester('Function');
var hasObjectTag = tagTester('Object');
var hasStringTagBug = typeof DataView !== 'undefined' && hasObjectTag(new DataView(new ArrayBuffer(8)));
var isArrayBuffer = tagTester('ArrayBuffer');
var isDataView = tagTester('DataView');
var isFunction = tagTester('Function');
// 兼容性
var nodelist = document && document.childNodes;
if (typeof /./ != 'function' && typeof Int8Array != 'object' && typeof nodelist != 'function') {
    isFunction = function(obj) {
        return typeof obj == 'function' || false;
    }
}
function ie10IsDataView(obj) {
    return obj != null && isFunction(obj.getInt8) && isArrayBuffer(obj.buffer);
}
var isDataView$1 = (hasStringTagBug ? ie10IsDataView : isDataView);

剩下来就是如何进行比较这两种类型:

function toBufferView(bufferSource) {
    return new Uint8Array(
        bufferSource.buffer || bufferSource,
        bufferSource.byteOffset || 0,
        bufferSource == null ? undefined : bufferSource.byteLength
    )
}

最后除了Array类型外,还需要考虑Int8Array、Float32Array等类型

// 代码接上面
var supportsArrayBuffer = typeof ArrayBuffer !== 'undefined',
    supportsDataView = typeof DataView !== 'undefined';
var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;

var nativeIsView = supportsArrayBuffer && ArrayBuffer.isView;

var typedArrayPattern = /\[object ((I|Ui)nt(8|16|32)|Float(32|64)|Uint8Clamped|Big(I|Ui)nt64)Array\]/;

var isBufferLike = function (obj) {
    var sizeProperty = obj == null ? void 0 : obj['byteLength'];
    return typeof sizeProperty == 'number' && sizeProperty >= 0 && sizeProperty <= MAX_ARRAY_INDEX;
}

function isTypedArray(obj) {
    return nativeIsView ? (nativeIsView(obj) && !isDataView$1(obj)) :isBufferLike(obj) && typedArrayPattern.test(toString.call(obj));
}

最终代码如下:

var toString = Object.prototype.toString;
function tagTester(name) {
    return function(obj) {
        return toString.call(obj) === '[object ' + name + ']';
    };
}
var isFunction = tagTester('Function');
var hasObjectTag = tagTester('Object');
var hasStringTagBug = typeof DataView !== 'undefined' && hasObjectTag(new DataView(new ArrayBuffer(8)));
var isArrayBuffer = tagTester('ArrayBuffer');
var isDataView = tagTester('DataView');
var isFunction = tagTester('Function');
// 兼容性
var nodelist = document && document.childNodes;
if (typeof /./ != 'function' && typeof Int8Array != 'object' && typeof nodelist != 'function') {
    isFunction = function(obj) {
        return typeof obj == 'function' || false;
    }
}
function ie10IsDataView(obj) {
    return obj != null && isFunction(obj.getInt8) && isArrayBuffer(obj.buffer);
}
var isDataView$1 = (hasStringTagBug ? ie10IsDataView : isDataView);

var supportsArrayBuffer = typeof ArrayBuffer !== 'undefined',
    supportsDataView = typeof DataView !== 'undefined';
var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
var nativeIsView = supportsArrayBuffer && ArrayBuffer.isView;

var typedArrayPattern = /\[object ((I|Ui)nt(8|16|32)|Float(32|64)|Uint8Clamped|Big(I|Ui)nt64)Array\]/;

var isBufferLike = function (obj) {
    var sizeProperty = obj == null ? void 0 : obj['byteLength'];
    return typeof sizeProperty == 'number' && sizeProperty >= 0 && sizeProperty <= MAX_ARRAY_INDEX;
}
var getByteLength = function (obj) {
    return obj == null ? void 0 : obj['byteLength'];
}

function isTypedArray(obj) {
    return nativeIsView ? (nativeIsView(obj) && !isDataView$1(obj)) :isBufferLike(obj) && typedArrayPattern.test(toString.call(obj));
}
var isTypedArray$1 = supportsArrayBuffer ? isTypedArray : false;

var tagDataView = '[object DataView]';

function eq(a, b, aStack, bStack) {
    // === 结果为true的区别出+0 和 -0
    if (a === b) return a !== 0 || 1 / a === 1 / b;

    // null === null 为true, 这里做判断是为了让有null的情况尽早退出函数
    if (a === null || b === null) return false;

    // 判断NaN
    if (a !== a) return b !== b;

    // 判断参数a类型,如果是基本类型这里直接返回false    
    var type = typeof a;
    if (type !== 'function' && type !== 'object' && typeof b != 'object') return false;
    return deepEq(a, b, aStack, bStack);
}


function deepEq(a, b, aStack, bStack) {
    var className = toString.call(a);
    if (className !== toString.call(b)) return false;
    // 解决IE 10-Edge 13中的兼容性问题
    if (hasStringTagBug && className == '[object Object]' && isDataView$1(a)) {
        if (!isDataView$1(b)) return false;
        className = tagDataView;
    }
    switch (className) {
        // 这些类型按值进行比较
        case '[object RegExp]':
        case '[object String]':
            return '' + a === '' + b;
        case '[object Number]':
            // 判断Object(NaN)
            if (+a !== +a) return +b !== +b;
            return +a === 0 ? 1 / +a === 1 / b : +a === +b;
        case '[object Date]':
        case '[object Boolean]':
        // 将日期和布尔值转换为数值原始值
             return +a === +b;
        case '[object Symbol]':
            return SymbolProto.valueOf.call(a) === SymbolProto.valueOf.call(b);
        case '[object ArrayBuffer]':
        case tagDataView:
            return deepEq(toBufferView(a), toBufferView(b), aStack, bStack);
    }

    var areArrays = className === '[object Array]';
    if (!areArrays && isTypedArray$1(a)) {
        var byteLength = getByteLength(a);
        if (byteLength !== getByteLength(b)) return false;
        if (a.buffer === b.buffer && a.byteOffset === b.byteOffset) return true;
        areArrays = true;
    }
    if (!areArrays) {
        if (typeof a != 'object' || typeof b != 'object') return false;
        var aCtor = a.constructor, bCtor = b.constructor;
        if (aCtor !== bCtor && !(isFunction(aCtor) && aCtor instanceof aCtor &&
                                 isFunction(bCtor) && bCtor instanceof bCtor)
                            && ('constructor' in a && 'constructor' in b)) {
          return false;
        }
    }
    // 处理循环引用问题
    aStack = aStack || [];
    bStack = bStack || [];
    var length = aStack.length;
    while (length--) {
        if (aStack[length] === a) return bStack[length] === b;
    }

    aStack.push(a);
    bStack.push(b);

    if (areArrays) {
        length = a.length;
        if (length !== b.length) return false;
        while (length--) {
            if (!eq(a[length], b[length], aStack, bStack)) return false;
        }
    } else {
        var _keys = Object.keys(a), key;
        length = _keys.length;
        if (Object.keys(b).length !== length) return false;
        while (length--) {
            key = _keys[length];
            if (!(b.hasOwnProperty(key) && eq(a[key], b[key], aStack, bStack))) return false;
        }
    }
    aStack.pop();
    bStack.pop();
    return true;
}

最后我们测试一下:

console.log(eq(0, 0));     // true
console.log(eq(0, -0));    // false

console.log(eq(NaN, NaN));  // true
console.log(eq(Object(NaN), Number(NaN)));  // true
console.log(eq('5', new String('5'))); // true

console.log(eq([1, 2], [1, 2])); // true
console.log(eq({ value: 1 }, { value: 1 }));  // true

console.log(eq(new Int32Array([21,31]), new Int32Array([21,31]))); // true

var a = {foo: null};
var b = {foo: null};
a.foo = a;
b.foo = b;
console.log(eq(a, b));     // true

参考资料: JavaScript专题之如何判断两个对象相等

underscore isEqual

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

学习underscore之比较两个元素是否相同 的相关文章

  • 你不知道的javascript之this的全面解析之绑定规则(一)

    1 1 默认绑定 首先介绍的是函数调用类型 独立函数调用 在没有其他应用下的默认规则 首先看以下代码 function foo console log this a var a 2 foo 2 我们可以看到调用foo 时 this a被解析
  • js运算符之一元运算符

    一元运算符 var a 2 a 它就等价于a a 1 先返回结果后运算 上面的语句块就可以写成下面的语句块 它们是等价的 var a 2 a a 1 同理 a 就相当于 a a 1 也是先运算后返回结果 注意 无论是 a a 还是 a a
  • js ---- 排序(1)

    目录 冒泡排序 选择排序 插入排序 冒泡排序 可以先看动图 如果动图就能够理解的话 就不需要看下面的步骤了 比较相邻的元素 如果第一个比第二个大 就交换他们两个 对每一对相邻元素做同样的工作 从开始第一对到结尾的最后一对 在这一点 最后的元
  • js事件 及 事件对象event

    事件类型 鼠标事件 click 点击 dblclick双击 mouseover mouseenter鼠标移入 mouseout mouseleave鼠标离开 onmouseover和onmouseenter的区别 onmouseout和on
  • axios从入门到源码分析

    axios是什么 axios 基于promise封装的ajax库 基于这个类库发送ajax请求 默认就是基于promise管理的 核心还是XMLHttpRequest axios中文文档8 axios中文网 axios axios中GET系
  • JavaScript 中有趣的 9 个常用编码套路

    set对象 数组快速去重 常规情况下 我们想要筛选唯一值 一般会想到遍历数组然后逐个对比 或者使用成熟的库比如lodash之类的 不过 ES6带来了一个新玩意儿 它引入了一个全新的对象类型 Set 而且 如果结合上 展开运算符 我们可以超级
  • 你不知道的javascript之运算符

    学过c php这些语言的同学在学习javascript时候可能会有一些困扰 因为javascript中的 和c或者是php中有很大的差别 因为在javascript中返回的类型并不是布尔值 他返回的而是两个操作值中之一 例如一下例子 var
  • debounce与throttle实现与原理

    前言 前端时间在面试中 面试官让我写一个关于input输入框 并且实时搜索的问题 我就当然用keyup事件来写 写完面试官还是挺满意的 又问我一个问题 如何减少每次输入频繁请求的性能开销 这个我就犯难了 事后 我百度了下 查到了thrott
  • JS-----------Ajax

    目录 传统网站存在的问题 ajax概述 阿贾克斯 异步和同步的区别 Ajax运行原理 ajax的实现步骤 请求报文 Ajax的其他方法和Ajax配置信息 请求传参的几种格式 get post区别 同源政策 扩展 思维导图 传统网站存在的问题
  • .8布尔值、Null和Undefined

    一 布尔值 Boolean 只有两个值 返回值 二 Null Null类型的值只有一个 null 专门用来表示一个空的对象 返回值 三 Undefined Undefined类型的值只有一个 undefined 声明一个变量而不赋值则为该值
  • location protocol 属性(http、https)

    location protocol 属性 protocol 属性是一个可读可写的字符串 可设置或返回当前 URL 的协议 语法 location protocol location protocol http 使用场景 vue配置api地址
  • 根据三角形的三条边长(长、中、短三条边),来判断三角形类型

    根据三角形的三条边长 长 中 短三条边 来判断三角形类型 注意 1 一个三角形的边应该都为正数 2 一个三角形的边都应该满足三角形条件 两边之和大于第三边 如果有两边的平方和比第三边的平方小 它就是钝角三角形 比如 a a b b
  • Canvas 画布随机变换背景色

  • JS设计模式

    目录 前言 单例设计模式 Command 命令模式 Constructor构造器模式 工厂模式Factory 发布订阅设计模式 publish subscribe 观察者模式 中介者模式 前言 JS设计模式是一种思想 更规范更合理的管理代码
  • 数组及常用方法

    思维导图 数组的基本概念 什么是数组 数组是存储一个或多个数据的容积 它是一组内存空间 通常用来批量处理数据 这组内存空间的名字叫做数组2 数组的特点 对齐自身储存的数据并没有什么要求 无论是数量还是类型 数组中的每一项可以是任意一种数据类
  • 你不知道的javascript之函数作用域和块作用域(一)

    立即执行函数表达式 IIFE 1 使用匿名函数表达式 var a 2 function IIFE var a 3 console log a 3 console log a 2 2 当作函数调用并传递参数进去 var a 2 functio
  • 工厂模式与构造函数模式的区别

    目录 一 工厂模式 二 构造函数模式 一 工厂模式 1 工厂模式其实就是普通函数 2 可以解决创建多个类似对象的问题 3 没有解决对象标识问题 即新创建的对象是什么类型 工厂模式 function createPerson name age
  • AJAX核心基础知识之倒计时抢购案例

    倒计时 分析 两个时间 目标时间 当前时间 目标时间 当前时间 计算时间差中包含多少小时 多少分钟 多少秒 每间隔一秒钟重新获取当前时间 定时器 重算时间 核心问题 1当前时间不可以获取客户端本地的 本地的时间客户可以肆意修改 获取服务器的
  • 堆栈内存和闭包

    思维导图 堆栈内存小科普 1 js中的内存分为 堆内存和栈内存 堆内存 只要用来存储引用数据类型的值 对象存的是键值对 函数存的是字符串 栈内存 供js运行的环境 函数执行 存基本数据类型的值 堆栈内存的释放问题 我们每次给变量存值或者执行
  • JS中的声明提升

    变量声明提升 使用var关键字声明的变量 会在所有的代码执行之前被声明 如果声明变量时未使用var关键字 变量不会被提前声明 console log a 输出undefined var a 1 等同于 var a console log a

随机推荐

  • OpenCV自适应阈值化函数adaptiveThreshold

    图像阈值化的一般目的是从灰度图像中分享目标区域和背景区域 然而仅仅通过设定固定阈值很难达到理想的分割效果 在实际应用中 我们可以通过某个像素的邻域以某种方法确定这个像素应该具有的阈值 进而保证图像中各个像素的阈值会随着周期围邻域块的变化而变
  • EasyExcel的简单导出

    EasyExcel的简单导出 Controller层代码 GetMapping download public void download String name HttpServletResponse response fileManag
  • 5、安全理论与框架-企业架构模型(EA)-业务组件模型(IBM CBM)

    一 背景 CBM component business model 组件化业务模型或叫业务组件模型 是IBM在2003年提出的 当时的大背景 公司内 外专业化 CBM是IBM做业务架构的一个重要方法论 就是把业务描述成一个个独立的小块 我们
  • 面试题一:前端去重方法汇总你知道多少?

    题记 我们项目中有很多的业务是需要去重的 那么下面是常用的一些去重的一些方法 用indexOf方法去重 新建一个空数组 遍历需要去重的数组 将数组元素存入新数组中 存放前判断数组中是否已经含有当前元素 没有则存入 此方法也无法对NaN去重
  • 上采样,下采样,过采样,欠采样的区别

    上下是方法 过欠是现象 上采样 upsampling 应该就是内插 补零滤波 下采样 downsampling 应该就是抽取 过采样就是采样频率大于两倍的信号最高频率 欠采样就是采样频率小于两倍的信号最高频率 欠采样失真仅仅是对基带信号而言
  • 源码编译llvm Error 记录

    cmake G Unix Makefiles llvm DLLVM ENABLE PROJECTS bolt clang clang tools extra compiler rt cross project tests libclc l
  • OceanBase:编译、安装和配置手册

    概述 OceanBase是 一个高性能的分布式表格系统 提供类似BigTable的性能和扩展性 但表格中保存的是强类型的数据 比如integer string datetime等 它使用C 编写 运行于64位Linux环境下 生产环境下需要
  • Ubuntu20.04编译安装opencv3.2和opencv_contrib-3.2

    图像特征提取中需要用到SIFT等算法 因此不得不安装从源码编译安装opencv contrib 网上有很多教程 但是在不同的环境下多少会出现一些错误 针对Ubuntu20 04 gcc 7环境下对opencv opencv contrib编
  • ios内嵌h5点击输入框页面放大

    首先咱们这个是基于修改meta没卵用的情况 去修改这个input的style把font size改成16px 我的机型是xr 自己用了反正有效 希望对你有帮助
  • 实战:tomcat版本升级

    tomcat版本升级 由原来的apache tomcat 7 0 96升级到apache tomcat 7 0 109 版本 1 先把原来的备份 mv apache tomcat 7 0 96 1 apache tomcat 7 0 96
  • 01-Kafaka

    1 Kafka 2 的安装与配置 1 上传kafka 2 12 1 0 2 tgz到服务器并解压 tar zxf kafka 2 12 1 0 2 tgz C opt 2 配置环境变量并更新 编辑profile配置文件 vim etc pr
  • 春招大厂面试升级笔记!光CRUD已经不能满足了

    大厂的面试已经升级 早就不满足于CRUD了 今天给大家分享的就是大厂最近升级的面试小 炒 全篇共计为大家详细划分了19个部分 字数超过了20W字 面试题数量超过了1500道 同时结合了大量的实例和代码 涵盖了 Java基础 并发编程 JVM
  • python中sort()和sorted()排序函数用法详解

    python中对数据的排序主要使用sort 和sorted 方法 1 sort 方法 语法结构 列表序列 sort key None reverse False 注意 reverse 表示排序规则 reverse True 降序 rever
  • typora插件_Typora + PicGo 编写博客的神器

    一 软件版本要求 typora 0 9 93 使用最新版本即可 下载链接 https www typora io PicGo 2 2 0以上 也是最好用最新版的 下载链接 https github com Molunerfinn PicGo
  • stable diffusion实践操作-embedding(TEXTUAL INVERSION)

    系列文章目录 本文专门开一节写图生图相关的内容 在看之前 可以同步关注 stable diffusion实践操作 文章目录 系列文章目录 前言 1 embeddding的功能 2 如何去下载 https civitai com models
  • 粽子SHOP-粽子商城官网-一款简洁大气的官网源码

    介绍 一款简洁大气的官网源码 无后台 直接上传服务器或主机即可 可自行编辑内容非常实用的个人介绍页面 大家需要的自行下载 网盘下载地址 http zijieyunpan com OSdKfaj4W2z0 图片
  • FPGA时序分析约束

    时序分析约束 时序分析 时序分析的目的就是通过分析fpga设计各个寄存器之间的数据和时钟传输路径 来分析数据延迟和时钟延迟之间的关系 保证整个系统中的所有寄存器都能正确存储数据 时序约束 两个作用 1 告知EDA软件 该设计需要达到怎么样的
  • 程序员如何逆袭,达到财富自由?

    首先 先给程序员做一个定义 我定义的是 一个普通的程序员 家里普普通通 自己也没在大厂 一个中等公司 拿着两万左右的薪水 年终奖一般发不超过两个月 这样的程序员 逆袭的路有三条 背题 去大厂 混到高P拿股票 劲熬 找到靠谱的创业公司 拿到期
  • Python实现汽车油耗预测_基于Tensorflow2.X

    目录 一 开发环境 二 代码实现 2 1 准备操作 2 1 1 导入所需模块 2 1 2 matplotlib无法正常显示中文的解决方案 若无此情况可跳过 2 2 加载数据集 2 3 数据处理 2 3 1 数据清洗 2 3 2 数据转换 2
  • 学习underscore之比较两个元素是否相同

    underscore1 11 0 中判断两个参数相同的函数为isEqual isEqual 函数认为以下相等 0 与 0 不相等 NaN 与 NaN相等 a i 与 new RegExp a i 相等 5 与 new String 5 相等