百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT知识 > 正文

第58条:区分数组对象和类数组对象

liuian 2025-01-14 15:20 31 浏览

示例

设想有两个不同类的API。第一个是位向量:有序的位集合

var bits=new BitVector;
bits.enable(4);
bits.enable([1,3,8,17]);

bits.bitAt(4);//1
bits.bitAt(8);//1
bits.bitAt(9);//0

enable方法被重载了,可以传入一个索引或索引的数组。第二个类的API是字符串集合:无序的字符串集合

var set=new StringSet;

set.add('Hamlet');
set.add(['Rosencrantz','Guildenstern']);
set.add({'Ophelia':1,'Polonius':1,'Horatio':1});

set.contains('Polonius');//true
set.contains('Guildenstern');//true
set.contains('Falstaff');//false

其中add方法被重载了,除了可以接收字符串和字符串数组外,还可以接收一个字典对象。

函数重载

为了实现BitVerctor.prototype.enable方法,可以通过测试其他情况来避免如何判断一个对象是否为数组的问题。

BitVector.prototype.enable=function(x){
    if(typeof x === 'number'){
        this.enableBit(x);
    }else{
        for(var i=0,n=x.length;i< n;i++){
 this.enableBit(x[i]);
        }
    }
};

这里只实现了索引及索引数组的判断,很容易实现。那StringSet.prototype.add方法怎么实现呢?这里需要区分数组和对象。在js中数组就是一个对象。这里真正想做的是分离数组对象和非数组对象。这样的区分和js的灵活的类数组对象的概念是有争执的。任何对象都可被视为数组,只要它遵循正确的接口。而且也没有明确的方法来测试一个对象是否满足一个接口。可以尝试把具有length属性的对象视为数组,但这也会有错误出现,比如碰巧一个字典对象有length属性呢?

dimensions.add({
    'length':1,
    'height':1,
    'width':1
});

使用不精确的启发探索法来确定接口是一个容易被误解和滥用的方法。猜测一个对象是否实现了结构类型有时被称为鸭子测试,这是不好的实践。因为对象没有明确的信息标记来表示它们实现的结构类型,并没有可靠的编程方法来检测信息。

重载两种类型意味着必须有一种方法来区分这两种情况。不可能检测一个值是否实现了一种结构性的接口。规则-API绝不应该重载与其他类型有重叠的类型

instanceof

对于StringSet,开始就不要使用结构性的类数组接口。相反,我们应当选择一种类型,这种类型具有明确的定义的“标签”,可以表明用户真想将其作为一个数组。一个显而易见但不完美的选择是使用instanceof操作符来测试一个对象是否继承自Array.prototype。

StringSet.prototype.add=function(x){
    if(typeof x === 'string'){
        this.addString(x);
    }else if(x instaceof Array){
        x.forEach(function(s){
 this.addString(s);
        },this);
    }
};

任何时候一个Array的实例,它的行为会像一个数组。但有时候,在一些可以允许多个全局对象的环境中,可能会有标准的Array构造函数和原型对象的多份副本。在浏览器中有这种情况,每个frame会有标准库的一份单独副本。当跨frame通信时,一个frame中的数组不会继承自另一个frame的Array.prototype。

Array.isArray

出于上面这种情况,ES5引入了Array.isArray函数,其用于测试一个值是否是数组,而不管原型继承。在ES标准中,该函数测试对象的内部[[Class]]属性值是否是Array。当需要测试一个对象是否是真数组,而不仅仅是类数组对象,Array.isArray方法比instanceof操作符更好。

StringSet.prototype.add=function(x){
    if(typeof x === 'undefined'){
        this.addString(x);
    }else if(Array.isArray(x)){
        x.forEach(function(s){
 this.addString(s);
        },this);
    }else{
        for(var key in x){
 this.addString(key);
        }
    }
};

Object.prototype.toString

在不支持ES5的环境中,可以使用标准的Object.prototype.toString方法测试一个对象是否为数组。

var toString=Object.prototype.toString;
functin isArray(x){
    return toString.call(x) === '[object Array]';
}

Object.prototype.toString函数使用对象内部的[[Class]]属性创建结果字符串,所以测试一个对象是否为数组时,它比instanceof操作符更准确。

注意:该版本的add方法存在不同的影响该API的使用者的行为。重载API的数组版本不接收随意的类数组对象。例如,你不能传入arguments对象并期待它视为数组。

function MyClass{
    this.keys=new StringSet;
    //...
}
MyClass.prototype.update=function{
    this.keys.add(arguments);
};

Array.prototype.slice

这里会把arguments作为字典来对待。可以把arguments对象转化为真正的数组。

MyClass.prototype.update=function{
    this.keys.add(.slice.call(arguments));
};

当调用者传入多个参数时,会把它们转化为真正的数组,然后再使用add操作。当调用者想传递一个类数组对象给一个期望接收真正数组的API时,都需要做这种转换。可以在API的文档中标明各API接收哪些类型的参数。如上面的例子中,enable方法接收数字和类数组对象。add方法接收字符串、真数组和非数组对象。

提示

  • 绝不重载与其他类型有重叠的结构类型

  • 当重载一个结构类型与其他类型时,先测试其他类型

  • 当重载其他对象类型时,接收真数组而不是类数组对象

  • 文档标注你的API是否接收真数组或类数组

  • 使用ES5提供的Array.isArray方法测试真数组

相关推荐

GANs为何引爆机器学习?这篇基于TensorFlow的实例教程为你解惑!

「机器人圈导览」:生成对抗网络无疑是机器学习领域近三年来最火爆的研究领域,相关论文层出不求,各种领域的应用层出不穷。那么,GAN到底如何实践?本文编译自Medium,该文作者以一朵玫瑰花为例,详细阐...

高丽大学等机构联合发布StarGAN:可自定义表情和面部特征

原文来源:arXiv、GitHub作者:YunjeyChoi、MinjeChoi、MunyoungKim、Jung-WooHa、SungKim、JaegulChoo「雷克世界」编译:嗯~...

TensorFlow和PyTorch相继发布最新版,有何变化

原文来源:GitHub「机器人圈」编译:嗯~阿童木呀、多啦A亮Tensorflow主要特征和改进在Tensorflow库中添加封装评估量。所添加的评估量列表如下:1.深度神经网络分类器(DNNCl...

「2022 年」崔庆才 Python3 爬虫教程 - 深度学习识别滑动验证码缺口

上一节我们使用OpenCV识别了图形验证码躯壳欧。这时候就有朋友可能会说了,现在深度学习不是对图像识别很准吗?那深度学习可以用在识别滑动验证码缺口位置吗?当然也是可以的,本节我们就来了解下使用深度...

20K star!搞定 LLM 微调的开源利器

LLM(大语言模型)微调一直都是老大难问题,不仅因为微调需要大量的计算资源,而且微调的方法也很多,要去尝试每种方法的效果,需要安装大量的第三方库和依赖,甚至要接入一些框架,可能在还没开始微调就已经因为...

大模型DeepSeek本地部署后如何进行自定义调整?

1.理解模型架构a)查看深度求索官方文档或提供的源代码文件,了解模型的结构、输入输出格式以及支持的功能。模型是否为预训练权重?如果是,可以在预训练的基础上进行微调(Fine-tuning)。是否需要...

因配置不当,约5000个AI模型与数据集在公网暴露

除了可访问机器学习模型外,暴露的数据还可能包括训练数据集、超参数,甚至是用于构建模型的原始数据。前情回顾·人工智能安全动态向ChatGPT植入恶意“长期记忆”,持续窃取用户输入数据多模态大语言模型的致...

基于pytorch的深度学习人员重识别

基于pytorch的深度学习人员重识别Torchreid是一个库。基于pytorch的深度学习人员重识别。特点:支持多GPU训练支持图像的人员重识别与视频的人员重识别端到端的训练与评估简单的re...

DeepSeek本地部署:轻松训练你的AI模型

引言:为什么选择本地部署?在AI技术飞速发展的今天,越来越多的企业和个人希望将AI技术应用于实际场景中。然而,对于一些对数据隐私和计算资源有特殊需求的用户来说,云端部署可能并不是最佳选择。此时,本地部...

谷歌今天又开源了,这次是Sketch-RNN

前不久,谷歌公布了一项最新技术,可以教机器画画。今天,谷歌开源了代码。在我们研究其代码之前,首先先按要求设置Magenta环境。(https://github.com/tensorflow/magen...

Tensorflow 使用预训练模型训练的完整流程

前面已经介绍了深度学习框架Tensorflow的图像的标注和训练数据的准备工作,本文介绍一下使用预训练模型完成训练并导出训练的模型。1.选择预训练模型1.1下载预训练模型首先需要在Tensorf...

30天大模型调优学习计划(30分钟训练大模型)

30天大模型调优学习计划,结合Unsloth和Lora进行大模型微调,掌握大模型基础知识和调优方法,熟练应用。第1周:基础入门目标:了解大模型基础并熟悉Unsloth等工具的基本使用。Day1:大模...

python爬取喜马拉雅音频,json参数解析

一.抓包分析json,获取加密方式1.抓包获取音频界面f12打开抓包工具,播放一个(非vip)视频,点击“媒体”单击打开可以复制URL,发现就是我们要的音频。复制“CKwRIJEEXn-cABa0Tg...

五、JSONPath使用(Python)(json数据python)

1.安装方法pipinstalljsonpath2.jsonpath与Xpath下面表格是jsonpath语法与Xpath的完整概述和比较。Xpathjsonpath概述/$根节点.@当前节点...

Python网络爬虫的时候json=就是让你少写个json.dumps()

大家好,我是皮皮。一、前言前几天在Python白银交流群【空翼】问了一个Python网络爬虫的问题,提问截图如下:登录请求地址是这个:二、实现过程这里【甯同学】给了一个提示,如下所示:估计很多小伙伴和...