《javascript高级程序设计》笔记:Number数值转换 segmentfault.com/a/119000001…
有 3 个函数可以把非数值转换为数值:Number()、parseInt()和 parseFloat()。 Number()用于任何数据类型,另两个函数专门用于把字符串转换成数值
Number()函数的转换规则如下
-
如果是 Boolean 值,true 和 false 将分别被转换为 1 和 0。
-
如果是数字值,只是简单的传入和返回。
-
如果是 null 值,返回 0。
-
如果是 undefined,返回 NaN。
-
如果是字符串,遵循下列规则:
- 如果字符串中只包含数字(包括前面带正号或负号的情况),则将其转换为十进制数值,即"1" 会变成 1,"123"会变成 123,而"011"会变成 11(注意:前导的零被忽略了);
- 如果字符串中包含有效的浮点格式,如"1.1",则将其转换为对应的浮点数值(忽略前导零);
- 如果字符串中包含有效的十六进制格式,例如"0xf",则将其转换为相同大小的十进制整数值;
- 如果字符串是空的(不包含任何字符),则将其转换为 0;
- 如果字符串中包含除上述格式之外的字符,则将其转换为 NaN。
-
如果是对象,则调用对象的 valueOf()方法,然后依照前面的规则转换返回的值。如果转换的结果是 NaN,则调用对象的 toString()方法,然后再次依照前面的规则转换返回的字符串值。
// Boolean
Number(true); // 1
Number(false); // 0
// 数字
Number(12); // 12
Number(012); // 10
Number(0xa1); // 161
// null
Number(null); // 0
// undefined
Number(undefined); // NaN
// string
Number("000011"); // 11
Number("01.1"); // 1.1
Number("0xf"); // 15
Number(""); // 0
Number("Hello world!"); // NaN
// object
Number({a:0}); // NaN toString()后只为"[object Object]"
Number([1,2]); // NaN toString()后值为“1,2”
Number([1]); // 1 toString()后值为“1”
parseInt() 转换规则:
从第一位 非空字符 开始判断(忽略字符串前面的空格)
如果找到的第一位不是数字字符或者负号,parseInt() 就会返回 NaN 比如:用 parseInt()转换空字符串会返回 NaN(Number()对空字符返回 0)
如果第一个字符是数字字符,parseInt()会继续解析第二个字符,直到解析完所有后续字符或者遇到了一个非数字字符
parseInt()能够识别出八进制和十六进制
parseInt("1234blue"); // 1234
parseInt(""); // NaN
parseInt("0xA"); // 10(十六进制数)
parseInt(22.5); // 22
parseInt("070"); // 56(八进制数)
parseInt("70"); // 70(十进制数)
parseInt("0xf"); // 15(十六进制数)
在使用 parseInt()解析像八进制字面量的字符串时,ECMAScript 3 和 5 存在分歧
//ECMAScript 3 认为是 56(八进制),ECMAScript 5 认为是 70(十进制)
const num = parseInt("070");
建议在进行数值转换时,指明转换的基数
指明基数后,不需要在数值前添加‘0’或‘0x’
const num1 = parseInt("10", 2); //2 (按二进制解析)
const num2 = parseInt("10", 8); //8 (按八进制解析)
const num3 = parseInt("10", 10); //10(按十进制解析)
const num4 = parseInt("10", 16); //16(按十六进制解析)
parseFloat() 转换规则:
从第一位 非空字符 开始判断(忽略字符串前面的空格)
如果找到的第一位不是数字字符、负号或者小数点,parseFloat() 就会返回 NaN 比如:用 parseFloat()转换空字符串会返回 NaN(Number()对空字符返回 0)
如果第一个字符是三者之一,则继续解析第二个字符,直到解析完所有后续字符或者遇到了一个非数字字符 比如:字符串中的第 一个小数点是有效的,而第二个小数点就是无效的了,因此它后面的字符串将被忽略
注意:如果字符串包含的是一个可解析为整数的数(没有小数点,或者小数点后 都是零),parseFloat()会返回整数
parseFloat("1234blue"); // 1234 (整数)
parseFloat("0xA"); // 0
parseFloat("22.5"); // 22.5
parseFloat("22.34.5"); // 22.34
parseFloat("0908.5"); // 908.5
parseFloat("3.125e7"); // 31250000
《javascript高级程序设计》笔记:数组方法 segmentfault.com/a/119000001…
将数组转换成字符串
join()能够将数组用指定的字符分割成字符串
| 方法 | 用法 | 变量的值 | 表达式的值 |
|---|---|---|---|
| 假设 arr = [1,2,3] | |||
| join | arr.join() | [1,2,3] | "1,2,3" |
| - | arr.join(undefined) | [1,2,3] | "1,2,3" |
| - | arr.join("-") | [1,2,3] | "1-2-3" |
| - | arr.join(null) | [1,2,3] | "1null2null3" |
| - | arr.join({}) | [1,2,3] | "1[object Object]2[object Object]3" |
结论:
1.不给 join()方法传入任何值,或者给它传入 undefined,则使用逗号作为分隔符;
2.join()会将传入的参数隐式转换成字符串形式
3.如果数组中的某一项的值是 null 或者 undefined,那么返回的结果中以空字符串表示,toString()也遵循该准则 [1,2,undefined,3].join() ==> "1,2,,3"
toString() / toLocaleString() 也能够将数组转换成字符串;
alert() 方法会隐式调用toString()方法
调用数组的 toString() 方法会返回由数组中每个值的字符串形式拼接而成的一个以逗号分隔的字符串;
当调用数组的 toLocaleString() 方法时,它也会创建一个数组值的以逗号分隔的字符串。而与之前方法唯一的不同之处在于,这一次为了取得每一项的值,调用的是每一项的 toLocaleString() 方法,而不是 toString() 方法,下面的例子可以解释这一现象:
const person1 = {
toLocaleString : function () {
return "Nikolaos";
},
toString : function() {
return "Nicholas";
} };
const person2 = {
toLocaleString : function () {
return "Grigorios";
},
toString : function() {
return "Greg";
} };
const people = [person1, person2];
alert(people);
alert(people.toString());
alert(people.toLocaleString());
//Nicholas,Greg
//Nicholas,Greg
//Nikolaos,Grigorios
数组的增删操作
1.堆栈方法
| 方法 | 用法 | 变量的值 | 表达式的值 |
|---|---|---|---|
| 假设 arr = [1,2,3] | |||
| push | arr.push(4,5) | [1,2,3,5] | 4 |
| - | 接收任意数量的参数,把它们逐个添加到数组末尾,并返回修改后数组的长度 | ||
| pop | arr.pop() | [1,2] | 3 |
| - | arr.pop(123) | [1,2] | 3 |
| - | 从数组末尾移除最后一项,减少数组的 length 值,然后返回移除的项(有参忽略) | ||
| unshift | arr.unshift(4,5) | [4,5,1,2,3] | 5 |
| - | 接收任意数量的参数,把它们逐个添加到数组首端,并返回修改后数组的长度 | ||
| shift | arr.shift() | [2,3] | 1 |
| - | 从数组首端移除第一项,减少数组的 length 值,然后返回移除的项(有参忽略) |
2.concat方法
concat()方法可以基于当前数组中的所有项创建一个新数组。具体来说,这个方法会先创建当前数组一个副本,然后将接收到的参数添加到这个副本的末尾,最后返回新构建的数组。
1.在没有给 concat()方法传递参数的情况下,它只是复制当前数组并返回副本。
2.如果传递给 concat()方法的是一或多个数组,则该方法会将这些数组中的每一项都添加到结果数组中。
3.如果传递的值不是数组,这些值就会被简单地添加到结果数组的末尾
4.arr === arr.concat() 为false
| 方法 | 用法 | 变量的值 | 表达式的值 |
|---|---|---|---|
| 假设 arr = [1,2,3] | |||
| concat | arr.concat() | [1,2,3] | [1,2,3] |
| - | arr.concat(4,5) | [1,2,3] | [1,2,3,4,5] |
| - | arr.concat(4,5,[6,7]) | [1,2,3] | [1,2,3,4,5,6,7] |
3.slice方法
slice()方法用于数组的截取,可以接受一或两个参数,即要返回项的起始和结束位置;
1.没有参数时,会创建一个副本,但arr !== arr.slice()
1.在只有一个参数的情况下,slice()方法返回从该参数指定位置开始到当前数组末尾的所有项。
2.如果有两个参数,该方法返回起始和结束位置之间的项,但不包括结束位置的项。
3.如果 slice()方法的参数中有一个负数,则用数组长度加上该数来确定相应的位置。
4.如果结束位置小于起始位置,则返回空数组。
| 方法 | 用法 | 变量的值 | 表达式的值 |
|---|---|---|---|
| 假设 arr = [1,2,3,4,5] | |||
| slice | arr.slice() | [1,2,3,4,5] | [1,2,3,4,5] |
| - | arr.slice(1) | [1,2,3,4,5] | [2,3,4,5] |
| - | arr.slice(1,4) | [1,2,3,4,5] | [2,3,4] |
| - | arr.slice(-2,-1) | [1,2,3,4,5] | [4] |
| - | arr.slice(4,3) | [1,2,3,4,5] | [] |
4.splice方法
splice(删除的第一项索引,删除元素个数,插入的内容...)
splice()的主要用途是向数组的中部插入项,但使用这种方法的方式则有如下 3 种:
1.删除:可以删除任意数量的项,只需指定 2 个参数:要删除的第一项的位置和要删除的项数
2.插入:可以向指定位置插入任意数量的项,只需提供 3 个参数:起始位置、0(要删除的项数)和要插入的项。如果要插入多个项,可以再传入第四、第五,以至任意多个项
3.替换:可以向指定位置插入任意数量的项,且同时删除任意数量的项,只需指定 3 个参数:起始位置、要删除的项数和要插入的任意数量的项。插入的项数不必与删除的项数相等
splice()方法始终都会返回一个数组,该数组中包含从原始数组中删除的项(如果没有删除任何 项,则返回一个空数组)
| 方法 | 用法 | 变量的值 | 表达式的值 |
|---|---|---|---|
| 假设 arr = [1,2,3,4,5] | |||
| splice | arr.splice() | [1,2,3,4,5] | [] |
| - | arr.splice(1) | [2,3,4,5] | [1] |
| - | arr.splice(1,2) | [1,4,5] | [2,3] |
| - | arr.splice(-2,2) | [1,2,3] | [4,5] |
| - | arr.splice(1,2,"a","b","c","插入") | [1,"a","b","c","插入",4,5] | [2,3] |
| - | arr.splice(1,1,"替代") | [1,"替代",3,4,5] | [2] |
数组排序
1.reverse()方法
数组反转,数组自身改变,并返回反转后的值
| 方法 | 用法 | 变量的值 | 表达式的值 |
|---|---|---|---|
| 假设 arr = [1,2,3,4,5] | |||
| reverse | arr.reverse() | [5,4,3,2,1] | [5,4,3,2,1] |
2.sort()方法
参考:js中sort()方法的用法,参数以及排序原理
在默认情况下(没有参数),sort()方法按升序排列数组项——即最小的值位于最前面,最大的值排在最后面。 为了实现排序,sort()方法会调用每个数组项的 toString()转型方法,然后比较得到的字符串,以确定如何排序。即使数组中的每一项都是数值,sort()方法比较的也是字符串
因此,会出现下面这种情况:
var arr1 = ["George", "John", "Thomas", "James", "Adrew", "Martin"];
arr.sort(); // ["Adrew", "George", "James", "John", "Martin", "Thomas"]
var arr2 = ["10", "5", "40", "25", "1000", "1"];
arr.sort(); // ["1", "10", "1000", "25", "40", "5"]
如果想按照其他标准进行排序,就需要提供比较函数,该函数要比较两个值,然后返回一个用于说明这两个值的相对顺序的数字。比较函数应该具有两个参数 a 和 b,其返回值如下:
若 a 小于 b,在排序后的数组中 a 应该出现在 b 之前,则返回一个小于 0 的值。
若 a 等于 b,则返回 0。
若 a 大于 b,则返回一个大于 0 的值。
《javascript高级程序设计》笔记:短路运算 segmentfault.com/a/119000001…
在逻辑运算中,转换为boolean类型的值后为false的情况: 0、""、null、false、undefined、NaN,其他都为true
|| 短路运算:仅当前者不成立时才去执行后者
原理: || 先计算第一个运算数,如果可以被转换成true,则返回左边这个表达式的值,否则计算第二个运算数
&&短路运算 仅当前者成立时采取执行后者
原理:&& 先计算第一个表达式,若为假,就不会去处理第二个表达;否则继续处理后继表达式
《javascript高级程序设计》笔记:Sting类型及其转换 segmentfault.com/a/119000001…
字符串的不可变性:操作字符串时并不会在原来的字符串上修改,而是重新开辟内存,生成新的字符串,把变量重新指向新的字符串,原来的字符串不会马上消失,要等待垃圾回收机制回收
字符串拼接的方法:+、使用Array的join("")、修改字符串原型对象添加方法处理
转换成字符串:调用toString方法、使用String构造函数进行转换
《javascript高级程序设计》笔记:Number类型 segmentfault.com/a/119000001…
《javascript高级程序设计》笔记:undefined和null segmentfault.com/a/119000001…
在使用 var 声明变量但未对其加以初始化时,这个变量的值就是 undefined;
从逻辑角度来看,null 值表示一个空对象指针,而这也正是使用 typeof 操作符检测 null 值时会返回"object"的原因
null表示"没有对象",即该处不应该有值。典型用法是:
(1) 作为函数的参数,表示该函数的参数不是对象。
(2) 作为对象原型链的终点。
undefined表示"缺少值",就是此处应该有一个值,但是还没有定义。典型用法是:
(1)变量被声明了,但没有赋值时,就等于undefined。
(2)调用函数时,应该提供的参数没有提供,该参数等于undefined。
(3)对象没有赋值的属性,该属性的值为undefined。
(4)函数没有返回值时,默认返回undefined
《javascript高级程序设计》笔记:变量及变量检测 segmentfault.com/a/119000001…
ECMAScript 中有 5 种简单数据类型(也称为基本数据类型):Undefined、Null、Boolean、Number 和 String。还有 1 种复杂数据类型—Object,Object 本质上是由一组无序的键值对组成的
1. 变量检测—typeof
typeof始终返回的是下列的某个字符串
"undefined"—如果这个值未定义;
"boolean"—如果这个值是布尔值;
"string"—如果这个值是字符串;
"number"—如果这个值是数值;
"object"—如果这个值是对象或 null;
"function"—如果这个值是函数
注意:
特殊值null被认为是一个空的对象引用,因此typeof null === 'object'
typeof会将函数类型识别为'function',虽然函数不是单独的数据类型
2. 变量检测—instanceof
语法: result = variable instanceof constructor
如果变量是给定引用类型(根据它的原型链来识别)的实例,那么 instanceof 操作符就会返回 true
注意:
- 在检测一个引用类型值和 Object 构造函数时,instanceof 操作符始终会返回 true,因为
所有引用类型的值都是 Object 的实例 - 如果使用 instanceof 操作符检测基本类型的值,则该操作符始终会返回 false,因为基本类型不是对象
instanceof 能够确定引用类型的实例对象是否在某条原型链上,但是无法精准的判断变量到底是什么类型,而且在面对基本类型时都会返回false...
3. 变量检测—Obect.prototype.toString
这个方法是检测数据类型最准确的方法(在不认为更改对象原型方法toString的前提下),建议将其封装为函数做判别
Object.prototype.toString.call(123) //'[object Number]'
Object.prototype.toString.call('123') //'[object String]'
Object.prototype.toString.call(undefined) //'[object Undefined]'
Object.prototype.toString.call(true) //'[object Boolean]'
Object.prototype.toString.call({}) //'[object Object]'
Object.prototype.toString.call([]) //'[object Array]'
Object.prototype.toString.call(function(){}) //'[object Function]'
Object.prototype.toString.call(new Date) // '[object Date]'
函数封装:
// 判断是否为函数
function isFunction(fn) {
return Object.prototype.toString.call(fn) === '[object Function]';
}
// 判断是否为数组
function isArray(o) {
return Object.prototype.toString.call(o) === '[object Array]';
}
《javascript高级程序设计》笔记:Function类型 segmentfault.com/a/119000001…
1. 几个概念
函数:将代码进行封装, 复用的逻辑单元(代码)
对象:无序键值对的集合
数组:有序键值对的集合, 数组的索引号就是键
属性:对象属性的值是一个普通的数据
方法:对象的属性是一个函数
对象的成员:包括属性和方法
函数也是对象,函数名是一个指向函数对象的指针。因此,函数也可以作为参数传递
2. 函数的三种创建方式
2.1 函数表达式
标准语法:
var fn = function(){}; // 只能在声明之后调用
有一种写法也需要注意,可能在面试题中会遇到:
var fn = function fn1(){}; // 不会报错
有这样一个例子,能够很好的区分两种写法的差异
// 标准写法
var fn = function(){
console.log(fn); // function (){ console.log(fn) }
};
fn();
console.log(fn); // function (){ console.log(fn) }
// 非主流写法
var fn1 = function fn2() {
console.log(fn1);
console.log(fn2);
}
fn1();
console.log(fn1);
console.log(fn2);
结论:
函数表达式声明方式中,function后面也可以添加函数名,但仅能在函数内部使用
2.2 函数声明
语法:
function fn(){}; // 能够在作用域下的任何地方使用
2.3 构造函数声明
语法:
var fn = new Function(param1, param2, body)
Function构造函数可以接受任意数量的参数,但最后一个参数始终被看做函数体,相当于一个小型的js编译器(执行效率低)
var fn = new Function(num1, num2, “return num1+num2”);
// 等价于
function fn(num1, num2) {
return num1 + num2;
}
// 或
var fn = function(num1, num2) {
return num1 + num2;
}
2.3 函数声明和函数表达式的区别
1 函数声明会把整个函数体提升到最前面function fn() {},因此调用的位置没有先后之分;函数表达式只会把函数名字提升var fn = function() {}; 此时函数作为数据,因此必须先声明后使用
2 函数声明不能够出现在其他语句块中!函数声明能够出现的位置: 全局环境中其他函数内部
个人建议:从代码可维护性出发,尽量使用函数表达式的方式来声明函数
3. 函数内部属性
1.name属性
函数名.name => 获取字符串类型的函数名称
// 外部
function fn1(){};
console.log(fn1.name); // fn1
// 内部
function fn2() {
console.log(fn2.name); // fn2
}
fn2();
2.length属性
函数名.length => 获取形参的个数,未传参时返回0
// 外部
function fn1(a,b){};
console.log(fn1.length); // 2
// 内部
function fn2(a,b,c) {
console.log(fn2.length); // 3
}
fn2();
3.caller属性
函数名.caller => 获得调用函数的函数引用(函数在哪被调用),如果在全局中调用当前函数,值为null
var inner = function() {
alert(inner.caller);
};
var outer = function() {
inner();
};
outer(); // function() { inner(); };
inner(); // null
4.arguments属性
arguments只能在函数内部使用,用来获取传入的实参。是一个伪数组
其内部有如下属性:
arguments.length:获取实参的个数
arguments.callee:获取当前函数的引用,一般用在匿名函数递归中
// 阶乘
function factorial(num) {
if(num <= 1) {
return 1;
} else {
return num * arguments.callee(num - 1);
}
}
5.this属性
this会在下一篇博客中详细讲解,先记住一句话:
this的指向和函数执行的环境相关,与它声明的环境无关
4.函数的形参和实参
形参:函数声明时的参数,起占位作用——函数名.length(形参个数)
实参:函数调用时的参数,实际参与运算的值—arguments.length(实参个数)
当形参个数大于实参时,多余的形参将设置成undefined
当实参个数大于形参时,无法直接获得所有的实参,通过arguments获得实参
参数传递的理解:形参相当于一个具有局部作用域不需要声明的和实参指向相同堆地址对象的值,其类型与实参相同
《javascript高级程序设计》笔记_数组 稀疏数组 伪数组 segmentfault.com/a/119000001…
牢记:
JavaScript中的数组并不像我们在C或java等语言中遇到的常规数组,在js中数组并不是起始地址+长度构成的一片连续的地址空间。
javascript中数组其实就是个对象,只不过会自动管理一些"数字"属性和length属性罢了。
说的更直接一点,JavaScript中的数组根本没有索引,因为索引应该是数字,而JavaScript中数组的索引其实是字符串
创建数组
构造函数方式
1.无参构造函数,创建一空数组
var colors = new Array();
2.创建指定长度的数组,一个数字参数构造函数,指定数组长度(由于数组长度可以动态调整,作用并不大)
var colors = new Array(5);
3.带有初始化数据的构造函数,创建数组并初始化参数数据
var colors = new Array("red", "blue", "green");
使用Array构造函数是可以省略new操作符,如下:
var colors = Array(3); // 创建一个包含 3 项的数组
var names = Array("Greg"); // 创建一个包含 1 项,即字符串"Greg"的数组
注意,这里有个坑!
同样是使用构造函数的方式,并传递一个值,new Array(2)与new Array("2")是有区别的
new Array(2) // ["undefined", "undefined"]
new Array("2") // ["2"]
字面量方式
数组字面量由一对包含数组项的方括号表示,多个数组项之间以逗号隔开,如下所示:
var colors = ["red", "blue", "green"]; // 创建一个包含 3 个字符串的数组
var names = []; // 创建一个空数组
var values = [1,2,]; // 不要这样!这样会创建一个包含 2 或 3 项的数组
var options = [,,,,,]; // 不要这样!这样会创建一个包含 5 或 6 项的数组
字面量方式创建数组的兼容问题
| 字面量数组长度 | IE8及以下 | IE8以上 |
|---|---|---|
| ["red", "blue", "green"] | 3 | 3 |
| ["red", "blue", , "green"] | 4 | 4 |
| ["red", "blue", "green", ,] | 4 | 3 |
| [, , , , ,] | 6 | 5 |
数组 VS 对象
javascript中数组其实就是个对象,只不过会自动管理一些"数字"属性和length属性
var a1=[1,2,3,4];
console.log(a1[0]); //1
var i=1;
console.log(a1[i]); //2
console.log(a1[++i]); //3
数组也是对象,我们可以使用索引的奥秘在于,数组会把索引值转换为对应字符串(1=>”1”)作为对象属性名,验证:
console.log(1 in a1);//true,确实是一个属性
索引特殊性在于数组会自动更新length属性,当然因为JavaScript语法规定数字不能作为变量名,所以我们不能显示使用array.1这样的格式。由此可见其实负数,甚至非数字”索引“都是允许的,只不过这些会变成数组的属性,而不是索引
var a = new Array(1,2,3);
a[-10] = "a[-10]";
a["sss"] = "sss";
console.log(a); // [1, 2, 3, -10: "a[-10]", sss: "sss"]
为对象添加数组方法
var blankArray = [];
var obj = {
splice: blankArray.splice,
push: blankArray.push,
unshift: blankArray.unshift,
pop: blankArray.pop,
shift: blankArray.shift
};
obj.push();
obj.unshift();
obj.pop();
obj.shift();
数组中的length属性
数组的length属性不是只读的
1.通过设置这个属性,可以从数组的末尾移除项或向数组中添加新项
var colors = ["red", "blue", "green"]; // 创建一个包含 3 个字符串的数组 colors.length = 2;
alert(colors[2]); //undefined
2.利用 length 属性也可以方便地在数组末尾添加新项
var colors = ["red", "blue", "green"]; // 创建一个包含 3 个字符串的数组
colors[colors.length] = "black"; //(在位置3)添加一种颜色
colors[colors.length] = "brown"; //(在位置4)再添加一种颜色
3.利用length属性删除/清空数组
var arr = [1,2,3,4];
arr.length = 2;
console.log(arr[2]); // "undefined"
arr.length = 0;
console.log(arr); // []
密集数组与稀疏数组
密集数组:在Java和C语言中,数组是一片连续的存储空间,有着固定的长度。加入数组其实位置是address,长度为n,那么占用的存储空间是address[0],address[1],address[2].......address[n-1]。即数组元素之间是紧密相连的,不存在空隙。如下的js代码创建的就是一个密集数组
var data = [3,1,6,9,2];
稀疏数组:与密集数组相反,javascript并不强制要求数组元素是紧密相连的,即允许间隙的存在。如下的js代码是合法的:
var sparse = new Array();
sparse[0] = 0;
sparse[3] = 3;
alert(sparse[0]);//输出0
alert(sparse[1]);//输出undefined
密集数组的创建: var dense = Array.apply(null, Array(3));
稀疏数组与密集数组便利区别:
// 稀疏数组
var array = new Array(3);
array[2] = "name";
for(var a in array){
console.log("index=" + a + ",value=" + array[a]);
}
// 密集数组
var dense = Array.apply(null, Array(3));
dense[2] = "name";
for(var a in dense){
console.log("index=" + a + ",value=" + dense[a]);
}
// 结果
// 稀疏数组:index=2,value=name
// 密集数组:index=0,value=undefined
// index=1,value=undefined
// index=2,value=name
差别:稀疏数组只遍历了已存在元素的次数,密集数组遍历了arr.length次
伪数组(类数组)
特点:
1.具有length属性;
2.按索引方式存储数据;
3.不具有数组的push()、pop()等方法;
伪数组无法直接调用数组方法或期望length属性有什么特殊的行为,不具有数组的push()、pop()等方法,但仍可以对真正数组遍历方法来遍历它们。
常见的伪数组类型:
1.function内的arguments对象;
2.调用getElementsByTagName, document.childNodes之类的,返回的NodeList对象都属于伪数组;
3.自定义对象的伪数组;
如何将伪数组转换成数组?
1.声明一个空数组,通过遍历伪数组把它们重新添加到新的数组(不推荐)
var links = document.querySelectorAll('a');
var arr = [];
for (var i = 0; i < links.length; i++) {
arr[arr.length] = links[i]
}
2.使用数组的slice()方法 它返回的是数组,使用call或者apply指向伪数组
var arr = Array.prototype.slice.call(links);
3.原型继承
links.__proto__ = Array.prototype;
4.ES6中数组的新方法 from()
var arr = Array.from(links);
清空数组的几种方式
1.length赋值为0
var arr = [1,2,3,4];
arr.length = 0;
console.log(arr); // 输出 [],空数组,即被清空了
2.splice
var arr = [1,2,3,4];
arr.splice(0,arr.length);
console.log(arr); // 输出 [],空数组,即被清空了
3.赋值为[]
var arr = [1,2,3,4];
arr = []; // 赋值为一个空数组以达到清空原数组