JS-掌握不同方法并了解其优缺点-中克隆对象的终极指南 (js掌握程度)
对象克隆是指创建对象的副本而不修改原始对象。这是在需要操纵对象而不影响其原始状态的情况下很有用的。
浅克隆
浅克隆只复制对象顶层的属性。嵌套对象或数组的引用仍然指向原始对象。
const cat = { name: "薛定谔", girlFriends: { name: "龙猫" } }; const newCat = {...cat}; newCat.name = "柴郡猫"; console.log(newCat.name); // "柴郡猫" console.log(cat.name); // "柴郡猫"
在上例中,
newCat
和
cat
对象都指向同一
girlFriends
对象。当我们更新
newCat
中的
girlFriends.name
属性时,
cat
中的该属性也会相应更新。
浅克隆的限制
浅克隆适用于对象属性只有单层深度的场景。如果对象属性包含嵌套引用,浅克隆将无法正确复制这些引用。
深克隆
深克隆复制对象的整个结构,包括所有嵌套对象和数组。这确保了克隆对象与原始对象完全独立。
JSON克隆
一种执行深克隆的方法是使用JSON。这涉及将对象转换为JSON字符串,然后将其解析回一个新对象。
const cat = { name: "薛定谔", girlFriends: { name: "龙猫" } }; const newCat = JSON.parse(JSON.stringify(cat)); newCat.name = "柴郡猫"; console.log(newCat.name); // "柴郡猫" console.log(cat.name); // "薛定谔"
JSON克隆适用于大多数情况下,但它有以下限制:
- 日期对象将被转换为字符串。
-
undefined
属性将被删除。 -
Set
对象无法被克隆。 -
Symbol
值无法被克隆。 - 正则表达式无法被克隆。
-
BigInt
值无法被克隆。
递归克隆
另一种执行深克隆的方法是使用递归函数。该函数遍历对象并为每个属性创建副本,包括嵌套对象和数组。
function deepClone(obj) { if (typeof obj !== "object" || obj === null) { return obj; } if (obj instanceof Array) { return obj.map(deepClone); } const newObj = {}; for (const prop in obj) { newObj[prop] = deepClone(obj[prop]); } return newObj; } const cat = { name: "薛定谔", girlFriends: { name: "龙猫" } }; const newCat = deepClone(cat); newCat.name = "柴郡猫"; console.log(newCat.name); // "柴郡猫" console.log(cat.name); // "薛定谔"
递归克隆适用于所有类型的数据结构,但它可能比JSON克隆效率较低,尤其是对于大型对象。
选择正确的克隆方法
选择哪种克隆方法取决于对象的结构和要求。如果对象属性只有单层深度,浅克隆就足够了。如果对象包含嵌套引用,则需要使用深克隆。
克隆方法 | 优点 | 缺点 |
---|---|---|
浅克隆 | 简单、高效 | 只复制顶层属性,不复制嵌套引用 |
JSON克隆 | 适用于大多数情况下 | 某些数据类型(如日期对象和正则表达式)无法克隆 |
递归克隆 | 适用于所有类型的数据结构 | 可能比JSON克隆效率较低 |
详解js中Number,parseInt和parseFloat的区别
详解js中Number,parseInt和parseFloat的区别var bb = 35.23ace23; (Number(bb));NaN (parseFloat(bb));35.23 (parseFloat(Number(bb)));NaN Number():可以用于任何数据类型转换成数值; parseInt()、parseFloat():专门用于把字符串转换成数值;转换规则: Number(): 1)如果是Boolean值,true和false将分别转换为1和0。 2)如果是数字值,只是简单的传入和返回。 3)如果是null值,返回0。 4)如果是undefined,返回NaN。 5)如果是字符串,遵循下列规则: 如果是字符串中只包含数字(包括前面带正号或负号的情况),则将其转换为十进制数值,即“1”变成1,“123”会变成123,而“011”会变成11(前导的零被忽略了); 如果字符串中包含有效的浮点格式,如“1.1”,则将其转换为对应的浮点数值(同样也会忽略前导零); 如果字符串中包含有效的十六进制格式,例如0xf,则将其他转换为相同大小的十进制整数值; 如果字符串是空的(不包含任何字符),则将其转换为0; 如果字符串中包含除上述格式之外的字符,则将其他转换成NaN. 6)如果是对象,则调用对象的valueOf()方法,然后依照前面的规则转换返回的值。 如果转换的结果是NaN,则调用的对象的toString()方法,然后再次依照前面的规则转换返回的字符串值。 ex: var num1=Number(Hello World);NaN var num2=Number();0 var num3=Number();11 var num4=Number(true); 1 由于Number()函数在转换字符串时比较复杂而且不够合理,因此在处理整数的时候更常用的是parseInt()函数。 parseInt(): 在转换字符串时,更多的时看其是否符合数值模式。 会忽略字符串前面的空格,直至找到第一个非空格字符。 如果第一个字符不是数字字符或都负号,parseInt()就会返回NaN; 也就是说,用parseInt()转换空字符串会返回NaN。 如果第一个字符是数字字符,parseInt()会继续解析第二个字符,直到解析完所有后续字符或者遇到了一个非数字字符。 例如,1234blue会被转换为1234,因为blue会被完全忽略。 类似地22.5会被转换为22,因为小数点不是有效的数字字符。 如果字符串以0x开头且后跟数字字符,就会将其当作一个十六进制整数; 如果字符串以0开头且后跟数字字符,就会将其当作一个八进制整数; parseInt()函数增加了第二参数用于指定转换时使用的基数(即多少进制)如:parseInt(10,16)按十六进制解析;parseInt(10,8)按八进制解析 parseFloat(): 与parseInt()函数类似,parseFloat()也是从第一个字符(位置0)形如解析每个字符,而且也是一直解析到字符串末尾,或者解析到遇见一个无效的浮点数字字符为止。 也就是说,字符串中的第一个小数点是有效的,而第二个小数点就是无效的了,因此它后面的字符串将被忽略。 例如:22.34.5将会转换为22.34。 除了第一个小数点有效之外,parseFloat()与parseInt()的第二个区别在于它始终都会忽略前导的零。 parseFloat()可以识别前面讨论过的所有的浮点数值格式,也包括十进制整数格式。 但十六进制格式的字符串则始终会被转换成0。 由于parseFloat()只解析十进制值,因此它没有用第二个参数指定基数的用法。 另外,如果字符串包含的是一个可解析为整数的数(没有小数点,或者小数点后面都是零),parseFloat()会返回整数。 ex: var num1=parseFloat(1234blue);1234 var num2=parseFloat(0xA);0 var num3=parseFloat(0908.5);908.5 var num4=parseFloat(3.125e7); 注意: 1)值得注意的是,浮点数值的最高精度是17位小数,但在进行算术计算时其精确度远远不如整数。 例如0.1加0.2的结果不是0.3,而是0.;99.99加0.1的结果不是100.09而是100.999。 这个小小的舍人误差会导致无法测试特定的浮点数值。 例如: if(a+b==0.3) 不要做这样的测试 2)在计算时有可能会计算出NaN的结果,ECMAScript定义了isNaN()函数。 这个函数接受一个参数,该参数可以是任何类型,而函数会帮我们确定这个参数是否“不是数值”。 isNaN()在接收到一个值之后,会尝试将这个值转换为数值。 不能转换为数值的参数会返回true。 Number是将函数把对象转换成数字; ParseInt可以做进制转换(字符前加0x或限定他是16进就16进制,不细讲);当然他还有一个作用就是取整数部分(字符串内第一个非数字以前的所有内容【包括小数点】)。 parseFloat和parseInt很像,不过他取的是浮点数,也就是碰到小数点后不停下,继续找。 知道碰到下一个字符var a=0.5;var n=Number(a);n=0.5var b=parseInt(a);b=0var c=parseFloat(a);c=0.5区别var _a=0.16e5svar _b=Number(A);_b=NaNvar _c=parseInt(_a);_c=0var _d=parseFloat(_a);d=0.16 ()a.如果转换的内容本身就是一个数值类型的字符串,那么在转换的时候返回自己;b.如果转换的内容本身不是一个数值类型的字符串,那么在转换的时候返回NaN;c.如果转换的内容本身是空的字符串,那么在转换的时候返回0;d.如果是其他字符串,结果是NaN;()a.忽略字符串前面的空格,直至找到第一个非字符串,会将数字后面的非数字的字符串去掉;b.如果第一个字符不是数字符号或者负号,返回NaN;c.会将小数取整(向下取整)()与parseInt()一样,但是可以保留小数。 纯手打,望采纳。 parseInt和parseFloat的区别 一、parseInt()parseInt()方法首先查看位置0处的 字符,判断它是否是个有效数字;如果不是,该方法将返回NaN,不再继续执行其他操作。 但如果该字符是有效数字,该方法将查看位置1处的字符,进行同样的 测试。 这一过程将持续到发现非有效数字的字符为止,此时parseInt()将把该字符之前的字符串转换成数字。 例如如果要把字符串 1234blue 转换成整数,那么parseInt()将返回1234,因为当它检测到字符b时,就会停止检测过程。 parseInt()方法还有基模式,可以把二进制、八进制、十六进制或其他任何进制的字符串转换成整数。 基是由parseInt()方法的第二个参数指定的,所以要解析十六进制的值,当然,对二进制、八进制,甚至十进制(默认模式),都可以这样调用parseInt()方法。 如果十进制数包含前导0,那么最好采用基数10,这样才不会意外地得到八进制的值。 二、parseFloat()与parseInt()方法的处理方式相似,从位置0开始查看每个字符,直到找到第一个非有效的字符为止,然后把该字 符之前的字符串转换成数字。 不过,对于这个方法来说,第一个出现的小数点是有效字符。 如果有两个小数点,第二个小数点将被看作无效的, parseFloat()方法会把这个小数点之前的字符串转换成数字。 这意味着字符串 22.34.5 将被解析成22.34。 使用parseFloat()方法的另一不同之处在于,字符串必须以十进制形式表示浮点数,而不能用八进制形式或十六进制形式。 该方法会忽略前导0,所以八进制数0908将被解析为908。 对于十六进制数0xA,该方法将返回NaN,因为在浮点数中,x不是有效字符。 此外,parseFloat()也没有基模式。 Javascript中Number,parseIn和parseFloat的区别 Number():概述:Number 对象由 Number() 构造器创建,是经过封装的能让你处理数字值的对象。 在非构造器上下文中 (如:没有 new 操作符),Number 能被用来执行类型转换。 语法:Number(value);特点:1、如果是Boolean值,true和false值将分别被转换为1和0。 2、如果是数字值,只是简单的传入和返回。 3、如果是null值,返回0。 4、如果是undefined,返回NaN。 5、如果是字符串:a. 如果字符串中只包含数字时,将其转换为十进制数值,忽略前导0b. 如果字符串中包含有效浮点格式,如“1.1”,将其转换为对应的浮点数字,忽略前导0c. 如果字符串中包含有效的十六进制格式,如“0xf”,将其转换为相同大小的十进制数值d. 如果字符串为空,将其转换为0e. 如果字符串中包含除上述格式之外的字符,则将其转换为NaN如果是对象,则调用对象的valueOf()方法,然后依照前面的规则转换返回的值。 如果转换的结果是NaN,则调用对象的toString()方法,然后再依照前面的规则转换返回的字符串值。 实例:var num1 = Number(Hello world); ·NaNvar num2 = Number();0var num3 = Number();11var num4 = Number(3.14fasdasf); Uncaught SyntaxError: Invalid or unexpected tokenvar num5 = Number(3.14fasdasf); NaNparseInt():概述:parseInt() 函数将给定的字符串以指定基数(radix/base)解析成为整数。 语法:parseInt(string, radix);参数:string:要被解析的值。 如果参数不是一个字符串,则将其转换为字符串。 字符串开头的空白符将会被忽略。 radix:一个2到36之间的整数值,用于指定转换中采用的基数。 比如参数10表示使用我们通常使用的十进制数值系统。 总是指定该参数可以消除阅读该代码时的困惑并且保证转换结果可预测。 当忽略该参数时,不同的实现环境可能产生不同的结果。 特点:1、如果被解析参数的第一个字符无法被转化成数值类型,则返回 NaN。 转换空字符串也会返回NaN。 2、开头和结尾的空白符允许存在,会被忽略,直到找到第一个非空格字符。 3、如果第一个字符是数字字符,parseInt() 会继续解析第二个字符,直到解析完所有后续字符串或者遇到了一个非数字字符。 遇到不能解析的字符和其后的字符都将被忽略。 接着返回已经解析的整数部分。 4、parseInt()方法还有基模式,可以把二进制、八进制、十六进制或其他任何进制的字符串转换成整数。 5、基是由parseInt()方法的第二个参数指定的,所以要解析十六进制的值,当然,对二进制、八进制,甚至十进制(默认模式),都可以这样调用parseInt()方法。 实例:var num1 = parseInt(AF,16); 175var num2 = parseInt(AF); NaNvar num3 = parseInt(10,2);2(按照二进制解析)var num4 = parseInt(sdasdad);NaNparseFloat():概述:parseFloat()方法将参数中指定的字符串解析成为一个浮点数字并返回.语法:parseFloat(string)特点:1、parseFloat是个全局函数,不属于任何对象。 2、如果在解析过程中遇到了正负号(+或-),数字(0-9),小数点,或者科学记数法中的指数(e或E)以外的字符,则它会忽略该字符以及之后的所有字符,返回当前已经解析到的浮点数.3、字符串首位的空白符会被忽略.如果参数字符串的第一个字符不能被解析成为数字,则parseFloat返回NaN.4、字符串中第一个小数点是有效的,而第二个小数点就是无效的了,它后面的字符串将被忽略。 5、parseFloat() 只解析十进制,因此它没有第二个参数指定基数的用法6、如果字符串中包含的是一个可解析为正数的数(没有小数点,或者小数点后都是零),parseFloat() 会返回整数。 实例:var num1 = parseFloat(123AF); 123var num2 = parseFloat(0xA);0var num3 = parseFloat(22.5);22.5var num4 = parseFloat(22.3.56); 22.3var num5 = parseFloat(0908.5);908.5Number()、parseInt() 和parseFloat() 的区别:Number()的强制类型转换与parseInt()和parseFloat()方法的处理方式相似,只是它转换的是整个值,而不是部分值。 如“3.4.5”,用Number()进行强制类型转换将返回NAN, 如果确定字符串值能被完整地转换,Number()将判断是调用parseInt()还是parseFloat()。 parseFloat() 所解析的字符串中第一个小数点是有效的,而parseInt() 遇到小数点会停止解析,因为小数点并不是有效的数字字符。 parseFloat() 始终会忽略前导的零,十六进制格式的字符串始终会被转换成0,而parseInt() 第二个参数可以设置基数,按照这个基数的进制来转换。
Js创建对象额几种方式
第一种模式:工厂方式说明: 1.在函数中定义对象,并定义对象的各种属性,,虽然属性可以为方法,但是建议将属性为方法的属性定义到函数之外,这样可以避免重复创建该方法 2.引用该对象的时候,这里使用的是 var x = Parent()而不是 var x = new Parent();因为后者会可能出现很多问题(前者也成为工厂经典方式,后者称之为混合工厂方式),不推荐使用new的方式使用该对象 3.在函数的最后返回该对象 4.不推荐使用这种方式创建对象,但应该了解。 缺点:①无法确定对象的类型(因为都是Object)。 ②创建的多个对象之间没有关联。 第二种模式:构造函数方式说明: 1.与工厂方式相比,使用构造函数方式创建对象,无需再函数内部重建创建对象,而使用this指代,并而函数无需明确return 2.同工厂模式一样,虽然属性的值可以为方法,扔建议将该方法定义在函数之外 3..同样的,不推荐使用这种方式创建对象,但仍需要了解。 缺点:①多个实例重复创建方法,无法共享。 ②多个实例均不是同一个Function的实例。 第三种模式:原型模式 说明:1.函数中不对属性进行定义 2.利用prototype属性对属性进行定义 3.同样的,不推荐使用这样方式创建对象缺点:①无法传入参数,不能初始化属性值。 ②如果包含引用类型的值时,改变其中一个实例的值,则会在所有实例中体现。 第四种模式:混合的构造函数,原型方式(推荐) 说明:1.该模式是指混合搭配使用构造函数方式和原型方式 2.将所有属性不是方法的属性定义在函数中(构造函数方式) 将所有属性值为方法的属性利用prototype在函数之外定义(原型方式) 3.推荐使用这样方式创建对象优点:构造函数共享实例属性,原型共享方法和想要共享的属性。 可传递参数,初始化属性值。 第五种模式:动态原型方式 说明: 1.动态原型方式可以理解为混合构造函数,原型方式的一个特例 2.该模式中,属性为方法的属性直接在函数中进行了定义,但是因为从而保证创建该对象的实例时,属性的方法不会被重复创建 3.推荐使用这种模式。 附:JS中多种方式创建对象详解
免责声明:本文转载或采集自网络,版权归原作者所有。本网站刊发此文旨在传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及版权、内容等问题,请联系本网,我们将在第一时间删除。同时,本网站不对所刊发内容的准确性、真实性、完整性、及时性、原创性等进行保证,请读者仅作参考,并请自行核实相关内容。对于因使用或依赖本文内容所产生的任何直接或间接损失,本网站不承担任何责任。