• [技术干货] Javascript Object.create 用法详解
    在 JavaScript 中,Object.create() 是一个静态方法,它创建一个新对象,使用现有的对象来提供新创建的对象的 __proto__。换句话说,它允许你创建一个对象,该对象继承自另一个对象的属性和方法。Object.create 详解语法Object.create(proto[, propertiesObject])proto:新创建对象的原型对象。propertiesObject(可选):可选属性描述符,这些属性描述符将被添加到新创建的对象中。返回值一个新对象,其原型(即内部 [[Prototype]] 属性)由参数 proto 提供。如果参数 proto 不是对象或者为 null,则新创建的对象将不会有原型(即它将不会继承任何属性和方法)。在 ES5 规范中,如果参数 proto 是 undefined 或 null,则新对象的原型会被设置为 Object.prototype 的原型,但这是一个已废弃的行为,并且在 ES6 及以后的版本中,如果 proto 是 null 或 undefined,将会抛出一个 TypeError。特性原型继承:Object.create() 允许你创建一个对象,该对象继承自指定的原型对象。属性定义:通过第二个参数,你可以在新对象上定义属性,并指定这些属性的特性(如可枚举性、可配置性、可写性等)。减少全局命名空间污染:使用 Object.create() 而不是直接通过字面量创建对象,可以减少全局命名空间中的对象数量,因为你可以创建一个具有特定原型的对象,而不需要将属性添加到全局对象(如 Object.prototype)上。示例// 创建一个原型对象 const person = { isHuman: false, printIntroduction: function() { console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`); } }; // 创建一个新对象,其原型是 person const me = Object.create(person); // "name" 和 "isHuman" 是 me 的属性 me.name = 'John'; // "name" 是 me 的属性,而不是 person 的属性 me.isHuman = true; // 改变 me 的 isHuman 属性,不会影响到 person me.printIntroduction(); // 输出: "My name is John. Am I human? true" // 由于 person 没有 "name" 属性,所以访问 person.name 会返回 undefined console.log(person.name); // 输出: undefined在这个例子中,me 是通过 Object.create(person) 创建的,它继承了 person 的属性和方法。但是,me 有自己的 name 和 isHuman 属性,这些属性与 person 的属性是分开的。使用属性描述符你还可以使用属性描述符来定义新对象的属性:const newPerson = Object.create(person, { name: { value: 'Jane', writable: false, enumerable: true, configurable: true } }); console.log(newPerson.name); // 输出: Jane newPerson.name = 'Doe'; // 尝试修改 name 属性,但由于 writable: false,所以这里会静默失败(严格模式下会抛出错误) console.log(newPerson.name); // 仍然输出: Jane在这个例子中,newPerson 的 name 属性被设置为不可写(writable: false),因此尝试修改它的值会失败。注意事项使用 Object.create() 时,请确保提供的原型对象(proto)是有效的对象,否则将会抛出 TypeError。在 ES5 及以后的版本中,Object.create() 是创建具有指定原型的新对象的标准方法。在 ES5 之前,你需要使用其他方法(如构造函数或 __proto__ 属性)来实现类似的功能。当你使用 Object.create() 创建对象时,请考虑属性的可枚举性、可配置性和可写性,以确保你的对象符合预期的行为。
  • [技术干货] Javascript Object.call 用法详解
    在 JavaScript 中,同样没有直接名为 Object.call 的方法。你可能是在提到 Function.prototype.call,这是一个函数对象的方法,允许你调用一个函数,同时设置函数体内 this 的值和在函数体开始执行之前提供初始的参数。Function.prototype.call 详解语法func.call([thisArg[, arg1, arg2, ...]])thisArg(可选):在 func 函数运行时使用的 this 值。注意,在非严格模式下,如果指定的值为 null 或 undefined,则会自动替换为全局对象(在浏览器中通常是 window),而原始值会被包装。arg1, arg2, ...(可选):调用 func 函数时传入的参数。返回值调用函数 func 的返回值。特性改变 this 指向:call 方法允许你显式地设置调用函数时 this 的值。立即执行:与 bind 不同,call 会立即执行函数。参数传递:你可以通过 call 方法传递任意数量的参数给被调用的函数。示例function greet(greeting, punctuation) { console.log(greeting + ', ' + this.name + punctuation); } const person = { name: 'Alice' }; greet.call(person, 'Hello', '!'); // 输出: Hello, Alice!在这个例子中,greet 函数通过 call 方法被调用,this 在 greet 函数内部被设置为 person 对象,并且 'Hello' 和 '!' 分别作为参数传递给 greet 函数。与 apply 的比较Function.prototype.apply 方法与 call 非常相似,不同之处在于 apply 接受参数的方式:call 方法接受若干个参数,第一个参数是 this 的值,后面的参数是传递给函数的参数。apply 方法接受两个参数,第一个参数是 this 的值,第二个参数是一个数组或类数组对象,表示传递给函数的参数。greet.apply(person, ['Hello', '!']); // 输出: Hello, Alice!在这个例子中,greet 函数通过 apply 方法被调用,this 被设置为 person 对象,并且参数 ['Hello', '!'] 被展开并传递给 greet 函数。注意事项使用 call 或 apply 时,要确保第一个参数(thisArg)是一个对象,或者 null 或 undefined(在非严格模式下会被替换为全局对象)。call 和 apply 是非常强大的方法,允许你动态地改变函数的 this 值和参数,但它们也可能导致代码难以理解和维护,特别是在复杂的代码库中。在类(class)的方法中,通常不需要使用 call 或 apply,因为类的方法在调用时会自动绑定到类的实例上。然而,在函数式编程或需要动态改变 this 指向的场景中,call 和 apply 非常有用。
  • [技术干货] Javascript Object.bind用法详解
    在 JavaScript 中,实际上并没有一个名为 Object.bind 的方法。你可能是在提到 Function.prototype.bind,这是一个非常重要的函数方法,用于创建一个新的函数,这个新函数的 this 值会被设置为指定的值,并且在调用新函数时,其前几个参数会被预设为指定的值。Function.prototype.bind 详解语法fun.bind(thisArg[, arg1[, arg2[, ...]]])thisArg:在 fun 函数运行时使用的 this 值。注意,thisArg 在非严格模式下指定为 null 或 undefined 时会自动替换为全局对象(浏览器中通常是 window),而原始值会被包装。arg1, arg2, ...(可选):当调用新函数时,这些参数将置于实参之前提供给 fun 函数。返回值返回一个新的函数,这个函数的 this 永远被绑定到 thisArg 上,并且在其运行时,前置参数将排在提供的实参之前。特性改变 this 指向:bind 方法允许你显式地设置一个函数的 this 值,无论你如何调用这个函数,其 this 值都保持不变。参数预设:除了改变 this 指向,bind 还可以预设函数的前几个参数,这些参数在函数调用时会被放置在实参之前。不会立即执行:与 call 和 apply 不同,bind 不会立即执行函数,而是返回一个新的函数,这个新函数在被调用时会执行原函数。示例function greet(greeting, punctuation) { console.log(greeting + ', ' + this.name + punctuation); } const person = { name: 'Alice' }; const greetAlice = greet.bind(person, 'Hello'); greetAlice('!'); // 输出: Hello, Alice!在这个例子中,greet 函数被绑定到 person 对象上,并且 'Hello' 被预设为第一个参数。因此,当调用 greetAlice('!') 时,this 在 greet 函数内部被设置为 person 对象,并且 'Hello' 和 '!' 分别作为 greeting 和 punctuation 参数传递给 greet 函数。注意事项使用 bind 创建的新函数与原函数在功能上完全相同,只是 this 值和预设参数有所不同。由于 bind 返回的是一个新函数,因此它不会立即执行原函数。在类(class)的构造函数中,通常不会使用 bind,因为类的方法在调用时会自动绑定到类的实例上(除非你在类的方法中显式地使用了箭头函数,这会导致 this 绑定到定义该方法的上下文中,而不是类的实例)。希望这个详解能帮助你更好地理解 Function.prototype.bind 的用法!
  • [技术干货] Javascript Object.apply 用法详解
    在 JavaScript 中,实际上并不存在 Object.apply 这个方法。你可能是在寻找 Object.assign()、Function.prototype.apply() 或者其他某个方法,但是 Object.apply 确实不是一个标准的 JavaScript 方法。不过,我可以为你解释 Function.prototype.apply() 的用法,因为这是一个非常常见且重要的 JavaScript 方法。Function.prototype.apply()apply() 方法调用一个具有给定 this 值的函数,以及以一个数组(或类数组对象)的形式提供的参数。语法func.apply(thisArg, [argsArray])thisArg:在 func 函数运行时使用的 this 值。注意,null 和 undefined 会被自动替换为全局对象(在浏览器中是 window),而原始值会被包装。[argsArray]:一个数组或者类数组对象,其中的数组元素将作为单独的参数传给 func 函数。如果该参数的值为 null 或 undefined,则表示不需要传入任何参数。返回值函数调用的结果。示例function sum(a, b) { return a + b; } // 使用 apply 调用 sum 函数,并传入参数 const numbers = [1, 2]; const result = sum.apply(null, numbers); console.log(result); // 输出: 3在这个例子中,sum.apply(null, numbers) 相当于调用 sum(1, 2),因为 numbers 数组中的元素被作为单独的参数传给了 sum 函数。与 call() 的区别apply() 和 call() 方法的作用相似,区别在于 apply() 接受的是参数数组,而 call() 需要逐个列举参数。// 使用 call 调用 sum 函数,并传入参数 const resultWithCall = sum.call(null, 1, 2); console.log(resultWithCall); // 输出: 3在这个例子中,sum.call(null, 1, 2) 和 sum.apply(null, [1, 2]) 的效果是相同的。使用场景当你有一个数组(或类数组对象),并且想将其元素作为参数传递给一个函数时,可以使用 apply()。在编写通用函数时,如果你不确定会接收到多少个参数,或者参数是以数组形式给出的,那么 apply() 会非常有用。在一些情况下,你可能需要改变 this 的指向,这时 apply() 和 call() 都是很有用的工具。
  • [技术干货] Javascript Object.assign 用法详解
    Object.assign() 是 JavaScript ES6 (ECMAScript 2015) 引入的一个静态方法,用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它返回目标对象。语法Object.assign(target, ...sources)target:目标对象——将要接收新属性的对象。sources:源对象——一个或多个对象,其可枚举属性将被复制到目标对象。返回值返回目标对象(修改后的对象)。特性浅拷贝:Object.assign() 只会拷贝源对象自身的和可枚举的属性到目标对象,而不会拷贝其原型链上的属性。并且,它是浅拷贝,即如果源对象的属性值是对象,那么目标对象对应的属性值将引用同一个对象。同名属性覆盖:如果源对象中有多个同名属性,后面的属性会覆盖前面的属性。不可枚举属性:Object.assign() 不会拷贝源对象的不可枚举属性(例如使用 Object.defineProperty() 定义的属性,且 enumerable 属性设为 false)。原始数据类型:如果目标对象不是对象(例如,原始数据类型),Object.assign() 会将其转换为对象,然后返回这个新对象。示例基本用法const target = { a: 1 }; const source1 = { b: 2 }; const source2 = { c: 3 }; const returnedTarget = Object.assign(target, source1, source2); console.log(target); // 输出: { a: 1, b: 2, c: 3 } console.log(returnedTarget); // 输出: { a: 1, b: 2, c: 3 } // 注意:目标对象被修改,并且返回的也是目标对象浅拷贝const obj1 = { a: { b: 1 } }; const obj2 = Object.assign({}, obj1); obj2.a.b = 2; console.log(obj1.a.b); // 输出: 2 // 由于是浅拷贝,obj1 和 obj2 中的 a 属性指向同一个对象合并对象const defaults = { a: 1, b: 2 }; const options = { b: 3, c: 4 }; const finalOptions = Object.assign({}, defaults, options); console.log(finalOptions); // 输出: { a: 1, b: 3, c: 4 } // 注意到 b 属性被 options 中的值覆盖了处理原始数据类型const target = 'abc'; const result = Object.assign(target, { a: 1 }); console.log(result); // 输出: { 0: 'a', 1: 'b', 2: 'c', a: 1 } // 注意:目标字符串被转换为对象,并且属性被添加不可枚举属性const source = Object.create(Object.prototype, { foo: { value: 1, enumerable: false, writable: true, configurable: true }, bar: { value: 2, enumerable: true, writable: true, configurable: true } }); const target = {}; Object.assign(target, source); console.log(target); // 输出: { bar: 2 } // 不可枚举属性 foo 不会被拷贝注意事项使用 Object.assign() 时,要确保目标对象是可以被修改的对象,否则会出现不可预期的行为。浅拷贝的特性可能导致数据污染或意外的数据共享,特别是在处理嵌套对象时。实际应用Object.assign() 在实际应用中非常广泛,可以用于对象合并、配置选项的默认值和覆盖、对象属性的复制等场景。
  • [技术干货] Javascript 深拷贝和浅拷贝
    在JavaScript中,深拷贝和浅拷贝是用于复制对象的两种不同方式,它们各自有着独特的原理和应用场景。一、深拷贝的原理及应用原理: 深拷贝是指创建一个完全独立于原始对象的副本,包括对象的所有嵌套属性和数组元素。深拷贝会递归地遍历原始对象,将其所有属性和元素复制到新的对象中,确保新对象与原始对象完全分离。这意味着对深拷贝创建的对象进行修改不会影响原始对象。应用: 深拷贝适用于需要完全独立的副本,并保持与原始对象的分离的情况。当需要在两个独立的对象之间共享或传递数据时,使用深拷贝可以确保数据的独立性,避免意外的共享和修改。当需要对对象进行修改或转换,但不希望影响原始对象时,可以使用深拷贝创建一个可安全操作的副本。二、浅拷贝的原理及应用原理: 浅拷贝是指创建一个新的对象,新对象的内容是原始对象的引用。如果原始对象中有引用类型的属性,那么浅拷贝后的新对象中的这些属性仍然会指向原始对象中的相应属性。换句话说,浅拷贝只复制了对象的引用,而不复制引用指向的内容。应用: 浅拷贝适用于需要共享数据、降低内存占用和提高性能的情况。当需要在两个对象之间共享数据,且希望对其中一个对象进行修改时,可以使用浅拷贝。这样做可以减少内存占用和提高性能,因为不需要创建完全独立的副本。当只需要访问对象的一部分属性或元素时,浅拷贝可以提供便利,避免复制整个对象的开销。三、深拷贝与浅拷贝的对比及选择对比:深拷贝会递归地复制对象的所有属性和元素,确保新对象与原始对象完全分离。而浅拷贝只复制了对象的引用,不复制引用指向的内容。对深拷贝后的对象进行修改不会影响原始对象,而对浅拷贝后的对象进行修改(如果修改了引用类型的属性),则可能会影响原始对象。选择:如果需要保持数据的独立性,避免意外的共享和修改,应选择深拷贝。如果需要共享数据、降低内存占用和提高性能,且不需要完全独立的副本,可以选择浅拷贝。四、实现深拷贝和浅拷贝的方法深拷贝的实现方法:使用 JSON.parse(JSON.stringify()) 方法:这是目前最常用的深拷贝方法之一,但它无法拷贝函数、正则表达式等特殊对象,也无法处理循环引用的情况。手动递归复制对象及其属性:通过递归地复制对象的每个属性(包括嵌套对象和数组)来实现深拷贝。浅拷贝的实现方法:使用对象展开运算符(...):可以快速简洁地进行对象和数组的浅拷贝。使用 Object.assign() 方法:可以将一个或多个源对象的属性复制到目标对象中,并返回目标对象。对于数组,可以使用 Array.prototype.concat() 或 Array.prototype.slice() 方法进行浅拷贝。
  • [技术干货] Javascript Object.entries() 用法详解
    Object.entries() 定义Object.entries() 是 JavaScript 的一个内置方法,它返回一个给定对象自身可枚举属性的键值对数组,其排列与通过手动遍历对象属性返回的顺序一致(区别在于 for...in 循环枚举原型链中的属性)。数组中每个元素都是一个包含两个元素的数组,第一个元素是键名,第二个元素是键值。用法详解语法:Object.entries(obj)obj:要返回其键值对的对象。返回值:一个数组,其元素是键值对数组,每个键值对数组的第一个元素是键名(字符串类型),第二个元素是键值(可以是任何类型)。示例代码:const obj = { foo: 'bar', baz: 42 }; console.log(Object.entries(obj)); // 输出: [['foo', 'bar'], ['baz', 42]] // 转换对象到 Map const map = new Map(Object.entries(obj)); console.log(map); // 输出: Map(2) { 'foo' => 'bar', 'baz' => 42 } // 遍历对象的键值对 for (const [key, value] of Object.entries(obj)) { console.log(`${key}: ${value}`); } // 输出: // foo: bar // baz: 42 // 使用 Object.entries() 转换对象并过滤键值对 const filteredEntries = Object.entries(obj).filter(([key, value]) => typeof value === 'string'); console.log(filteredEntries); // 输出: [['foo', 'bar']] // 将键值对数组转换回对象 const newObj = Object.fromEntries(filteredEntries); console.log(newObj); // 输出: { foo: 'bar' }注意事项:Object.entries() 只返回对象自身的可枚举属性,不包括从原型链上继承的属性。返回的数组中的键值对顺序与通过手动遍历对象属性时的顺序一致。可以使用 for...of 循环来遍历 Object.entries() 返回的数组。Object.entries() 方法可以与 Object.fromEntries() 方法结合使用,以实现对象与键值对数组之间的转换。使用场景:当需要将对象的键值对转换为数组进行处理时,可以使用 Object.entries()。在需要遍历对象的键值对时,Object.entries() 提供了一种更直观、更易于理解的方式。在处理对象时,如果需要过滤、映射或转换键值对,可以先使用 Object.entries() 将对象转换为数组,然后进行相应的操作,最后使用 Object.fromEntries() 将数组转换回对象(如果需要的话)。
  • [技术干货] Javascript Object.is() 用法详解
    Object.is() 定义Object.is() 是 JavaScript 中的一个内置方法,用于比较两个值是否严格相等(即 === 比较的结果),但在处理某些特殊情况时,它提供了与 === 不同的行为。具体来说,Object.is() 在以下两个方面与 === 存在差异:+0 和 -0 被认为是不相等的。NaN 与 NaN 被认为是相等的。Object.is() 方法提供了一种更精确的方式来比较两个值是否相等,特别是在处理数字的特殊值时。用法详解语法:Object.is(value1, value2)value1:要比较的第一个值。value2:要比较的第二个值。返回值:如果两个值严格相等(考虑到了 +0 和 -0 的区别以及 NaN 的特殊情况),则返回 true。否则,返回 false。示例代码:console.log(Object.is('foo', 'foo')); // true console.log(Object.is({}, {})); // false,对象比较的是引用 console.log(Object.is(+0, -0)); // false,+0 和 -0 被视为不相等 console.log(Object.is(-0, -0)); // true console.log(Object.is(NaN, 0/0)); // true,NaN 与 NaN 被视为相等 console.log(Object.is(NaN, NaN)); // true console.log(Object.is(42, 42)); // true console.log(Object.is(true, true)); // true console.log(Object.is(false, false)); // true console.log(Object.is(null, null)); // true console.log(Object.is(undefined, undefined)); // true console.log(Object.is([], [])); // false,数组比较的是引用 console.log(Object.is([], [])); // false,同上 console.log(Object.is(function() {}, function() {})); // false,函数比较的是引用特殊情况说明:Object.is(+0, -0) 返回 false,因为 +0 和 -0 虽然被认为是相等的(使用 ===),但在 Object.is() 中它们被视为不相等。Object.is(NaN, NaN) 返回 true,因为 NaN 与 NaN 在 Object.is() 中被认为是相等的,这与 === 不同,因为在 === 中 NaN !== NaN。使用场景:当需要精确比较两个值是否相等时,特别是在处理数字的特殊值(如 +0、-0 和 NaN)时,可以使用 Object.is()。在编写需要精确判断相等性的算法或逻辑时,Object.is() 可以提供比 === 更准确的结果。总的来说,Object.is() 提供了一种更严格、更精确的相等性比较方法,特别适用于处理 JavaScript 中的一些特殊情况。
  • [技术干货] Javascript Object.keys() Object.values() 用法详解
    Object.keys()定义: Object.keys() 是一个JavaScript内置函数,用于返回一个由对象自身的(不包括原型链上的)所有可枚举属性组成的数组。数组中属性名的排列顺序与通过手动循环对象属性时的顺序一致。使用场景:当需要遍历对象的可枚举属性时,可以使用 Object.keys() 获取属性名数组,然后进行遍历。在处理对象时,如果需要获取对象的所有键(属性名),可以使用 Object.keys()。在需要判断对象是否包含某个属性时,可以先使用 Object.keys() 获取属性名数组,然后检查数组中是否包含该属性名。用法详解:// 示例对象 const person = { name: "张三", age: 25, sex: "男", getName: function() {} }; // 使用 Object.keys() 获取对象的所有可枚举属性名 const keys = Object.keys(person); console.log(keys); // 输出: ["name", "age", "sex", "getName"] // 遍历对象的所有可枚举属性 keys.forEach(key => { console.log(`${key}: ${person[key]}`); });对于数组和字符串,Object.keys() 会返回其索引值组成的数组。// 示例数组 const arr = [1, 2, 3, 4, 5]; console.log(Object.keys(arr)); // 输出: ["0", "1", "2", "3", "4"] // 示例字符串 const str = "javascript"; console.log(Object.keys(str)); // 输出: ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]Object.values()定义: Object.values() 方法返回一个给定对象自身的所有可枚举属性值的数组,值的顺序与使用 for…in 循环的顺序相同(区别在于 for-in 循环枚举原型链中的属性,而 Object.values() 不包括原型链上的属性)。使用场景:当需要获取对象的所有值时,可以使用 Object.values()。在处理对象时,如果需要遍历对象的所有值,可以先使用 Object.values() 获取值数组,然后进行遍历。在需要将对象的值转换为数组进行进一步处理时,可以使用 Object.values()。用法详解:// 示例对象 const obj = { passport: '护照', mobile: '手机号', phone: '固定电话', email: '电子邮箱' }; // 使用 Object.values() 获取对象的所有可枚举属性值 const values = Object.values(obj); console.log(values); // 输出: ["护照", "手机号", "固定电话", "电子邮箱"] // 遍历对象的所有可枚举属性值 values.forEach(value => { console.log(value); });对于数组,Object.values() 会返回其顺序成员组成的数组。// 示例数组 const arr = ['x', 'y', 'z']; console.log(Object.values(arr)); // 输出: ["x", "y", "z"]总结Object.keys() 用于获取对象的所有可枚举属性名组成的数组。Object.values() 用于获取对象的所有可枚举属性值组成的数组。两者都不包括原型链上的属性。在处理对象、数组和字符串时,这两个方法都非常有用。
  • [技术干货] JavaScript里的循环方法:forEach,for-in,for-of
    在JavaScript中,有多种方法可以用来遍历数组或对象的属性。以下是三种常见的循环方法:forEach、for-in 和 for-of。每种方法都有其特定的用途和适用场景。1. forEachforEach 方法用于遍历数组中的每一个元素,并为每个元素执行一次提供的回调函数。语法:array.forEach(function(currentValue, index, array) { // 你的迭代逻辑 });示例:const numbers = [1, 2, 3, 4, 5]; numbers.forEach((number, index) => { console.log(`Index: ${index}, Value: ${number}`); });特点:forEach 不会改变原数组。没有返回值(返回 undefined)。不能使用 break 或 continue 语句来中断循环。2. for-infor-in 循环用于遍历对象的可枚举属性(包括原型链上的属性,除非使用 hasOwnProperty 方法进行过滤)。语法:for (let key in object) { // 你的迭代逻辑 }示例:const person = { name: 'Alice', age: 25, city: 'New York' }; for (let key in person) { if (person.hasOwnProperty(key)) { console.log(`${key}: ${person[key]}`); } }特点:遍历对象的可枚举属性。枚举顺序不是按照属性在对象中出现的顺序。可以遍历到对象原型链上的属性。3. for-offor-of 循环用于遍历可迭代对象(包括数组、字符串、Map、Set 等)的值。语法:for (let value of iterable) { // 你的迭代逻辑 }示例:const numbers = [1, 2, 3, 4, 5]; for (let number of numbers) { console.log(number); } // 字符串 const str = 'Hello'; for (let char of str) { console.log(char); }特点:直接遍历可迭代对象的值。适用于数组、字符串、Map、Set 等。可以使用 break、continue 和 return 语句来中断循环。总结**forEach**:适用于遍历数组,不能中断循环,没有返回值。**for-in**:适用于遍历对象的可枚举属性,包括原型链上的属性(需要过滤)。**for-of**:适用于遍历可迭代对象的值,可以中断循环,适用于数组、字符串、Map、Set 等。选择哪种循环方法取决于你的具体需求和数据类型。
  • [技术干货] JS 节流,防抖
    节流(Throttling)和防抖(Debouncing)是两种常用的优化函数执行频率的技术。节流(Throttling): 控制一定时间内函数的执行次数。function throttle(fn, wait) { let timeout = null; return function() { let context = this; let args = arguments; if (!timeout) { timeout = setTimeout(() => { fn.apply(context, args); timeout = null; }, wait); } }; }// 使用示例 window.addEventListener('resize', throttle(function() { console.log(window.innerWidth, window.innerHeight); }, 200));防抖(Debouncing): 当持续触发事件时,一定时间内只执行最后一次。function debounce(fn, wait) { let timeout = null; return function() { let context = this; let args = arguments; if (timeout) clearTimeout(timeout); let callNow = !timeout; timeout = setTimeout(() => { timeout = null; }, wait); if (callNow) fn.apply(context, args); }; }// 使用示例 window.addEventListener('resize', debounce(function() { console.log(window.innerWidth, window.innerHeight); }, 200));节流通过设置一个timeout控制函数执行的频率,防抖通过清除已经设置的timeout再次执行函数。
  • [技术干货] Javascript 生产环境防止被调试
    在Javascript生产环境中防止代码被调试是一个复杂但重要的任务,它有助于保护代码逻辑、敏感数据和业务逻辑不被轻易窥探或篡改。以下是一些常用的方法和策略:1. 代码混淆与加密代码混淆:通过改变代码的结构而不改变其功能,使得代码难以被人类阅读和理解。这包括改变变量名、函数名、删除空格和注释、改变控制流等。混淆后的代码对于调试器来说更难分析。代码加密:将JavaScript代码进行加密处理,然后在运行时通过解密函数来执行。这增加了分析和调试的难度,因为调试器无法直接看到原始的代码逻辑。需要注意的是,加密应确保是可逆的,以便在需要时能够正确解密并执行代码。2. 使用防调试技术检测调试器:通过检测浏览器是否开启了调试工具,如检查特定的全局变量或函数是否被修改或注入。一旦发现调试器,可以采取相应的措施,如抛出错误、终止代码执行或重定向页面等。自毁代码:在检测到调试器时,让代码自我销毁或变得不可执行。这可以通过抛出异常、修改关键变量或函数、甚至完全清空代码内容来实现。3. 利用JavaScript特性try-catch语句:在敏感代码块中使用try-catch语句来捕获异常,并防止调试器中断程序的执行。这可以防止调试器在敏感代码处停止执行。eval函数:虽然eval函数的使用存在安全风险,但在某些情况下,它可以用来隐藏代码的执行逻辑,使得调试器难以追踪。然而,需要谨慎使用,因为eval函数会执行传入的任何字符串作为代码,这可能导致安全问题。4. 服务器端验证与防护敏感操作验证:对于涉及敏感数据的操作,如数据库查询、API调用等,应在服务器端进行严格的验证和防护。确保客户端的请求符合预期,并且无法被轻易伪造或篡改。监控与日志:对生产环境中的JavaScript代码执行情况进行监控,并记录详细的日志。这有助于及时发现并响应潜在的调试或攻击行为。5. 外部库和工具使用防调试库:有一些JavaScript库可以帮助识别和防止调试器的使用,如AntiDebug.js和Detectify等。这些库通常提供了丰富的API和配置选项,可以根据实际需求进行定制。6. 安全最佳实践遵循安全编码规范:遵循业界公认的安全编码规范,如OWASP Top 10等,以减少代码中的安全漏洞和弱点。定期安全审计:对生产环境中的JavaScript代码进行定期的安全审计,以发现和修复潜在的安全问题。需要注意的是,尽管这些方法可以在一定程度上提高JavaScript代码的安全性并防止被调试,但它们并不是绝对安全的。因此,在开发过程中应综合考虑多种策略和方法,以确保代码的安全性。同时,也应持续关注最新的安全漏洞和攻击技术,以便及时调整和优化防护措施。
  • [技术干货] css marginTop减去自身高度的一半
    在CSS中,直接通过marginTop属性减去元素自身高度的一半并不是直接支持的,因为CSS本身并不提供直接计算元素尺寸(如高度)并在样式中动态应用这些计算结果的机制。不过,你可以通过一些技巧来实现类似的效果,尤其是在你想要垂直居中某个元素时。方法一:使用Flexbox如果你的布局允许,使用Flexbox是最简单且最强大的方法之一来实现垂直居中。你不需要知道元素的确切高度,Flexbox会为你处理这些。<div class="flex-container"> <div class="centered-child">我是居中的元素</div> </div> <style> .flex-container { display: flex; align-items: center; /* 垂直居中 */ justify-content: center; /* 水平居中(如果需要)*/ height: 100vh; /* 示例:容器高度为视窗高度 */ } .centered-child { /* 你的样式 */ } </style>方法二:使用CSS Grid与Flexbox类似,CSS Grid也提供了强大的布局能力,包括垂直居中。<div class="grid-container"> <div class="centered-child">我是居中的元素</div> </div> <style> .grid-container { display: grid; place-items: center; /* 简写,同时设置justify-items和align-items为center */ height: 100vh; /* 示例:容器高度为视窗高度 */ } .centered-child { /* 你的样式 */ } </style>方法三:使用绝对定位和transform(适用于已知或未知高度)如果你需要更传统的解决方案,并且希望手动控制元素的位置,可以使用绝对定位和transform属性。这种方法的好处是,它不需要你事先知道元素的确切高度。<div class="positioned-container"> <div class="absolutely-centered">我是居中的元素</div> </div> <style> .positioned-container { position: relative; height: 100vh; /* 示例:容器高度 */ } .absolutely-centered { position: absolute; top: 50%; transform: translateY(-50%); /* 向上移动自身高度的一半 */ /* 其他样式 */ } </style>这种方法通过transform: translateY(-50%);实现了向上移动元素自身高度的一半,从而实现了垂直居中的效果。这是处理未知高度元素垂直居中的常用技巧。
  • [技术干货] react实现全局改变字体大小
    在React中全局改变字体大小可以通过多种方式实现,但最直接和常用的方法是通过CSS或CSS-in-JS库(如styled-components, emotion等)来设定全局样式。以下是一些实现方法:方法1:使用全局CSS文件创建全局CSS文件:在你的项目中创建一个全局的CSS文件,比如命名为global.css。设置全局字体大小:在global.css中,使用*选择器或者html选择器来设置全局字体大小,并可以进一步设置body或其他元素的具体字体大小。/* global.css */ * { margin: 0; padding: 0; box-sizing: border-box; } html { font-size: 16px; /* 基础字体大小 */ } body { font-family: Arial, sans-serif; line-height: 1.6; }在React项目中引入全局CSS:确保在你的React项目的入口文件(如index.js或App.js)中引入了这个全局CSS文件。如果你使用的是Create React App,可以通过在src/index.js或src/App.js的顶部添加import './global.css';来实现。方法2:使用CSS变量(自定义属性)如果你想要更灵活地控制字体大小(例如,根据不同屏幕尺寸改变字体大小),你可以使用CSS自定义属性(也称为CSS变量)。在全局CSS中定义变量:/* global.css */ :root { --base-font-size: 16px; } html { font-size: var(--base-font-size); } @media (min-width: 768px) { :root { --base-font-size: 18px; } }引入CSS文件:同上,确保在你的React项目中引入了global.css。方法3:使用CSS-in-JS库如果你倾向于使用CSS-in-JS库,如styled-components或emotion,你可以在根组件或全局样式组件中设置字体大小。使用styled-components// GlobalStyles.js import { createGlobalStyle } from 'styled-components'; const GlobalStyles = createGlobalStyle` :root { --base-font-size: 16px; } html { font-size: var(--base-font-size); } @media (min-width: 768px) { :root { --base-font-size: 18px; } } `; export default GlobalStyles; // App.js import React from 'react'; import GlobalStyles from './GlobalStyles'; function App() { return ( <> <GlobalStyles /> {/* 其他组件 */} </> ); } export default App;以上就是在React中全局改变字体大小的几种方法。选择哪种方法取决于你的项目需求和个人偏好。
  • [技术干货] typescript || ?? 区别
    在TypeScript(以及JavaScript)中,||(逻辑或操作符)和??(空值合并操作符)都用于处理可能为null或undefined的值,但它们的行为和用途有所不同。|| 逻辑或操作符||操作符用于逻辑或运算,如果它的第一个操作数是truthy(在JavaScript中,除了false、0、""、null、undefined和NaN之外的所有值都被认为是truthy),则返回第一个操作数;否则,返回第二个操作数。重要的是要注意,||并不严格检查null或undefined,而是检查任何被视为falsy的值。因此,如果你使用||来提供一个默认值,而原始值可能是0、""或false(这些值在JavaScript中被视为falsy),那么这些值将会被错误地替换为默认值。?? 空值合并操作符??操作符是一个逻辑操作符,它仅当左侧的表达式结果是null或undefined时,才会返回右侧的表达式。它的主要目的是提供一种更直观的方式来为可能为null或undefined的变量提供一个默认值,而不会错误地替换掉那些被认为是falsy但实际上是有意义的值(如0、""或false)。示例let a = 0; let b = a || 5; // b 将会是 5,因为 0 是 falsy let c = a ?? 5; // c 将会是 0,因为 a 不是 null 或 undefined let d: string | undefined = undefined; let e = d || "default"; // e 将会是 "default",因为 d 是 falsy let f = d ?? "default"; // f 也会是 "default",但这里的逻辑更直接地指向了 null 或 undefined 的情况 let g: string | null = null; let h = g || "default"; // h 将会是 "default" let i = g ?? "default"; // i 也会是 "default",但使用 ?? 更清晰地表达了意图总结来说,虽然||和??在某些情况下看起来可以互换使用,但??在处理可能为null或undefined的值时提供了更精确的控制,并且不会错误地替换掉那些被认为是falsy但实际上有意义的值。
总条数:85 到第
上滑加载中