`
zha_zi
  • 浏览: 592936 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

JS 伪数组原理详解

 
阅读更多

                          javascript 伪数组原理详解

   很疑惑的一个概念,或者大家很少听说过,网上 关于伪数组的文章页比较少,但是我们每天都在不知不觉的使用的这伪数组,这里收集一些网上关于伪数组的文章和自己对伪数组的一些概念的理解 jQuery 和argument 是我们最常见的两个伪数组,下边是一个例子,看一下jQuery 中伪数组的用法 

   

                        var $div=$("#tag");
			console.log($div);
			console.log($div.length);
			console.log($div.selector);
			console.log($div[0]);  
			console.log($div["selector"]);
			console.log($div["length"]);
			console.log($div["length"].slice(0,1))

 

 

 你可以注意到最后一个结果就是使用数组的属性slice 的时候是报错误的,好像伪数组又无法正常的使用数组的方法,这里可以对伪数组进行一个简单的概述就是对象冒充数组,有了数组的形态其实就是有了length的概念,但是并不能真正使用数组的方法。下边介绍一下js中数组的概念

  javascript 数组

  JavaScript没有真正的数组,因此typeof运算符不能辨别数组和对象。伪数组在JavaScript中有很高的易用性,程序员不用给它设置维度,而且永远不用担心产生越界错误,但JavaScript数组的性能相比真正的数组可能更糟糕。要判断一个值是否为数组,必须使用constructor属性,例如:

if(value && typeof value === 'object' && value.constructor === Array) {

}

  arguments不是一个数组,它是一个带有length成员属性的对象,很多时候会把它理解为一个伪数组。

使用上面的检测方法会将arguments识别为一个数组,有时候这是希望得到的结果,尽管arguments不包含任何数组的方法。

   还有一种关于伪数组的解释能通过Array.prototype.slice转换为真正的数组的带有length属性的对象。 

这种对象有很多,比较特别的是arguments对象,还有像调用getElementsByTagName,document.childNodes之类的,它们都返回NodeList对象都属于伪数组。 

我们可以通过Array.prototype.slice.call(fakeArray)将伪数组转变为真正的Array对象。 

在我看来两者的说法大致相同都是一个对象,但是有个数组length属性,那么他在js的编辑器下就能看起来像一个数组就像你用console 打出一个伪数组,结果是一个

[
  div:"",
  content:"",
  length:1,
  proto:
]

 

 

 实现一个伪数组

 
var fakeArray01 = {0:'a',1:'b',length:2};//这是一个标准的有伪数组对象 
var arr01 = Array.prototype.slice.call(fakeArray01); 
alert(arr01[0]);//a 
var arr02 = [].slice.call(fakeArray01); 
alert(arr02[0]);//a 

    slice 可以用来获取数组片段,它返回新数组,不会修改原数组。 

 

示例中可以看到fakeArray被成功的转换成了Array对象。也许大家对Array.prototype.slice.call这种写法比较陌生,其实我们也可以通过[].slice.call这种形式实现同样的效果,那为什么我们要通过prototype的形式实现呢,答案是以prototype的形式执行程序效率更高,同样代码也更加优美。 

伪数组的实现 

 深入伪数组实现

    让我们再深入的看一下伪数组的实现。 

我们来看一些特殊的用例:

 

 
var fakeArray01 = {a:'a',b:'b',length:2};//没有length下标对应的值 
var arr01 = Array.prototype.slice.call(fakeArray01); 
alert(arr01[0]);//undefined 
var fakeArray02 = {0:'a',1:'b',length:'num'};//length不是数值 
var arr02 = Array.prototype.slice.call(fakeArray02); 
alert(arr02[1]);//undefined 

 

 

slice 内部原理 

同样fakeArray01和fakeArray02被转换成了真正的数组,但是数组中的值都为undefined 

查看 V8 引擎 array.js   的源码,可以将 slice 的内部实现简化为: 

 

 
function slice(start, end) { 
var len = ToUint32(this.length), result = []; 
    for(var i = start; i < end; i++) { 
        result.push(this[i]); 
    } 
    return result; 
} 

 可以看出,slice 并不需要 this 为 array 类型,只需要有 length 属性即可。并且 length 属性可以不为 number 类型,当不能转换为数值时,ToUnit32(this.length) 返回 0. 

根据以上结论可以得出:fakeArray01被转换成了lenth为2的数组,其值都被初始化为undefined,fakeArray02被转换成了length为0的数组,自然访问下标为1的元素返回undefined 

IE的问题 

针对于标准浏览器slice实现已经可以解释所有的问题,但是IE在处理NodeList时出现了问题。IE中无法将NodeList转换为真正的数组,会出错。这又是为什么呢?严格说,在IE内部定义了一个抽象类Arraioid,Array和Arguments都继承与此,所以可以用slice。但DOM对象是通过COM接入到JScript的,slice检测的时候失效。 

Jquery与伪数组 

Jquery内部大量运用了伪数组。可以说整个Jquery对象,都是构建在伪数组的基础之上的,好让我们来看一些Jquery的实际运用: 

 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 
<html> 
<head> 
<title>fakeArray</title> 
<meta http-equiv="content-type" content="text/html; charset=UTF-8"> 
<script src="jquery-1.4.2.js" type="text/javascript"></script> 
<script> 
$(document).ready(function(){ 
    var body = $("body"); 
    alert(body.get(0).tagName); 
}); 
</script> 
</head> 
<body> 
<div id="test"></div> 
</body> 
</html> 

 

    再简单不过的程序了,好,让我们来看一下其内部的实现原理: 

 
jQuery.fn = jQuery.prototype = { 
    init: function( selector, context ) { 
        var match, elem, ret, doc; 
        // Handle $(""), $(null), or $(undefined) 
        if ( !selector ) { 
            return this; 
        } 
        // Handle $(DOMElement) 
        if ( selector.nodeType ) { 
            this.context = this[0] = selector; 
            this.length = 1; 
            return this; 
         } 
         // The body element only exists once, optimize finding it 
         if ( selector === "body" && !context ) { 
             this.context = document; 
             this[0] = document.body; 
             this.selector = "body"; 
             this.length = 1; 
             return this; 
         } 
//... ... 
    }, 
    get: function( num ) { 
       return num == null ? 
// Return a 'clean' array 
       this.toArray() : 
// Return just the object 
      ( num < 0 ? this.slice(num)[ 0 ] : this[ num ] ); 
    } 
} 

   最后,我们来解释一下,程序的执行细节.但是在这之前,还得说一下关于Jquery的内部的一些东西。 

用过Jquery的用户应该都知道$()函数,它是Jquery的选择器代表。我们可能通过$()函数去选取页面中的元素(具体语法可参数Jquery帮助文档)。实际上当我们执行$()函数时,程序去执行上面列出的init方法,我们来看一下在调用$(document)时所发生的事件: 

 
//$(document) 
init: function( selector, context ) { 
    var match, elem, ret, doc; 
    // Handle $(DOMElement) : 处理DOM元素, 
    if ( selector.nodeType ) { 
        this.context = this[0] = selector; //给属性0赋予selector值,此时就是document对象 
        this.length = 1; //创建伪数组,更新下标 
        return this; //返回Jquery对象 
    } 
//... ... 
} 

   $("body")是同样的道理,不再多说了。 

我们知道Jquery里所有的操作返回的都是Jquery对象,那我们如何得到其所对应的dom对象呢,Jquery为我们提供了一个get方法,这是专门用来从jquery对象中取得DOM对象用的,由此,便有了body.get(0),那为什么又是get(0)而不是get()呢,因为Jquery的所有操作都是针对于数组进行的。所以,在get方法里,我们要传一个下标值,来得到具体的元素。现在该看get方法的具体实现了: 

 
get: function( num ) { 
    return num == null ? 
    //如果没有num,则直接返回DOM数组 
    this.toArray() : 
    //如果指定的num,则返回指定下标的元素 
    //this.slice是jquery的另一个方法,它内部其实还是调用Array.prototype.slice来实现将伪数组转换为真实的数组 
    ( num < 0 ? this.slice(num)[ 0 ] : this[ num ] ); 
} 

 关于伪数组就到这吧,我想应该已经差不多了。

 

补充:

   最近在一个项目中用到伪数组

场景   var resourceIDMapping={

       

        1:"机票",

        2:"酒店",

        3:"签证",

        4:"保险",

        5:"交通",

        6:"景点",

        7:"餐饮",

        8:"会议",

        9:"设备",

        10:"其他",

        11:"导游",

        12:"领队",

        13:"火车",

        14:"门票",

        "length":14

    }; 

  这样一个伪数组,因为后台定义类型的时候下标并不是从零开始,

  var resourceIDArray=[].slice.call(resourceIDMapping);  转换成一个数组,

  调用的时候是这样<%=resourceIDArray[parseInt(d.ResourceID)]%>,调用的时候大部分都是正常,只有ResourceID=14 的时候 无法正常显示内容,无论怎么修改都不能正常显示,百思不能其解,最后发现把length 修改成15就正常,但是实际上内容只有14项,原因是resourceIDArray 是首先作为一个数组处理,视为已经越界,不会去真正拿对象中14:"" 对应的内容

  

 

分享到:
评论

相关推荐

    javaScript动态随即生成UUID

    下面,我们将深入探讨“javaScript动态随即生成UUID”的相关内容,包括UUID的基本概念、生成原理以及三种不同的生成方法。 ### UUID的基本概念 UUID,全称Universally Unique Identifier,即通用唯一识别码,是由...

    js立体图片轮播特效

    - 数据存储与管理:使用JavaScript对象或数组来管理图片数据,包括图片URL、当前显示的索引等。 3. 知识点详解: - DOM操作:JavaScript通过DOM(Document Object Model)接口可以访问和修改HTML元素,如获取图片...

    最新Python3.5零基础+高级+完整项目(28周全)培训视频学习资料

    Django之CSRF原理详解 Django之中间件详解 Django之缓存实例详解 Django之信号 Django之Form组件验证 作业 第23周 主机管理项目需求分析 主机管理项目架构设计 主机管理项目初始构建 主机管理项目编写插件基类 ...

    韩顺平PHP JS JQUERY 所有视频下载种子 货真价实

    9-30 2 javascript的闭包 js变量作用域 9-30 3 仿超级玛丽兄弟游戏制作 9-30 4 构造方法 对象的常用操作 9-30 5 面向对象的封装 继承 多态 9-30 6 面向对象的封装 继承 多态2 9-5 1.php xml编程①-xml基本介绍 xml...

    JS树菜单

    **JS树菜单详解** 在网页开发中,"JS树菜单"是一种常见的交互元素,它以树状结构展示数据,常用于导航、文件管理、层级关系显示等场景。JS树菜单利用JavaScript语言动态构建和操作DOM元素,实现节点的展开、折叠、...

    js实现的网站首页随机公告随机公告

    根据给定的信息,本文将详细解析如何利用JavaScript(简称JS)在网站的首页实现随机公告功能,包括具体的实现原理、代码细节以及相关的扩展知识。 ### 一、随机公告功能的实现原理 首先,我们需要理解随机公告功能...

    详解jquery选择器的原理

    jQuery选择器是jQuery库的核心功能之一,它提供了一种高效且灵活的方式来选取DOM元素,使得JavaScript操作DOM变得简单。在jQuery中,选择器是用于选取HTML元素的关键工具,其工作原理基于CSS选择器规范,同时也引入...

    史上最全韩顺平传智播客PHP就业班视频,10月份全集

    9-30 2 javascript的闭包 js变量作用域 9-30 3 仿超级玛丽兄弟游戏制作 9-30 4 构造方法 对象的常用操作 9-30 5 面向对象的封装 继承 多态 9-30 6 面向对象的封装 继承 多态2 9-5 1.php xml编程①-xml基本介绍 xml...

    史上最全传智播客PHP就业班视频课,8月份视频

    9-30 2 javascript的闭包 js变量作用域 9-30 3 仿超级玛丽兄弟游戏制作 9-30 4 构造方法 对象的常用操作 9-30 5 面向对象的封装 继承 多态 9-30 6 面向对象的封装 继承 多态2 9-5 1.php xml编程①-xml基本介绍 xml...

    史上最全韩顺平传智播客PHP就业班视频,9月份全集

    9-30 2 javascript的闭包 js变量作用域 9-30 3 仿超级玛丽兄弟游戏制作 9-30 4 构造方法 对象的常用操作 9-30 5 面向对象的封装 继承 多态 9-30 6 面向对象的封装 继承 多态2 9-5 1.php xml编程①-xml基本介绍 xml...

    (全)传智播客PHP就业班视频完整课程

    9-30 2 javascript的闭包 js变量作用域 9-30 3 仿超级玛丽兄弟游戏制作 9-30 4 构造方法 对象的常用操作 9-30 5 面向对象的封装 继承 多态 9-30 6 面向对象的封装 继承 多态2 9-5 1.php xml编程①-xml基本介绍 xml...

    jQuery+CSS3蓝色夜空星星背景动画特效.zip

    《jQuery+CSS3蓝色夜空星星背景动画特效详解》 在网页设计中,引入动态元素可以极大地提升用户体验,其中星空背景动画就是一种常见的视觉增强手段。"jQuery+CSS3蓝色夜空星星背景动画特效"就是一个典型的例子,它...

    coursera-jhu-web:约翰·霍普金斯大学(Johns Hopkins University)为Web开发人员准备HTML,CSS和Javascript

    学习CSS时,要熟练运用类选择器、ID选择器、伪类和伪元素,以及盒模型、布局模式(如流体布局、网格布局)和响应式设计原理,以适应不同设备的显示需求。 JavaScript是网页的动态灵魂,使得用户与网页能进行交互。...

    架构脑图.pdf

    - **Js数组和字符串**:JavaScript中的数组和字符串操作。 - **Js函数和函数化**:JavaScript中的函数定义和使用。 以上内容覆盖了从Java基础到数据库操作再到分布式存储系统的各个方面,为读者提供了一个全面的...

    射击小游戏 Java

    通过分析这段 JavaScript 代码,我们可以看到一个简单的射击游戏的基本框架和实现原理。尽管这段代码并不完美,但通过学习它可以了解到如何使用基本的 HTML、CSS 和 JavaScript 来构建一个互动性游戏。这对于初学者...

    iPlatUI 前台开发指南

    ### iPlatUI 前台开发指南知识点详解 #### 一、iPlatUI概述 iPlatUI是一款专为提升前台用户界面(UI)开发效率而设计的框架。通过集成丰富的组件库以及一系列便捷的功能特性,使得开发者能够快速构建出高质量的前端...

    calculator_[removed]计算器jscript

    【JavaScript计算器实现详解】 在IT领域,JavaScript是一种广泛使用的脚本语言,特别是在Web开发中,它为用户提供了丰富的交互性。本项目“calculator_jscript”是基于JavaScript实现的一个计算器,其设计灵感来源...

    字节跳动(抖音面试题)

    【字节跳动面试知识点详解】 1. 中间透明、四周蒙层遮蔽效果的实现: 这种效果通常通过CSS实现,可以使用`border-radius`创建圆角,然后结合`rgba()`颜色函数设置背景透明度,或者利用`clip-path`属性定义裁剪区域...

    python入门到高级全栈工程师培训 第3期 附课件代码

    08 JS的数组对象 09 JS的函数对象 第42章 01 JS的函数作用域 02 JS的window对象之定时器 03 JS的history对象和location对象 04 JS的DOM节点 05 JS的DOM节点 第43章 01 上节知识回顾 02 js之onsubmit事件与组织...

    前端技术部分.pdf

    ### 前端技术知识点详解 #### 一、目标任务 在前端开发中,明确的目标任务是确保项目顺利推进的关键。本部分将引导开发者熟练运用AdminLTE、LayerUI、SmartAdmin等后台主题模板,以实现系统功能的前端部分。为了...

Global site tag (gtag.js) - Google Analytics