整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

深入理解 JavaScript:实现自定义 `map` 方法

家好,很高兴又见面了,我是姜茶的编程笔记,我们一起学习前端相关领域技术,共同进步,也欢迎大家关注、点赞、收藏、转发,您的支持是我不断创作的动力

在 JavaScript 中,Array.prototype.map 是一个常用的方法,它对数组的每个元素调用提供的函数,并返回一个新数组,包含函数的返回值。为了更好地理解其内部机制,今天我们将从零开始,实现一个自定义的 map 方法,并详细解析其实现步骤。

实现自定义 map 方法

首先,我们创建一个 myMap 方法,将其添加到 Array.prototype 上。这个方法接受两个参数:一个回调函数 callback 和一个可选的 thisArg 参数。callback 函数将对数组的每个元素进行操作,thisArg 是执行回调函数时的 this 值。

Array.prototype.myMap = function(callback, thisArg) {
  // 将传入的数组转换为对象
  const O = Object(this);

  // 获取数组的长度
  const len = O.length >>> 0;

  // 如果 callback 不是函数,则抛出 TypeError
  if (typeof callback !== 'function') {
    throw new TypeError(callback + ' is not a function');
  }

  // 创建一个新的数组,用于存储映射结果
  const result = new Array(len);

  // 遍历数组并应用回调函数
  for (let i = 0; i < len; i++) {
    // 只有当元素在数组中存在时才进行映射
    if (i in O) {
      // 调用回调函数,传递 thisArg 作为 this 值,并传递当前元素、索引、数组本身
      result[i] = callback.call(thisArg, O[i], i, O);
    }
  }

  return result;
};

让我们逐步解析这个实现。

1. 将传入的数组转换为对象

我们首先将 this 转换为一个对象,以便在方法中使用:

const O = Object(this);

2. 获取数组的长度

使用 >>> 0 操作符将长度转换为无符号整数,确保其为正整数:

const len = O.length >>> 0;

3. 检查回调函数

如果 callback 不是函数,则抛出一个 TypeError

if (typeof callback !== 'function') {
  throw new TypeError(callback + ' is not a function');
}

4. 创建结果数组

我们创建一个与原数组长度相同的新数组,用于存储映射结果:

const result = new Array(len);

5. 遍历数组并应用回调函数

使用 for 循环遍历数组的每个索引。如果当前索引存在于数组中,则调用回调函数,并将结果存储在 result 数组中:

for (let i = 0; i < len; i++) {
  if (i in O) {
    result[i] = callback.call(thisArg, O[i], i, O);
  }
}

6. 返回结果数组

最后,我们返回存储映射结果的 result 数组:

return result;

示例使用

下面是一个示例,展示如何使用自定义的 myMap 方法:

const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.myMap(x => x * 2);

console.log(doubled); // 输出 [2, 4, 6, 8, 10]

在这个示例中,我们将 numbers 数组中的每个元素都乘以 2,并将结果存储在 doubled 数组中。结果输出为 [2, 4, 6, 8, 10],这与内置的 Array.prototype.map 方法的行为一致。

结论

通过实现自定义的 map 方法,我们深入理解了 JavaScript 中数组的操作方式。希望你可以更好地掌握 map 方法的内部机制,并提升你的 JavaScript 编程技巧。

最后

如果你有任何问题或建议,欢迎在评论区留言交流!祝你编程愉快!

bjects 和 maps 的比较:

  Object的键只能是字符串或者 Symbols,但 Map 的键可以是任意值,包括函数、对象、基本类 型。

  Map 中的键值是有序的,而添加到 Object 对象中的键则不是。因此,当对它进行遍历时,Map 对象是按插入的顺序返回键值。

  可以通过 size 属性直接获取一个 Map 的键值对个数,而 Object 的键值对个数只能手动计算。

  Map 可直接进行迭代,而 Object 的迭代需要先获取它的键数组,然后再进行迭代。

 Map 在涉及频繁增删键值对的场景下会有些性能优势。

Map 类型实例化语法:

new Map([iterable])
let map = new Map([['key1', 'value1'], ['key2', 'value2']]);

Map 类型实例属性与方法:

Map.prototype.size                              // 元素数量
Map.prototype.clear()                           // 移除Map对象的所有键/值对 。
Map.prototype.delete(key)                       // 如果 Map 对象中存在该元素,则移除它并返回 true;否则如果该元素不存在则返回 false
Map.prototype.entries()                         // 返回一个新的 Iterator 对象,它按插入顺序包含了Map对象中每个元素的[key, value] 数组。
Map.prototype.forEach(callbackFn[, thisArg])    // 按插入顺序,为 Map对象里的每一键值对调用一次callbackFn函数。
Map.prototype.get(key)                          // 返回键对应的值,如果不存在,则返回undefined。
Map.prototype.has(key)                          // 返回一个布尔值,表示Map实例是否包含键对应的值。
Map.prototype.keys()                            // 返回一个新的 Iterator对象, 它按插入顺序包含了Map对象中每个元素的键 。
Map.prototype.set(key, value)                   // 设置Map对象中键的值。返回该Map对象。
Map.prototype.values()                          // 返回一个新的Iterator对象,它按插入顺序包含了Map对象中每个元素的值 。

Map 实例:

let myMap = new Map();
let keyObj = {},
    keyFunc = function () { },
    keyString = "a string";
 
    // 添加键
myMap.set(keyString, "和键'a string'关联的值");
myMap.set(keyObj, "和键keyObj关联的值");
myMap.set(keyFunc, "和键keyFunc关联的值");
console.log(myMap.size);    // => 3
 
// 读取值
myMap.get(keyString);       // "和键'a string'关联的值"
myMap.get(keyObj);          // "和键keyObj关联的值"
myMap.get(keyFunc);         // "和键keyFunc关联的值"
myMap.get("a string");      // "和键'a string'关联的值",因为keyString === 'a string'
myMap.get({});              // undefined, 因为keyObj !== {}
myMap.get(function () { })  // undefined, 因为keyFunc !== function () {}

Map 类型迭代,举例:

let myMap = new Map();
myMap.set(0, "zero");
myMap.set(1, "one");
 
// 将会输出两个log,一个是"0 = zero", 另一个是"1 = one"
for (let [key, value] of myMap) {
    console.log(key + " = " + value);
}
 
// 将会输出两个log, 一个是 "0" 另一个是 "1"
for (let key of myMap.keys()) {
    console.log(key);
}
 
// 将会输出两个log, 一个是 "zero" 另一个是 "one"
for (let value of myMap.values()) {
    console.log(value);
}
 
// 将会输出两个log, 一个是 "0 = zero" 另一个是 "1 = one"
for (let [key, value] of myMap.entries()) {
    console.log(key + " = " + value);
}
 
// 将会输出两个logs, 一个是 "0 = zero" 另一个是 "1 = one"
myMap.forEach(function (value, key) {
    console.log(key + " = " + value);
})

Map 类型与数组类型互转,举例:

var kvArray = [["key1", "value1"], ["key2", "value2"]];
// 使用常规的Map构造函数可以将一个二维键值对数组转换成一个Map对象
var myMap = new Map(kvArray);
console.log(myMap.get("key1"));             // => value1
 
// 使用Array.from函数可以将一个Map对象转换成一个二维键值对数组
console.log(Array.from(myMap));             // 输出和kvArray相同的数组
 
// 在键或者值的迭代器上使用Array.from,进而得到只含有键或者值的数组
console.log(Array.from(myMap.keys()));      // 输出 ["key1", "key2"]
console.log(Array.from(myMap.values()));    // 输出 ["value1", "value2"]

Map 对象间可以合并,有重复键值时,后面的会覆盖前面的;

站地图及制作方法

Sitemaps(网站地图)协议使你能够告知搜索引擎网站中可供抓取的网址。

最简便的方式就是,使用Sitemaps协议的Sitemaps就是列有某个网站所有网址的XML文件。

Sitemaps协议此可高度扩展,因此可适用于各种大小的网站。它还能够使网站管理员提供有关每个网址的其他信息(上次更新的时间、更改的频率、与网站中其他网址相比它的重要性等),以便搜索引擎可以更智能地抓取该网站。

Sitemaps协议补充而不是取代搜索引擎已用来发现网址的基于抓取的机制。通过向搜索引擎提交一个Sitemaps(或多个Sitemaps),可帮助搜索引擎更好地抓取你的网站。

网站地图的合理使用

网站地图文件原本是方便访问用户更好的了解站点的构架而设置的,它能帮助用户便捷得查询得到所需的信息。

网站地图,又称站点地图,它就是一个页面,上面放置了网站上所有页面的链接。大多数人在网站上找不到自己所需要的信息时,可能会将网站地图作为一种补救措施。搜索引擎蜘蛛非常喜欢网站地图。

网站地图是一个网站所有链接的容器。很多网站的连接层次比较深,蜘蛛很难抓取到,网站地图可以方便搜索引擎蜘蛛抓取网站页面,通过抓取网站页面,清晰了解网站的架构,网站地图一般存放在根目录下并命名为sitemaps,为搜索引擎蜘蛛指路,增加网站重要内容页面的收录。网站地图就是根据网站的结构、框架、内容,生成的导航网页文件。

大多数人都知道网站地图对于提高用户体验有好处:它们为网站访问者指明方向,并帮助迷失的访问者找到他们想看的页面。对于SEO,网站地图的好处就更多了:

1.为搜索引擎蜘蛛提供可以浏览整个网站的链接简单的体现出网站的整体框架出来给搜索引擎看;

2.为搜索引擎蜘蛛提供一些链接,指向动态页面或者采用其他方法比较难以到达的页面;

3.作为一种潜在的着陆页面,可以为搜索流量进行优化;

4.如果访问者试图访问网站所在域内并不存在的URL,那么这个访问者就会被转到“无法找到文件”的错误页面,而网站地图可以作为该页面的“准”内容。

网站地图的形式

1、WEB界面形式

它作为构成网站的诸多页面之一,以纯文本的超级链接形式为最佳表现形式,用户和搜索引擎机器人都可以识别。传统网站用来方便用户,现在更主要是帮助搜索引擎找到深层次的页面

2、XML文本形式

不易于绝大多数访问用户理解阅读,专为搜索引擎机器人而准备。可在ROBOTS.TXT文件中进行描述,目前,包裹谷歌在内的四大搜索引擎均支持sitemaps协议。

建议使用网站地图的场合

1.网站包含大量动态网页;

2.网站包含大量使用图片,Flash或者Ajax(特效网页)的网页;

3.网站为新网站且指向该网站的链接不多;

4.网站有大量内容页存档,这些内容页彼此之间没有很好地链接,或根本没有链接。

生成网站地图sitemaps的方法

第一种方式:网站地图自动生成器

在这里大家可以选择一个自己熟悉的网站生成一个网站地图xml文件,生成的速度比较慢,所以选择不要太大的网站。生成的xml文件应该借助ftp协议上传到自己网站的根目录下。

第二种方式:Site Map Builder .NET

注意:【安装方式:先安装.NET Framework 1.1,然后安装Site Map Builder .NET 】

第三种方式:XENU.EXE工具生成.html的地图

1、运行XENU.EXE文件,先单击“options”菜单,取消除“Valid text Url”外的其他多选按钮前的“√”,如果不取消则会结果中出现更多的选项。

2、然后选择“File”菜单下的“Check Url”命令,在第一个输入框里输入你的网址,最后单击“确定”。

3、过一段时间,系统会提示你检查完毕;

4、这时选择“File”菜 单下的“Report”命令,系统会自动打开一个IE窗口,这就是生成的静态页面了。

5、最后,将此文件保存,并根据自己的要求,在DreamWeaver 或者FrontPage里面把这个静态页面修改一下即可。

第四种方式:站长工具

使用百度统计_站长工具_sitemap。(robotx协议也可以在这里生成)。

附:网站目录(Directory)的使用

大型站点,往往具有较为庞大的注册用户和其他数据库信息,为了更合理的展现,我们需要进行各种分类,整理成目录,以确保用户和搜索引擎均能较快的找到所需信息。

1)企业类信息常用分类方式:行业分类,地区分类,首字母分类,企业规模和性质分类。

2)会员信息常用分类方式:兴趣分类,地区分类,首字母分类,性别分类。

网站目录与网站地图的区别:网站地图以信息本身为索引主体,而网站目录以信息类型为索引主体,不是同一个概念。

【袁帅论道】袁帅,互联网数据分析运营实践者,智能一体化会展活动运营服务平台会点网事业合伙人/运营负责人。CEAC国家信息化计算机教育认证:网络营销师,SEM搜索引擎营销师,SEO工程师。中国电子商务协会认证:中国电子商务职业经理人,畅销书《互联网销售宝典》联合出品人之一。中国国际贸易促进委员会:今日会展会员联盟VIP个人会员,全经联园区委秘书处成员,中国低碳智慧园区联盟理事,周五咖啡媒体人俱乐部发起合伙人。互联网数据官(iCDO)原创作者,互联网营销官CMO原创作者,执牛耳媒体特约撰稿人。