学习笔记 2020-10-10
决定从今天开始每天记录当日学习所得。
JavaScript 高级程序设计(第4版) 阅读记录
集合引用类型
1. Object
Object 是 ECMAScript 中最常用的类型之一。
创建 Object 实例的方法:
使用
new操作符和Object构造函数let person = new Object(); person.name = 'Sirine'; person.age = 21;
使用对象字面量方法。
// 推荐使用 ✔ let person = { name: 'Sirine', age: 21 };
对象中获取属性的方法:
点语法
中括号语法
console.log(person["name"]); console.log(person.name); // 以上两种语法等价但在使用中括号语法获取属性时可以传入变量或是包含空格等字符的键名。
let propertyName = 'name'; console.log(person[propertyName]); // === console.log(person['name']); // 键名包含空格时必须使用中括号语法。 person['first name'] = 'Zhao'; console.log(person['first name']);
2. Array
ECMAScript 中的数组十分自由,数组内元素的类型不受限制,大小也是动态的。
创建数组的方法也是两种。
Array构造函数let colors = new Array(); // 创建一个长度为 0 的空数组。 let colors = new Array(20); // 创建一个长度为 20 的空数组。 let colors = new Array("red", "blue", "green"); // 创建一个长度为 3 ,包含 red blue green 三个字符串的数组。
数组字面量
let colors = ['red', 'blue', 'yellow']; // 创建一个长度为3,包含 red blue green 三个字符串的数组。 let names = []; // 创建一个长度为 0 的空数组。 let options = [,,,,,]; // 创建一个长度为 5 的数组。空位元素为 `undefined`; for (const option of options) { console.log(option === undefined); } // true * 5 // 空位元素在 map join 等方法中会被跳过。
ES6 当中新增了两个创建数组的静态方法。
Array.from这个方法可以将任何可迭代的结构例如类数组,转换为数组。
可迭代结构举例:字符串、
Map实例,Set实例,拥有[Symbol.iterator]方法的对象,函数的arguments对象, 携带有索引键值和length属性的对象。该方法的第一个参数为被转换的对象,第二个参数为映射函数,第三个参数为映射函数的
this指向。const a1 = [1, 2, 3, 4]; const a2 = Array.from(a1, x => x**2); const a3 = Array.from(a1, function(x) {return x**this.exponent}, {exponent: 2}); console.log(a2); // [1, 4, 9, 16] console.log(a3); // [1, 4, 9, 16]
Array.of用于替代
Array.prototype.slice.call(arguments),将传入的参数转换为数组。
数组的索引值可以动态修改,并且会直接影响到数组的长度。
let options = [10, 9, 8, 7, 6, 5, 4];
options.length = 10;
console.log(options);
// [10, 9, 8, 7, 6, 5, 4, empty × 3]
options.length = 3;
console.log(options);
// [10, 9, 8]
options[50] = 50;
console.log(options);
// [10, 9, 8, empty × 47, 50]
在数组中访问不存在的元素(例如下标越界)的时候会返回 undefined 。前面也提到了被设置为 empty 的数组元素被访问时也是被当作 undefined 。
数组最多可以包含的元素值为 4 294 967 295 。
判断是否为数组的方法有:
instanceofArray.isArray
两者的区别是 instanceof 的返回结果取决于 Array 构造函数(即是否为某个构造函数的实例),而 isArray 只会判断是否为一个数组。
Array 新增的三个迭代器方法:
keys()返回数组索引的迭代器。
values()返回数组元素的迭代器。
entries()返回索引值对的迭代器。
三个迭代器都可以通过 Array.from 转换为数组。也可以用于 for of 循环迭代。
Array 新增的复制和填充方法:
copyWithin(insertIndex, copyIndex, lastIndex)fill(arg, startIndex, lastIndex)两个方法的索引值都支持负值。
copyWithin从copyIndex开始复制到lastIndex结束(可忽略),复制到insertIndex位置。若忽略复制索引则全部复制。fill方法将第一个参数填充到startIndex开始到lastIndex前一个位置,若忽略索引值则整个数组进行填充。两个方法的操作都是对原有元素的覆盖。
现代 JavaScript 教程
break/continue
非表达式的语法结构不能与三元运算符一起使用。
if (i > 5) {
alert(i);
} else {
continue;
}
// 没有问题
(i > 5) ? alert(i) : continue; // 语法错误
标签用法:
适用于多层循环嵌套跳出的场景。
outer: for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
if (condition) break outer; // 若满足条件,则跳出至最外层。
}
}
alert('Done!');
任务:
1. 最后一次循环的值
此代码最后一次 alert 值是多少?为什么?
let i = 3;
while (i) {
alert( i-- );
}
答案为 1 ,循环体内使用了后置自减,那么在弹出后才会对 i 自减,当 i 为 1 时,弹出显示,然后自减为 0 , 再次判断循环条件,不符合,不再进入循环。
2. while 循环显示哪些值?
以下两个循环的 alert 值是否相同?
前缀形式
++i:let i = 0; while (++i < 5) alert( i );
后缀形式
i++let i = 0; while (i++ < 5) alert( i );
两个循环的 alert 值前四次相等,因为不管是前置还是后置,i 的自增都在条件判断处完成,对于 alert 不影响。
但是自增的时间影响了循环执行的次数。
因为第一个循环是自增后再判断,每次循环的 i 为 1, 2, 3, 4, 5 , 第五次已经无法满足条件判断,不再进入循环,所以只打印了四次。
第二个循环是自增前判断,判断时的 i 值依次为 0, 1, 2, 3, 4, 5 ,因此该循环多了一次进入循环的机会,因为进入循环时 i 已经完成自增,所以打印的值依次为 1, 2, 3, 4, 5 。
3. for 循环显示哪些值?
两次循环 alert 值是否相同?
后缀形式:
for (let i = 0; i < 5; i++) alert( i );
前缀形式:
for (let i = 0; i < 5; ++i) alert( i );
两次循环显示的值完全相同,因为 for 循环的自增条件是单独执行,不与条件判断放置在一起。写成 while 循环就是类似于:
let i = 0;
while(i < 5){
alert(i);
i++;
// or
++i;
}
如上所示,这样的自增无论是前置还是后置都没有影响。
4. 使用 for 循环输出偶数
使用 for 循环输出从 2 到 10 的偶数。
for (let i = 1; i < 11; i++) {
if (i % 2 === 0) {
console.log(i);
}
}
// 2 4 6 8 10
5. 使用 while 替换 for
重写代码,在保证不改变其行为的情况下,将 for 循环更改为 while(输出应保持不变)。
for (let i = 0; i < 3; i++) {
alert( `number ${i}!` );
}
let i = 0;
while(i < 3) {
alert( `number ${i}!` );
i++;
}
6. 重复输入,直到正确为止
编写一个提示用户输入大于 100 的数字的循环。如果用户输入其他数值 —— 请他重新输入。
循环一直在请求一个数字,直到用户输入了一个大于 100 的数字、取消输入或输入了一个空行为止。
在这我们假设用户只会输入数字。在本题目中,不需要对非数值输入进行特殊处理。
let input = prompt('please input a number greater than 100!');
while(input <= 100) {
if (input === null) {
alert('input canceled.');
break;
}
if (input === '') {
alert('you enter a nothing.');
break;
}
input = prompt('please input a number greater than 100!');
}
参考解决方案:
let num;
do {
num = prompt("Enter a number greater than 100?", 0);
} while (num <= 100 && num);
代码简洁,利用了 do while 循环的特性。
7. 输出素数
大于 1 且不能被除了 1 和它本身以外的任何数整除的整数叫做素数。
换句话说,n > 1 且不能被 1 和 n 以外的任何数整除的整数,被称为素数。
例如,5 是素数,因为它不能被 2、3 和 4 整除,会产生余数。
写一个可以输出 2 到 n 之间的所有素数的代码。
当 n = 10,结果输出 2、3、5、7。
P.S. 代码应适用于任何 n,而不是对任何固定值进行硬性调整。
let n = prompt('', 2);
function isPrime (n) {
if (n <= 1) {
return 'the n invalid';
}
let num = Math.ceil(Math.sqrt(n));
while (num > 1) {
if (n === num) {
num--;
continue;
}
if (n % num === 0) {
return false;
}
num--;
}
return true;
}
let arr = [];
for (let i = 2; i <= n; i++) {
if (isPrime(i)) arr.push(i);
}
console.log(arr);
JavaScript 深入学习
手写数组原型方法
unshift 方法
Array.prototype.myUnShift = function () {
var len = arguments.length;
var i = 0;
for (; i < len; i++) {
this.splice(i, 0, arguments[i]);
}
return this.length;
}
数组元素按照字节长度排序
function getBytes(str) {
var len = str.length;
var i;
for (i = 0; i < len; i++) {
if (str.charCodeAt(i) > 255) len++;
}
return len;
}
var arr = ['today', '今天', 'ok', 'haha', 'you say 什么'];
arr.sort(function (a, b) {
return getBytes(a) - getBytes(b);
})
console.log(arr);
// ["ok", "今天", "haha", "today", "you say 什么"]
手写可以判断所有类型的 typeof 函数
function myTypeof(arg) {
var type = typeof arg;
var toStr = Object.prototype.toString;
if (arg === null) {
return 'null';
} else if (type === 'object') {
return toStr.call(arg).slice(8, -1);
} else {
return type;
}
}
myTypeof([]); // "Array"
myTypeof({}); // "Object"
myTypeof(123); // "number"
myTypeof('123'); // "string"
myTypeof(false); // "boolean"
myTypeof(new Number(123)); // "Number"
myTypeof(new String('123')); // "String"
myTypeof(new Boolean(false)); // "Boolean"
myTypeof(null); // "null"
myTypeof(undefined); // "undefined"
数组去重
Array.prototype.unique = function () {
var newArr = [];
var len = this.length;
var i;
for(i = 0; i < len; i++){
var item = this[i];
if (newArr.indexOf(item) === -1) {
newArr.push(item);
}
}
return newArr;
}
let test = [1, 2, 1, 1, 1, 2, 3, 3, 3, 5, 5, 'a', 'a'];
console.log(test.unique());
// [1, 2, 3, 5, "a"]
Array.prototype.unique = function () {
var newArr = [];
var obj = {};
var len = this.length;
var i;
for (i = 0; i < len; i++) {
var item = this[i];
if (!obj.hasOwnProperty(item)) {
obj[item] = true;
newArr.push(item);
}
}
return newArr;
}
let test = [1, 2, 1, 1, 1, 2, 3, 3, 3, 5, 5, 'a', 'a'];
console.log(test.unique());
// [1, 2, 3, 5, "a"]
字符串去重
String.prototype.unique = function () {
var newStr = '';
var obj = {};
var len = this.length;
var i;
for (i = 0; i < len; i++) {
if (obj.hasOwnProperty(this[i])) continue;
obj[this[i]] = true;
newStr += this[i];
}
return newStr;
}
let str = '122132312341nfskdjfhhhrbbfjsdhfuke';
console.log(str.unique());
// 1234nfskdjhrbue
重复字符串中找出第一个不重复字符
function find (str) {
var len = str.length;
var i;
var j;
var flag;
for (i = 0; i < len; i++) {
flag = true;
var tmp1 = str[i];
for (j = i + 1; j < len; j++) {
var tmp2 = str[j];
if (tmp1 === tmp2) {
flag = false;
break;
}
}
if (flag === true) return str[i];
}
return null;
}
let str = '12213a231234qqqqeuerhkrjbrkfmigrhiofjcrjef';
console.log(find(str));
// a
知识点
arguments类型为objectvar test = function a () { console.log(a); console.log(test); console.log(test.name); console.log(test === a); } a(); // a is not defined test(); // ƒ a() { // console.log(a); // console.log(test); // console.log(test.name); // console.log(test === a); // } // ƒ a() { // console.log(a); // console.log(test); // console.log(test.name); // console.log(test === a); // } // a // true
TODO-LIST
- 想尝试一下
hugo作为博客。