数组 Array
本质上,数组属于一种特殊的对象。typeof
运算符会返回数组的类型是 object
-
数组的特殊性体现在,它的键名是按次序排列的一组整数(0,1,2...)
// Object.keys方法返回数组的所有键名。 var arr = ['a', 'b', 'c'];
Object.keys(arr); // ["0", "1", "2"] // 可以看到数组的键名就是整数0、1、2。 - 数组的键名其实也是字符串。之所以可以用数值读取,是因为非字符串的键名会被转为字符串
- JavaScript 使用一个32位整数,保存数组的元素个数。这意味着,数组成员最多只有 4294967295 个(232 - 1)个,也就是说
length
属性的最大值就是 4294967295
与普通对象的区别是 "数组使用数字作为索引 [index] 来操作属性"。index 从 0 开始。
数组的存储性能相对较好。
var arr = ['唐僧','孙悟空','猪八戒','沙和尚','白龙马'];
1. 创建数组对象
var arr = new Array(); // typeof arr 返回 object
2. 给数组添加对象
arr[] = ; // console.log(arr) 打印 "1"
arr[] = ; // console.log(arr) 打印 "1,11"
arr[] = ; // console.log(arr) 打印 "1,11,22"
3. 读取数组对象
console.log(arr[0]); //
console.log(arr[1]); //
console.log(arr[2]); //
console.log(arr[3]); // undefined 不会报错
4. 获取数组长度
- arr.length 总是返回 "最大索引值+1" ,所以尽量避免创建不连续数组
var arr = [1,2,3];
console.log(arr.length); // 返回 3 ,因为有 3 个元素 arr[0],arr[1],arr[2] arr.[100] = 100; // 此时数组有4个元素 arr[0],arr[1],arr[2],arr[100]
console.log(arr.length); // 但是会返回 101 , 实际只有 4 个元素, 这四个元素以外的其他 97 个元素值都为 undefined, 且用 in 判断时返回 false - 清空数组的一个有效方法,就是将 arr.length属性设为 0
var arr = [ 'a', 'b', 'c' ]; arr.length = 0;
arr // [] - b
- b
5. 在数组最后添加元素
// 根据上一个特性,可以在数组最后追加一个元素
arr[arr.length] = 666;
1. 使用字面量来创建数组
var arr = []; // 和 new Array() 效果相同
2. 在创建时指定元素
var arr = [0,1,2,3,4]; // 等同于
var arr = new Array(0,1,2,3,4);
3. 创建一个只有一个元素的数组
var arr = [10]; // 此时数组只有1个元素,arr[0] = 10; var arr = new Array(10); // 此时创建了一个长度为10的数组!!!
// 每个元素的值都为 undefined
4. 数组中元素可以放任意数据类型的数据
var arr = ["Hello","How",,,,null,undefined,true,false]; // 数组元素是对象
var sun = {name:"孙悟空"};
arr[arr.length] = sun;
console.log(arr[arr.length-].name); // 将会打印 "孙悟空" // 数组元素是函数
var arr = [
function(){console.log("Hello!"},
function(){console.log("Hi!")}
]; // 数组 里面放 数组
var newArr = [["","",""],[,,],["","",""]]; // 混合着放
var arr = [
{a: }, // 对象
[, , ], // 数组
function() {return true;} // 函数
]; arr[] // Object {a: 1}
arr[] // [1, 2, 3]
arr[] // function (){return true;}
5. 遍历数组
-
for...in
循环不仅可以遍历对象,也可以遍历数组,毕竟数组只是一种特殊对象var a = [1, 2, 3]; for (var i in a) {
console.log(a[i]); // 1 2 3
} - 但是,
for...in
不仅会遍历数组所有的数字键,还会遍历非数字键。所以,不推荐使用for...in
遍历数组。var a = [1, 2, 3];
a.foo = true; for (var key in a) {
console.log(key); // 0 1 2 foo
console.log(key); // 1 2 3 true
} - 数组的遍历可以考虑使用
for
循环 或while
循环var a = [1, 2, 3]; // for循环
for(var i = 0; i < a.length; i++) {
console.log(a[i]);
} // while循环
var i = 0;
while (i < a.length) {
console.log(a[i]);
i++;
} // 逆向遍历
var l = a.length;
while (l--) {
console.log(a[l]);
} -
数组的 arr.forEach() 方法,也可以用来遍历数组
var colors = ['red', 'green', 'blue'];
colors.forEach(function (color) {
console.log(color); // red green blue
}); - 数组的空位 hole 不影响
length
属性- 当数组的某个位置是空元素,即两个逗号之间没有任何值,我们称该数组存在空位(hole)
- 如果最后一个元素后面有逗号,并不会产生空位。也就是说,有没有这个逗号,结果都是一样的。
var a = ['a' , , 'c'];
a.length // 3
// 数组的空位是可以读取的,返回undefined
a[1] // undefined
a[0] // 'a'
a[2] // 'c'var a = [1, 2, 3,];
a.length // 3
- delete 命令删除一个数组成员,会形成空位,并且不会影响
length
属性var a = [1, 2, 3];
delete a[1]; a[1] // undefined
a.length // - 数组的某个位置是空位,与某个位置是
undefined
,是不一样的。- 如果是空位,使用数组的
forEach
方法、for...in
结构、以及Object.keys
方法进行遍历,空位都会被跳过。var a = [, , ,]; a.forEach(function (x, i) {
console.log(i + '. ' + x); // 不产生任何输出
}) for (var i in a) {
console.log(i); // 不产生任何输出
} Object.keys(a) // [] - 如果某个位置是 undefined,遍历的时候就不会被跳过
var a = [undefined, undefined, undefined]; a.forEach(function (x, i) {
console.log(i + '. ' + x);
});
// 0. undefined
// 1. undefined
// 2. undefined for (var i in a) {
console.log(i); // 0 1 2
} Object.keys(a) // ['0', '1', '2']
- 如果是空位,使用数组的
6. 类似数组对象
-
如果一个对象的所有键名都是正整数或零,并且有
length
属性,那么这个对象就很像数组,语法上称为“类似数组的对象”(array-like object)。var obj = {
0: 'a',
1: 'b',
2: 'c',
length: 3
}; obj[0] // 'a'
obj[1] // 'b'
obj.length //
obj.push('d') // TypeError: obj.push is not a function
// 因为它们不具备数组特有的方法。
// 对象obj没有数组的push方法,使用该方法就会报错。 - 有一个问题,这种
length
属性不是动态值,不会随着成员的变化而变化 - 典型的“类似数组的对象”有 函数的
arguments
对象,以及大多数 DOM 元素集,还有字符串。 -
数组的
slice
方法可以将 “类似数组的对象” 变成真正的数组var arr = Array.prototype.slice.call(arrayLike);
- 通过
call()
,可以把forEach()
嫁接到arrayLike
上面调用- 如:在
arguments
对象上面调用forEach
方法。// forEach 方法
function logArgs() {
Array.prototype.forEach.call(arguments, function (elem, i) {
console.log(i + '. ' + elem);
});
} // 等同于 for 循环
function logArgs() {
for (var i = 0; i < arguments.length; i++) {
console.log(i + '. ' + arguments[i]);
}
}
- 如:在
- 注意,这种方法比直接使用数组原生的
forEach
要慢, - 所以最好还是先将“类似数组的对象”转为真正的数组,然后再直接调用数组的
forEach
方法。var arr = Array.prototype.slice.call('abc');
arr.forEach(function (chr) {
console.log(chr); // a b c
});
7. 数组的静态方法
- Array.isArray() 判断变量是否是数组
var arr = [1, 2, 3]; typeof arr // "object"
Array.isArray(arr) // true
8. 数组的实例方法
- .valueOf() 数组的
valueOf
方法 返回数组本身。。。不同对象的valueOf
方法不尽一致 - .toString() 数组的
toString
方法 返回数组的字符串形式 - .push() 用于在数组的末端添加一个或多个元素,并返回添加新元素后的数组长度。注意,该方法会改变原数组
var arr = []; arr.push(1); //
arr.push('a'); //
arr.push(true, {}); // // arr = [1, 'a', true, {}]
- .pop() 用于删除数组的最后一个元素,并返回该元素。注意,该方法会改变原数组
-
var arr = ['a', 'b', 'c']; arr.pop() // 'c' // arr = ['a', 'b']
对空数组使用
pop
方法,不会报错,而是返回undefined
-
push
和pop
结合使用,就构成了“后进先出”的栈结构(stack)
-
- .shift() 用于删除数组的第一个元素,并返回该元素。注意,该方法会改变原数组
-
shift
方法可以遍历并清空一个数组。var list = [1, 2, 3, 4, 5, 6];
var item; while (item = list.shift()) {
console.log(item);
} list // [] -
push
和shift
结合使用,就构成了“先进先出”的队列结构(queue)
-
- .unshift() 用于在数组的第一个位置添加元素,并返回添加新元素后的数组长度。注意,该方法会改变原数组
-
unshift
方法可以接受多个参数,这些参数都会添加到目标数组头部
-
- .join() 以指定参数作为分隔符,将所有数组成员连接为一个字符串返回。如果不提供参数,默认用逗号分隔。
-
var a = [1, 2, 3, 4]; a.join(' '); // '1 2 3 4'
a.join(' | '); // "1 | 2 | 3 | 4"
a.join(); // "1,2,3,4"[undefined, null].join('#') // '#' ['a',, 'b'].join('-') // 'a--b'
如果数组成员是
undefined
或null
或空位,会被转成空字符串 -
通过
call
方法,这个方法也可以用于字符串或类似数组的对象Array.prototype.join.call('hello', '-') // "h-e-l-l-o" var obj = { 0: 'a', 1: 'b', length: 2 };
Array.prototype.join.call(obj, '-') // 'a-b'
-
- .concat() 用于多个数组的合并。
- 它将新数组的成员,添加到原数组成员的后部,然后返回一个新数组,原数组不变
['hello'].concat(['world']); // ["hello", "world"] ['hello'].concat(['world'], ['!']); // ["hello", "world", "!"] [].concat({a: 1}, {b: 2}); // [{ a: 1 }, { b: 2 }] [2].concat({a: 1}); // [2, {a: 1}]
- 如果数组成员包括对象,
concat
方法返回当前数组的一个浅拷贝。所谓“浅拷贝”,指的是新数组拷贝的是对象的引用- 改变原对象以后,新数组跟着改变
- .reverse() 颠倒排列数组元素,返回改变后的数组。注意,该方法将改变原数组
- .slice(start, end) 用于提取目标数组的一部分,返回一个新数组,原数组不变
- 它的第一个参数为起始位置(从0开始),
- 第二个参数为终止位置(但该位置的元素本身不包括在内)。如果省略第二个参数,则一直返回到原数组的最后一个成员
- 如果
slice
方法的参数是负数,则表示倒数计算的位置 - 如果第一个参数大于等于数组长度,或者第二个参数小于第一个参数,则返回空数组。
var a = ['a', 'b', 'c'];
a.slice(-2); // ["b", "c"]
a.slice(-2, -1); // ["b"] var a = ['a', 'b', 'c'];
a.slice(4); // []
a.slice(2, 1); // []-
Array.prototype.slice().call()方法的一个重要应用,是 将类似数组的对象转为真正的数组
Array.prototype.slice.call({ 0: 'a', 1: 'b', length: 2 }) // ['a', 'b'] Array.prototype.slice.call(document.querySelectorAll("div"));
Array.prototype.slice.call(arguments);
- .splice(start, count, addElement1, addElement2, ...)
- 用于删除原数组的一部分成员,并可以在删除的位置添加新的数组成员,返回值是被删除的元素。注意,该方法会改变原数组
- 第一个参数是删除的起始位置(从0开始),起始位置如果是负数,就表示从倒数位置开始删除。
- 第二个参数是被删除的元素个数,
- 如果后面还有更多的参数,则表示这些就是要被插入数组的新元素。
- 如果只提供第一个参数,从起始位置开始,删除后面所有元素组成一个数组返回
- .sort() 对数组成员进行排序,默认是按照字典顺序排序。排序后,原数组将被改变
数值会被先转成字符串,再按照字典顺序进行比较所以
101
排在11
的前面- 如果想让
sort
方法按照自定义方式排序,可以传入一个函数作为参数- 函数本身接受两个参数,表示进行比较的两个数组成员。如果该函数的返回值大于
0
,表示第一个成员排在第二个成员后面;其他情况下,都是第一个元素排在第二个元素前面。[10111, 1101, 111].sort(function (a, b) {
return a - b;
}); // [111, 1101, 10111][
{ name: "张三", age: 30 },
{ name: "李四", age: 24 },
{ name: "王五", age: 28 }
].sort(function (o1, o2) {
return o1.age - o2.age;
}); // [
// { name: "李四", age: 24 },
// { name: "王五", age: 28 },
// { name: "张三", age: 30 }
// ]
- 函数本身接受两个参数,表示进行比较的两个数组成员。如果该函数的返回值大于
- .map() 方法
- 将数组的所有成员依次传入参数函数,
- 然后把每一次的执行结果组成一个新数组返回。。。原数组没有变化
var numbers = [1, 2, 3]; numbers.map(function (n) {
return n + 1;
}); // [2, 3, 4] numbers // [1, 2, 3]
- 该函数调用时,
map
方法向它传入三个参数:当前成员 elem、当前位置 index、数组本身 arr[1, 2, 3].map(function(elem, index, arr) {
return elem * index;
}); // [0, 2, 6]
-
map
方法还可以接受第二个参数,用来绑定回调函数内部的this
变量var arr = ['a', 'b', 'c']; [1, 2].map(function (e) {
return this[e];
}, arr) // ['b', 'c']
- 如果数组有空位,
map
方法的回调函数在这个位置不会执行,会跳过数组的空位 (不会跳过不会跳过undefined
和null
)var f = function (n) { return 'a' }; [1, undefined, 2].map(f); // ["a", "a", "a"]
[1, null, 2].map(f); // ["a", "a", "a"]
[1, , 2].map(f); // ["a", , "a"]
- .forEach()
- 与
map
方法很相似,也是对数组的所有成员依次执行参数函数 - 但是,
forEach
方法不返回值,只用来操作数据。 - 这就是说,如果数组遍历的目的是为了得到返回值,那么使用
map
方法,否则使用forEach
方法 - 参数是一个函数,该函数同样接受三个参数:当前成员 elem、当前位置 index、数组本身 arr
forEach
方法也可以接受第二个参数,绑定参数函数的 this 变量-
forEach
方法也会跳过数组的空位 , 不会跳过undefined
和null
var out = []; [1, 2, 3].forEach(function(elem) {
this.push(elem * elem);
}, out); out // [1, 4, 9]-
注意 :
-
forEach
方法无法中断执行,总是会将所有成员遍历完。 - 如果希望符合某种条件时,就中断遍历,要使用
for
循环
-
- 与
- .filter() 用于过滤数组成员,满足条件的成员组成一个新数组返回
- 参数是一个函数,所有数组成员依次执行该函数,返回结果为
true
的成员组成一个新数组返回。该方法不会改变原数组。[1, 2, 3, 4, 5].filter(function (elem) {
return (elem > 3);
}); // [4, 5] 将大于3的数组成员,作为一个新数组返回 var arr = [0, 1, 'a', false]; arr.filter(Boolean); // [1, "a"] 获取所有布尔值为true的成员
- 函数可以接受三个参数:当前成员 elem、当前位置 index、数组本身 arr
[1, 2, 3, 4, 5].filter(function (elem, index, arr) {
return index % 2 === 0;
}); // [1, 3, 5]
-
filter
方法还可以接受第二个参数,用来绑定参数函数内部的this
变量var obj = { MAX: 3 };
var myFilter = function (item) {
if (item > this.MAX) return true;
}; var arr = [2, 8, 3, 4, 1, 3, 2, 9];
arr.filter(myFilter, obj); // [8, 4, 9]
- 参数是一个函数,所有数组成员依次执行该函数,返回结果为
- .some() 和 every()
- 这两个方法类似“断言”(assert),返回一个布尔值,表示判断数组成员是否符合某种条件
- 接受一个函数作为参数,所有数组成员依次执行该函数。然后返回一个布尔值
- 该函数接受三个参数:当前成员 elem、当前位置 index、数组本身 arr
-
some
方法是只要一个成员的返回值是true
,则整个some
方法的返回值就是true
,否则返回false
var arr = [1, 2, 3, 4, 5];
arr.some(function (elem, index, arr) {
return elem >= 3;
}); // true
-
every
方法是所有成员的返回值都是true
,整个every
方法才返回true
,否则返回false
var arr = [1, 2, 3, 4, 5];
arr.every(function (elem, index, arr) {
return elem >= 3;
}); // false
- 注意,对于空数组,
some
方法返回false
,every
方法返回true
,回调函数都不会执行
- .reduce() 和 .reduceRight()
- 依次处理数组的每个成员,最终累计为一个值。
- 它们的差别是 :
-
reduce
是从左到右处理(从第一个成员到最后一个成员) -
reduceRight
则是从右到左(从最后一个成员到第一个成员),其他完全一样
-
// 求出数组所有成员的和
[1, 2, 3, 4, 5].reduce(function (a, b) {
console.log(a, b);
return a + b;
}); // 1 2 第一次执行,a
是数组的第一个成员1
,b
是数组的第二个成员2
// 3 3 第二次执行,a
为上一轮的返回值3
,b
为第三个成员3
// 6 4 第三次执行,a
为上一轮的返回值6
,b
为第四个成员4
// 10 5 第四次执行,a
为上一轮返回值10
,b
为第五个成员5
// 最后结果:15-
reduce()
和reduceRight()
的第一个参数都是一个函数。该函数接受以下四个参数- 累积变量,默认为数组的第一个成员
- 当前变量,默认为数组的第二个成员
- 当前位置(默认从0开始)
- 原数组
- 只有前两个是必须的,后两个则是可选的
- 如果要对累积变量指定初值,可以把它放在
reduce
方法和reduceRight
方法的第二个参数[1, 2, 3, 4, 5].reduce(function (a, b) {
return a + b;
}, 10); //
// 指定参数a的初值为10,所以数组从10开始累加,最终结果为25。
// 注意,这时b是从数组的第一个成员开始遍历
- 由于空数组取不到初始值,
reduce
方法会报错。这时,加上第二个参数,就能保证总是会返回一个值 function substract(prev, cur) {
return prev - cur;
}
// 比较 reduce() reduceRight()
[3, 2, 1].reduce(substract) //
[3, 2, 1].reduceRight(substract) // -4- 还可以用来做一些遍历相关的操作。比如,找出字符长度最长的数组成员
function findLongest(entries) {
return entries.reduce(function (longest, entry) {
return entry.length > longest.length ? entry : longest;
}, '');
} findLongest(['aaa', 'bb', 'c']); // "aaa"
- .indexOf() 返回给定元素在数组中第一次出现的位置,如果没有出现则返回
-1
- 还可以接受第二个参数,表示搜索的开始位置
var a = ['a', 'b', 'c']; a.indexOf('b'); //
a.indexOf('y'); // -1 ['a', 'b', 'c'].indexOf('a', 1); // -1 结果为-1,表示没有搜索到
- 还可以接受第二个参数,表示搜索的开始位置
- .lastIndexOf() 返回给定元素在数组中最后一次出现的位置,如果没有出现则返回
-1
var a = [2, 5, 9, 2];
a.lastIndexOf(2); // 3 a.lastIndexOf(7); // -1[NaN].indexOf(NaN) // -1
[NaN].lastIndexOf(NaN) // -1
- 不能用来搜索
NaN
的位置,即它们无法确定数组成员是否包含NaN
- 有不少返回的还是数组,所以可以链式使用
var users = [
{name: 'tom', email: 'tom@example.com'},
{name: 'peter', email: 'peter@example.com'}
]; users
.map(function (user) {
return user.email;
})
.filter(function (email) {
return /^t/.test(email);
})
.forEach(function (email) {
console.log(email);
});
// 先产生一个所有 Email 地址组成的数组,然后再过滤出以t开头的 Email 地址,最后将它打印出来
(66)Wangdao.com第十一天_JavaScript 数组Array的更多相关文章
-
(68)Wangdao.com第十一天_JavaScript 数组的常用方法
数组的常用方法: 向数组末尾添加一个或多个元素,返回新长度 var arr = new Array(); arr.push("唐僧"); // 返回 1 删除数组最后一个元素,返回 ...
-
(67)Wangdao.com第十一天_JavaScript 数组的遍历
for 普通方式遍历 var arr = [0,1,2,3,4,5,6]; for(i=0; i<arr.length; i++){ document.write("["+i ...
-
(70)Wangdao.com第十一天_JavaScript 日期对象 Date
日期对象 Date 表示一个时间 Date 对象是 JavaScript 原生的时间库 它以1970年1月1日00:00:00作为时间的零点,可以表示的时间范围是前后各1亿天(单位为毫秒) 时间零点( ...
-
(71)Wangdao.com第十一天_JavaScript 数学对象 Math
Math 对象 封装了数学相关的 属性和方法. 和其他对象不一样,Math 不是一个构造函数,所以不能 new 生成实例, 其所有属性和方法都必须在 Math 对象上调用. 静态属性 Math.PI ...
-
(69)Wangdao.com第十一天_JavaScript 指定函数对象的 this 上下文对象
指定函数对象的 this 上下文对象 即调用函数对象的 .call() 或者 .apply() 方法 指定 this 指向指定的对象. function myFun(){ document.write ...
-
python3.4学习笔记(十一) 列表、数组实例
python3.4学习笔记(十一) 列表.数组实例 #python列表,数组类型要相同,python不需要指定数据类型,可以把各种类型打包进去#python列表可以包含整数,浮点数,字符串,对象#创建 ...
-
js常用数据类型(Number,String,undefined,boolean) 引用类型( function,object,null ),其他数据类型( 数组Array,时间Date,正则RegExp ),数组与对象的使用
js常用数据类型 数字类型 | 字符串类型 | 未定义类型 | 布尔类型 typeof()函数查看变量类型 数字类型 Number var a1 = 10; var a2 = 3.66; conso ...
-
JavaScript中的内置对象-8--1.Array(数组)-Array构造函数; 数组的栈方法; 数组的转换方法; 数组的操作方法; 删除-插入-替换数组项; ECMAScript为数组实例添加的两个位置方法;
JavaScript内置对象-1Array(数组) 学习目标 1.掌握任何创建数组 2.掌握数值元素的读和写 3.掌握数组的length属性 如何创建数组 创建数组的基本方式有两种: 1.使用Arra ...
-
我理解的数据结构(一)—— 数组(Array)
我理解的数据结构(一)-- 数组(Array) 首先,我是一个phper,但是毕竟php是一个脚本语言,如果使用脚本语言去理解数据结构具有一定的局限性.因为脚本语言是不需要编译的,如果你的语法写的不错 ...
随机推荐
-
magento安装
最近在做一个Magento 1.7.0.2的站,在安装环节Magento一直报错Database server does not support the InnoDB storage engine. ...
-
IntelliJ IDEA常用设置及快捷键
IntelliJ IDEA是一款非常优秀的JAVA编辑器,初学都可会对其中的一些做法感到很别扭,刚开始用的时候我也感到很不习惯,在参考了网上一些文章后在这里把我的一些经验写出来,希望初学者能快速适应它 ...
-
本地计算机上的MSSQLSERVER服务启动后又停止了。一些服务自动停止,如果它们没有什么可做的
本地计算机上的MSSQLSERVER服务启动后又停止了.一些服务自动停止,如果它们没有什么可做的 笔者ASP运行环境:操作系统为Windows XP SP2,IIS的版本为默认的5.1,数据库为SQL ...
-
tab切换jquery代码
http://immmmm.com/jquery-tab-switch-code-improved.html html <div id="sidebar-tab"> ...
-
C#连接sqlserver数据库
// 混合登录 写法1:Data Source=myServerAddress;Initial Catalog=myDataBase;User Id=myUsername;Password=myPas ...
-
hdoj:2080
夹角有多大II Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Sub ...
-
DLL.LoadLibrary失败(126)
1.LoadLibrary 返回 NULL,GetLastError 显示的是 错误码126,msdn上是这样的: ERROR_MOD_NOT_FOUND 126 (0x7E) The specifi ...
-
关键两招就解决Wampserver 打开localhost显示IIS7图片问题
我们在安装集成环境Wampserver之后,有时会遇到一个问题, 打开localhost显示一张IIS7图片,这个问题该如何解决呢,我在网上找了一些说的都很乱,我在这里简单整理了一下解决方法 1 ...
-
war部署到tomcat
gs-rest-service-0.1.0.war复制到tomcat-9.0.0.M17\webapps\ 打开server.xml,这Host节点,加入<Context path=" ...
-
用sql语句,快速备份表数据
1.SqlServer数据库 --DataTable 原数据表 --DataTable_20150717 要备份的新表名 select * into DataTable_20150717 from D ...