主页 > 开源代码  > 

刷题|牛客-js入门15题(更ing)5/15知识点解答

刷题|牛客-js入门15题(更ing)5/15知识点解答
知识点总结:

a.contains(b)---> a 节点中是否包含 b

a.parentNode()-----> 求a节点的父节点

Object.assign(target, ...sources)-----> 浅拷贝:只拷贝对象的第一层属性,内部嵌套对象依然是引用类型。常用Object.assign(tar,sour):将所有源对象的可枚举属性复制到目标对象

防御性编程

链式赋值

fn(...arr)-----> 扩展运算符,注:arr为参数/集合(数组) fn.apply(this,arr)-------->apply:修改 this的指向,一参是函数体内的this指向,二参是收集一个集合对象(数组和类数组) fn.call(this, ...arr)--------->call:修改 this指向,一参 函数体内的this指向,二参是往后是依次传入的参数


JS41 dom 节点查找 描述

查找两个节点的最近的一个共同父节点,可以包括节点自身

输入描述:

oNode1 和 oNode2 在同一文档中,且不会为相同的节点

解题思路:

递归求解,一个节点不动,另一个节点不断向上查找,直到找到一个父节点包含另一个节点为止。

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <style> /* 填写样式 */ </style> </head> <body> <!-- 填写标签 --> <script type="text/javascript"> // 填写JavaScript function commonParentNode(oNode1, oNode2) { // 方法一:不断向上查找,直到找到一个父节点包含oNode2 /* for(;;oNode1 = oNode1.parentNode){ if(oNode1.contains(oNode2)){ return oNode1; } }*/ // 方法二:递归求解。一个节点不动,另一个节点不断向上查找,直到找到一个父节点能够包含另一个节点为止 if(oNode1.contains(oNode2)){ return oNode1; }else{ return commonParentNode(oNode1.parentNode,oNode2); } } </script> </body> </html>
JS44 根据包名,在指定空间中创建对象 描述

根据包名,在指定空间中创建对象

输入描述:

namespace({a: {test: 1, b: 2}}, 'a.b.c.d')

输出描述:

{a: {test: 1, b: {c: {d: {}}}}}


解题与分析

法一: 

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <style> /* 填写样式 */ </style> </head> <body> <!-- 填写标签 --> <script type="text/javascript"> function namespace(oNamespace, sPackage) { const arr = sPackage.split('.'); let res = oNamespace // 如果不是对象,则使它成为对象 for(let i=0;i<arr.length;i++){ if(typeof res[arr[i]] != 'object'){ res[arr[i]] = {}; } res = res[arr[i]]; // 不可省,在循环中将其赋给res } return res // return oNamespace 二者都可,因为复制的是对象的引用 } </script> </body>

法二,浅拷贝方法:

// 法二:浅拷贝 let o = oNamespace; let res = sPackage.split('.').forEach(item => { o[item] = o[item] ? Object.assign({}, o[item]) : {} ; o = o[item]; }); // return res; return o;

 知识点:

🔑 一、Object.assign() 细讲

Object.assign() 是 ES6 引入的方法,作用是将所有源对象的可枚举属性复制到目标对象,并返回目标对象。

语法:Object.assign(target, ...sources) 参数作用target目标对象(会被修改并返回)sources一个或多个源对象
2. 浅拷贝特性

浅拷贝只拷贝对象的第一层属性,内部嵌套对象依然是引用类型。

示例:

let obj1 = { a: 1, b: { c: 2 } };

let obj2 = Object.assign({}, obj1);

obj2.a = 100; obj2.b.c = 200;

console.log(obj1.a); // 1 ✅(基本类型被拷贝)

console.log(obj1.b.c); // 200 ❌(引用类型被共享)

👉 说明:

a 是基本类型,直接拷贝值 ✅b.c 是引用类型,拷贝的只是地址引用 🔥
3. 为什么用 Object.assign({}, tmpWrap[item])?

假设代码里直接写:tmpWrap[item] = tmpWrap[item] || {};

如果 tmpWrap[item] 是对象:

直接赋值会共用同一个对象的引用,修改 tmpWrap[item] 也会影响原始对象而 Object.assign() 会创建一个新的对象,确保不会共享引用。
🚨 防御性编程核心原因 tmpWrap[item] = Object.assign({}, tmpWrap[item]);

这个写法的优势:

写法是否安全原因`tmpWrap[item] = tmpWrap[item]{};`tmpWrap[item] = {};❌会覆盖已有数据Object.assign({}, tmpWrap[item])✅创建新对象,数据隔离

🔥 二、额外思考的安全原因 代码:

tmpWrap[item] = tmpWrap[item] ? Object.assign({}, tmpWrap[item]) : {};

这个写法为什么更安全?

✅ 安全点在于: ? 这个三元运算符确保只有在对象已经存在的情况下才会执行浅拷贝如果对象不存在,直接创建 {},避免多余的浅拷贝
性能对比 写法性能安全性说明Object.assign({}, tmpWrap[item])较低✅每次都会浅拷贝tmpWrap[item] ? Object.assign({}, tmpWrap[item]) : {}较高✅只有存在对象时才拷贝

★ 三、三个等号解释

代码:

tmpWrap = tmpWrap[item] = Object.assign({}, tmpWrap[item]);

等号的执行顺序是从右往左,相当于:

Object.assign({}, tmpWrap[item]) 先执行,返回一个新对象tmpWrap[item] = 新对象 将新对象赋值给当前层级的属性 tmpWrap = 新对象 把 tmpWrap 移动到下一级,方便下一次迭代
🚀 执行顺序演示

假设:let obj = {}; namespace(obj, 'a.b.c');

执行过程:

步骤tmpWraptmpWrap[item]说明初始{}-初始对象a{}{}创建 a 属性b{}{}创建 a.b 属性c{}{}创建 a.b.c 属性

🔑 终极总结 知识点说明浅拷贝避免共享引用Object.assign()数据隔离 + 防御性编程三个等号执行顺序代码链式赋值的重要特性额外思考写法性能 + 安全性更高

💡 最佳代码写法

tmpWrap[item] = tmpWrap[item] ? Object.assign({}, tmpWrap[item]) : {}; tmpWrap = tmpWrap[item];

👉 这样写:

只有在需要时才进行浅拷贝不会污染已有对象代码可读性更好

本题考察的核心点:

对 浅拷贝/深拷贝 的理解对象引用类型的陷阱链式赋值的执行顺序防御性编程思想
JS54 函数传参 描述

将数组 arr 中的元素作为调用函数 fn 的参数

示例1

输入:

function (greeting, name, punctuation) {return greeting + ', ' + name + (punctuation || '!');}, ['Hello', 'Ellie', '!']

复制输出:

Hello, Ellie!
 解题: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <style> /* 填写样式 */ </style> </head> <body> <!-- 填写标签 --> <script type="text/javascript"> // 填写JavaScript function argsAsArray(fn, arr) { // 法一:扩展运算符,防止fn不存在 // return fn && fn(...arr); // 法二:apply 修改this的指向,一参是函数体内的this指向,二参是收集一个集合对象(数组和类数组) // return fn.apply(this,arr); // 法三:call 修改this指向,一参 函数体内的this指向,二参是往后是依次传入的参数 return fn.call(this, ...arr); } </script> </body> </html>

标签:

刷题|牛客-js入门15题(更ing)5/15知识点解答由讯客互联开源代码栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“刷题|牛客-js入门15题(更ing)5/15知识点解答