Array.prototype.xxx.call()处理字符串的疑惑
看你不知道的JavaScript中卷 2.1数组时有个疑问。具体是这样的:
通过“借用”数组的方法可以很方便的处理字符串。可以“借用”数组的非变更方法,但不能“借用”数组的可变更方法。
用代码来描述就是:
var a = 'foo';
// 数组的非变更方法,即不改变原有数组的方法
var b = Array.prototype.join.call(a, '-');
var c = Array.prototype.map.call(a, v => v.toUpperCase()).join()
var d = Array.prototype.slice.call(a);
console.log(b); // 'f-o-o'
console.log(c); // 'FOO'
console.log(d); // ['f', 'o', 'o'] // 数组的可变更方法,即能够改变原有数组的方法
var e = Array.prototype.reverse.call(a);
// chrome: Uncaught TypeError: Cannot assign to read only property '0' of object '[object String]'
刚开始比较疑惑:
- 为什么字符串可以通过这种方式,使用数组方法呢
- 为什么所谓的
非变更方法可以这样用而可变更方法不能呢
当我看到Uncaught TypeError: Cannot assign to read only property '0' of object '[object String]'这个报错时算是有些明白了。
- 我们知道,
call的第一个参数是作为上下文对象的,但这里直接传入的是字符串变量a,看到[object String]时可以知道,这里使用了字符串的封装对象String
var f = new String(a);
console.log(f); // String {0: f, 1: 0, 2: 0, length: 3,}
// 类数组对象大多有两个特征,属性名是0,1,2...,有length属性
数组的非变更方法 是不改变原数组,并返回一个新数组的。那么每次调用必定产生一个新数组,并遍历上下文对象,把对应索引上的值赋给新数组:
fn(){
var newArray = [];
for(var i = 0,len = f.length; i < len; i++){
newArray[i] = f[i];
}
return newArray;
}
这就解释了第一个问题,为什么可以通过Array.prototype.xxx.call() 这种方式操作字符串。
- 注意到报错中的
read only,我想到了对象每个属性的描述对象
Object.getOwnPropertyDescriptors(f);
/**
{
0: {value: "f", writable: false, enumerable: true, configurable: false},
1: {value: "o", writable: false, enumerable: true, configurable: false},
2: {value: "o", writable: false, enumerable: true, configurable: false},
length: {value: 3, writable: false, enumerable: false, configurable: false}
}
*/
可以看到只有 enumerable: true其余均为 false, 每个属性只能被枚举,而不能被更改,而数组的可变更方法如reverse等,均要直接操作上下文对象(数组或类数组)。但[Object String]的属性是只读的,不能更改,不能配置。这就解释了第二个问题。
虽然最初的疑惑算是有了个比较合理的解释了,但其实还是有很多问题的:
- 书中说
Array.prototype.reverse(a)返回值是 字符串foo的封装对象,但我的chrome会报错,试了firefox 、edge、ie11、ie10、ie9都会报错,只有ie8会返回[object String]{0: undefined, 1: undefined, 2: undefined},其他浏览器没有测试。 - 既然
类数组的结构可以这样使用数组的方法,那么部署了Iterator遍历器接口的数据结构是不是也可以这么用,如果可以,调用数组方法时的逻辑是否和类数组一样?如果不可以又是为什么...等等。不过,这感觉扯的有点远了...也有些没有意义,既然都有Iterator了,一般情况下是在ES6环境下,我一个扩展运算符[...a]或者直接Array.from()不就生成一个数组了么,干嘛要费劲巴拉的用call。
这里虽然给出了两个问题的解释,但都是从自己的理解出发的,总感觉有些未尽之意或者难以再深入下去,有自己理解的朋友大家可以交流下。有不对的地方也欢迎指正。
原文链接:https://www.jianshu.com/p/0362b6cd90d6
Array.prototype.xxx.call()处理字符串的疑惑的更多相关文章
- Array.prototype.slice.call引发的思考
概述 今天在看书的时候看到Array.prototype.slice.call(arguments),有点看不懂,所以认真研究了一下,记录下来,供以后开发时参考,相信对其他人也有用. call 每一个 ...
- Array.prototype.removeBeginWithVal(删除数组内以某值开头的字符串对象)
Array扩展方法: //author: Kenmu //created time: 2015-03-16 //function: 删除数组内以某值开头的字符串对象 Array.prototype.r ...
- 前端性能优化:使用Array.prototype.join代替字符串连接
来源:GBin1.com 有一种非常简单的客户端优化方式,就是用Array.prototype.join代替原有的基本的字符连接的写法.在这个系列的第一篇中,我在代码中使用了基本字符连接: htmlS ...
- js基础进阶--关于Array.prototype.slice.call(arguments) 的思考
欢迎访问我的个人博客:http://www.xiaolongwu.cn Array.prototype.slice.call(arguments)的作用为:强制转化arguments为数组格式,一般出 ...
- IE下Array.prototype.slice.call(params,0)
i8 不支持 Array.prototype.slice.call(params,0) params可以是 HTMLCollection.类数组.string字符串
- 详解 Array.prototype.slice.call(arguments)
首先,slice有两个用法,一个是String.slice,一个是Array.slice,第一个返回的是字符串,第二个返回的是数组 在这里我们看第二个方法 1.在JS里Array是一个类 slice是 ...
- Array.prototype.slice.call(document.querySelectorAll('a'), 0)
Array.prototype.slice.call(document.querySelectorAll('a'), 0)的作用就是将一个DOM NodeList 转换成一个数组. slice()方法 ...
- Javascript中Array.prototype.map()详解
map 方法会给原数组中的每个元素都按顺序调用一次 callback 函数.callback 每次执行后的返回值组合起来形成一个新数组. callback 函数只会在有值的索引上被调用:那些从来没被赋 ...
- Array.prototype.slice.call(arguments) 类数组转成真正的数组
Array.prototype.slice.call(arguments) 我们知道,Array.prototype.slice.call(arguments)能将具有length属性的对象转成数 ...
随机推荐
- Ubuntu 18.04安装arm-linux-gcc交叉编译器
Ubuntu 18.04安装arm-linux-gcc交叉编译器
- Vue.js 2.x API 知识梳理(一) 全局配置
Vue.js 2.x API 知识梳理(一) 全局配置 Vue.config是一个对象,包含Vue的全局配置.可以在启动应用之前修改指定属性. 这里不是指的@vue/cli的vue.config.js ...
- 快速批量删除 docker 镜像或容器
原文:快速批量删除 docker 镜像或容器 点击在我的博客 xuxusheng.com 中查看,有更好的排版哦~ docker 本身并没有提供批量删除的功能,当有大量的镜像或者容器需要删除的时候,手 ...
- FTP搭建注意事项
正常的FTP搭建步骤很简单,随便网搜一篇文章就出来了 下面提出一个网址可供学习 https://blog.csdn.net/m0_38044299/article/details/81627607 但 ...
- mybatis获取刚刚插入到数据库的数据的id(转载)
原文地址:https://blog.csdn.net/hehuihh/article/details/82800739 我用的是第一种写法,直接把代码copy到insert标签里(id要是自增id) ...
- iOS - Objective-C 关联(objc_setAssociatedObject、objc_getAssociatedObject、objc_removeAssociatedObjects)
关联是指把两个对象相互关联起来,使得其中的一个对象作为另外一个对象的一部分. 关联特性只有在Mac OS X V10.6以及以后的版本上才是可用的. 在类的定义之外为类增加额外的存储空间 使用关联,我 ...
- 【转载】网站配置Https证书系列(二):IIS服务器给网站配置Https证书
针对网站的Https证书,即SSL证书,腾讯云.阿里云都提供了免费的SSL证书申请,SSL证书申请下来后,就需要将SSL证书配置到网站中,如果网站使用的Web服务器是IIS服务器,则需要在IIS服务器 ...
- stm32 SPI-FLASH W25Q64
The W25Q64BV array is organized into 32,768 programmable pages of 256-bytes each. Up to 256 bytes ca ...
- Android NDK 学习之调用Java函数
本博客主要是在Ubuntu 下开发,且默认你已经安装了Eclipse,Android SDK, Android NDK, CDT插件. 在Eclipse中添加配置NDK,路径如下Eclipse-> ...
- sql server with as只能查询一次
WITH Emp AS (SELECT acc.* FROM GXSpreadDB.dbo.gxs_account acc LEFT JOIN RYAccountsDB.dbo.AccountsInf ...