[关闭]
@hx 2018-04-14T23:26:28.000000Z 字数 10022 阅读 1166

JavaScript笔记

前端


基本语法

Number

JavaScript不区分整数和浮点数,统一用Number表示。

比较运算符

JavaScript允许对任意数据类型做比较:

  1. false == 0; // true
  2. false === 0; // false

因为JavaScript使用==时会出现非常诡异的结果,所以不要使用==,始终坚持使用===

字符串

多行字符串
由于多行字符串用\n写起来比较费事,所以最新的ES6标准新增了一种多行字符串的表示方法,用` ... `表示:

  1. var s = `多行
  2. 字符串
  3. 表示`;

模版字符串
ES6新增了一种模板字符串,表示方法和上面的多行字符串一样,但是它会自动替换字符串中的变量:

  1. var name = '小明';
  2. var age = 20;
  3. var message = '你好, ' + name + ', 你今年' + age + '岁了!';

等同于

  1. var name = '小明';
  2. var age = 20;
  3. var message = `你好, ${name}, 你今年${age}岁了!`;

操作字符串
获取字符串某个指定位置的字符,使用类似Array的下标操作,索引号从0开始:

  1. var s = 'Hello, world!';
  2. s[0]; // 'H'
  3. s[6]; // ' '
  4. s[13]; // undefined 超出范围的索引不会报错,但一律返回undefined

需要特别注意的是,字符串是不可变的,如果对字符串的某个索引赋值,不会有任何错误,但是,也没有任何效果:

  1. var s = 'Test';
  2. s[0] = 'X';
  3. alert(s); // s仍然为'Test'

数组

1.直接给Arraylength赋一个新的值会导致Array大小的变化。

  1. var arr = [1, 2, 3];
  2. arr.length; // 3
  3. arr.length = 6;
  4. arr; // arr变为[1, 2, 3, undefined, undefined, undefined]
  5. arr.length = 2;
  6. arr; // arr变为[1, 2]

2.Array可以通过索引把对应的元素修改为新的值,因此,对Array的索引进行赋值会直接修改这个Array

  1. var arr = ['A', 'B', 'C'];
  2. arr[1] = 99;
  3. arr; // arr现在变为['A', 99, 'C']

3.如果通过索引赋值时,索引超过了范围,同样会引起Array大小的变化:

  1. var arr = [1, 2, 3];
  2. arr[5] = 'x';
  3. arr; // arr变为[1, 2, 3, undefined, undefined, 'x']

常用方法

.push(新元素) 从末尾添加

  1. var arr = [3, 4, 5];
  2. arr.push(6); // 4 返回修改后的长度
  3. console.log(arr); // [3, 4, 5, 6]

.unshift(新元素)从开头添加

  1. var arr = [3, 4, 5];
  2. arr.unshift(2); // 4 返回修改后的长度
  3. console.log(arr); // [2, 3, 4, 5]

.pop() 从末尾删

  1. var arr = [3, 4, 5, 6];
  2. arr.pop(); // 6 返回被删除的数
  3. console.log(arr); // [3, 4, 5]

.shift() 从开头删

  1. var arr = [2, 3, 4, 5];
  2. arr.shift(); // 2 返回被删除的数
  3. console.log(arr); // [3, 4, 5]

.reverse() 颠倒顺序

  1. [1, 2, 3].reverse(); // [3, 2, 1]

.splice(从哪剪, 剪多长, 替换元素1, 替换元素2) 剪接

  1. var 片儿 = ['a', 'b', '辣鸡1', '辣鸡2', 'c'];
  2. // 从第3格开始剪,剪2格
  3. 片儿.splice(2, 2); // ["辣鸡1", "辣鸡2"] 返回减掉的东西
  4. console.log(片儿); // ["a", "b", "c"]
  5. // 注意,现在片儿已经剪成了['a', 'b', 'c']
  6. // 从第2格开始剪,剪1格,进两个广告
  7. 片儿.splice(1, 1, '广告1', '广告2');
  8. console.log(片儿); // ["a", "广告1", "广告2", "c"]

.slice(从哪剪,在哪停) 剪裁

返回剪裁的新数组,不影响原数组。

  1. var 片儿 = ['a', 'b', '辣鸡1', '辣鸡2', 'c'];
  2. // 从第3格开始剪,剪2格
  3. var 垃圾堆 = 片儿.slice(2, 4); // ["辣鸡1", "辣鸡2"] 返回减掉的东西
  4. console.log(垃圾堆); // ["辣鸡1", "辣鸡2"]

高阶函数

map 映射

  1. let b = [1, 2, 3, 4, "5"];
  2. let c = b.map(String); // [ '1', '2', '3', '4', '5' ]
  3. let d = b.map(fun); // [ 201, 202, 203, 204, '5200' ]
  4. let e = b.map((e, i) => e + 100); // [ 101, 102, 103, 104, '5100' ]
  5. function fun(x) {
  6. return x + 200;
  7. }

reduce 依次

  1. let b = [1, 2, 3, 4, "5"];
  2. let w = b.reduce(function (x, y) {
  3. console.log(`x = ${x}, y = ${y}`);
  4. return parseInt(x) + parseInt(y);
  5. });
  6. /**
  7. x = 1, y = 2
  8. x = 3, y = 3
  9. x = 6, y = 4
  10. x = 10, y = 5
  11. he: 15
  12. **/

filter 过滤

filter也是一个常用的操作,它用于把Array的某些元素过滤掉,然后返回剩下的元素。和map()类似,Arrayfilter()也接收一个函数。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是true还是false决定保留还是丢弃该元素。

  1. let b = [1, 2, 3, 4, "5"];
  2. let c = b.filter(function (x) {
  3. return x >= 3;
  4. });
  5. // [ 3, 4, '5' ]

filter()接收的回调函数,其实可以有多个参数。通常我们仅使用第一个参数,表示Array的某个元素。回调函数还可以接收另外两个参数,表示元素的位置和数组本身。
filter()去重:

  1. var r,
  2. arr = ['apple', 'strawberry', 'banana', 'pear', 'apple', 'orange', 'orange', 'strawberry'];
  3. r = arr.filter(function (element, index, self) {
  4. return self.indexOf(element) === index;
  5. });
  6. console.log(r); // [ 'apple', 'strawberry', 'banana', 'pear', 'orange' ]

sort 排序

Arraysort()方法默认把所有元素先转换为String再排序,sort()方法会直接对Array进行修改,它返回的结果仍是当前Array

  1. var arr = ['apple', 'strawberry', 'banana', 'pear', 'apple', 'orange', 'orange', 'strawberry'], newarr;
  2. // 按字符串长度排序
  3. newarr = arr.sort(function (x, y) {
  4. let code = 0;
  5. if (x.length > y.length) {
  6. code = 1;
  7. }
  8. if (x.length < y.length) {
  9. code = -1;
  10. }
  11. return code;
  12. });
  13. console.log(arr === newarr); // true
  14. console.log(newarr);
  15. /**
  16. [ 'pear',
  17. 'apple',
  18. 'apple',
  19. 'banana',
  20. 'orange',
  21. 'orange',
  22. 'strawberry',
  23. 'strawberry' ]
  24. **/

find

找到通过传入的函数测试的第一个元素,该函数应该返回truefalse

  1. var people = [
  2. {name: 'Jack', age: 50},
  3. {name: 'Michael', age: 9},
  4. {name: 'John', age: 40},
  5. {name: 'Ann', age: 19},
  6. {name: 'Elisabeth', age: 16}
  7. ]
  8. function teenager(person) {
  9. return person.age > 10 && person.age < 20
  10. }
  11. var firstTeenager = people.find(teenager)
  12. console.log('First found teenager:', firstTeenager.name)
  13. // First found teenager: Ann

every

检查数组的每个元素是否通过传入函数的测试,该函数应该返回true或false(每个函数都返回true,则结果为true,否则为false)。

  1. var people = [
  2. {name: 'Jack', age: 50},
  3. {name: 'Michael', age: 9},
  4. {name: 'John', age: 40},
  5. {name: 'Ann', age: 19},
  6. {name: 'Elisabeth', age: 16}
  7. ]
  8. function teenager(person) {
  9. return person.age > 10 && person.age < 20
  10. }
  11. var everyoneIsTeenager = people.every(teenager)
  12. console.log('Everyone is teenager: ', everyoneIsTeenager)
  13. // Everyone is teenager: false

some

检查数组的任何元素是否通过由提供的函数实现的测试,该函数应该返回true或false。(有一个函数返回true,则结果true。否则结果为false)

  1. var people = [
  2. {name: 'Jack', age: 50},
  3. {name: 'Michael', age: 9},
  4. {name: 'John', age: 40},
  5. {name: 'Ann', age: 19},
  6. {name: 'Elisabeth', age: 16}
  7. ]
  8. function teenager(person) {
  9. return person.age > 10 && person.age < 20
  10. }
  11. var thereAreTeenagers = people.some(teenager)
  12. console.log('There are teenagers:', thereAreTeenagers)
  13. // There are teenagers: true

对象

JavaScript的对象是一种无序的集合数据类型,它由若干键值对组成。用一个{...}表示一个对象,键值对以xxx: xxx形式申明,用,隔开。
如果属性名包含特殊字符,就必须用''括起来,访问这个属性也无法使用.操作符,必须用['xxx']来访问。
由于JavaScript的对象是动态类型,你可以自由地给一个对象添加或删除属性:

  1. var xiaoming = {
  2. name: '小明'
  3. };
  4. xiaoming.age; // undefined
  5. xiaoming.age = 18; // 新增一个age属性
  6. xiaoming.age; // 18
  7. delete xiaoming.age; // 删除age属性
  8. xiaoming.age; // undefined
  9. delete xiaoming['name']; // 删除name属性
  10. xiaoming.name; // undefined
  11. delete xiaoming.school; // 删除一个不存在的school属性也不会报错

如果我们要检测xiaoming是否拥有某一属性,可以用in操作符
'name' in xiaoming; // true
如果in判断一个属性存在,这个属性不一定是xiaoming的,它可能是xiaoming继承得到的,要判断一个属性是否是xiaoming自身拥有的,而不是继承得到的,可以用hasOwnProperty()方法。

  1. var xiaoming = {
  2. name: '小明'
  3. };
  4. xiaoming.hasOwnProperty('name'); // true
  5. xiaoming.hasOwnProperty('toString'); // false

JavaScript把nullundefined0NaN和空字符串''视为false,其他值一概视为true,因此上述代码条件判断的结果是true

Object.assign()
用于对对象的合并和拷贝。

  1. let a = {a: 1};
  2. let b = {b: 2};
  3. let c = Object.assign([], a, b);
  4. console.log(c); // [ a: 1, b: 2 ]

循环

for循环的一个变体是for ... in循环,它可以把一个对象的所有属性依次循环出来;请注意,for ... in对Array的循环得到的是String而不是Number。

Map和Set(ES6)

Map是一组键值对的结构,具有极快的查找速度,一个key只能对应一个value,所以,多次对一个key放入value,后面的值会把前面的值冲掉。

  1. var m = new Map(); // 空Map
  2. var m2 = new Map([['Michael', 95], ['Bob', 75], ['Tracy', 85]]);
  3. m.set('Adam', 67); // 添加新的key-value
  4. m.set('Bob', 59);
  5. m.has('Adam'); // 是否存在key 'Adam': true
  6. m.get('Adam'); // 67
  7. m.delete('Adam'); // 删除key 'Adam'
  8. m.get('Adam'); // undefined

SetMap类似,也是一组key的集合,但不存储value。由于key不能重复,所以,在Set中,没有重复的key
要创建一个Set,需要提供一个Array作为输入,或者直接创建一个空Set

Iterable

for ... of循环和for ... in循环有何区别?
for ... in循环由于历史遗留问题,它遍历的实际上是对象的属性名称。一个Array数组实际上也是一个对象,它的每个元素的索引被视为一个属性。
当我们手动给Array对象添加了额外的属性后,for ... in循环将带来意想不到的意外效果:

  1. var a = ['A', 'B', 'C'];
  2. a.name = 'Hello';
  3. for (var x in a) {
  4. alert(x); // '0', '1', '2', 'name'
  5. }

for ... in循环将把name包括在内,但Arraylength属性却不包括在内。
for ... of循环则完全修复了这些问题,它只循环集合本身的元素:

  1. var a = ['A', 'B', 'C'];
  2. a.name = 'Hello';
  3. for (var x of a) {
  4. alert(x); // 'A', 'B', 'C'
  5. }

forEach()方法

  1. var a = ['A', 'B', 'C'];
  2. a.forEach(function (element, index, array) {
  3. // element: 指向当前元素的值
  4. // index: 指向当前索引
  5. // array: 指向Array对象本身
  6. alert(element);
  7. });

所以数组使用for of 或者 forEach,对象使用for in
for of只能遍历有Iterable接口的数据。

Date

JSON

6种数据类型:
number:和JavaScript的number完全一致;
boolean:就是JavaScript的true或false;
string:就是JavaScript的string;
null:就是JavaScript的null;
array:就是JavaScript的Array表示方式——[];
object:就是JavaScript的{ ... }表示方式。

方法 说明
JSON.parse(text[, reviver]) 将JSON文本转换为JS对象
JSON.stringify(value[, replacer[, spance]]) 对象序列化

函数

关键字argumentsrestletconst

关键字arguments,它只在函数内部起作用,并且永远指向当前函数的调用者传入的所有参数。arguments类似Array但它不是一个Array

  1. function foo(x) {
  2. alert(x); // 10
  3. for (var i=0; i<arguments.length; i++) {
  4. alert(arguments[i]); // 10, 20, 30
  5. }
  6. }
  7. foo(10, 20, 30);

ES6引入关键字参数rest,获取已知参数外的参数:

  1. function foo(a, b, ...rest) {
  2. }
  3. foo(1);
  4. // a = 1
  5. // b = undefined
  6. // rest = Array[] ,是一个空数组!!!

为了解决块级作用域,ES6引入了新的关键字let,用let替代var可以申明一个块级作用域的变量:

  1. function foo() {
  2. var sum = 0;
  3. for (let i=0; i<100; i++) {
  4. sum += i;
  5. }
  6. i += 1; // SyntaxError
  7. }

ES6标准引入了新的关键字const来定义常量,constlet都具有块级作用域:

  1. const PI = 3.14;
  2. PI = 3; // 某些浏览器不报错,但是无效果!
  3. PI; // 3.14

传入参数为基本类型时,为值传递;传入参数为对象时,为共享传递。

原型

  1. function Point(x, y) {
  2. this.x = x;
  3. this.y = y;
  4. }
  5. // 原型放公共方法
  6. Point.prototype.getX = function() {
  7. return this.x;
  8. };
  9. var p = new Point(1, 2);
  10. var p2 = new Point(2, 3);
  11. console.log(p.getX()); // 1
  12. console.log(p2); // {x: 2, y: 3}

闭包

闭包的应用
1. 保存现场
2. 封装
3. 性能优化

方法

在一个对象中绑定函数,称为这个对象的方法。
注意this的用法,和搭配that使用。
apply()call()的区别:apply()把参数打包成Array再传入;call()把参数按顺序传入。

this的使用场景

函数调用模式:this指向全局对象
方法调用模式:this指向调用者
构造函数调用模式:this指向被构造的对象
apply(call)调用模式:this指向第一个参数

对象类型

对象类型

隐式类型转换

类型识别

typeof可以识别标准类型,除了null以外;不能识别具体的对象类型(function除外)。
instanceof可以判别内置对象类型和自定义对象类型,不能判别原始类型。
Object.prototype.toString.call().slice(8, -1);可以识别标准类型以及内置对象类型。

  1. console.log(Object.prototype.toString.call([]).slice(8,-1));
  2. // Array

constructor判别标准类型、内置和自定义对象对象。

  1. // 获得构造函数名称
  2. function getConstructorName(obj) {
  3. return obj && obj.constructor && obj.constructor.toString().match(/function\s*([^(]*)/)[1];
  4. }

ES6

Promise

方法 说明
Promise.all(iterable) 这个方法返回一个新的promise对象,该promise对象在iterable参数对象里所有的promise对象都成功的时候才会触发成功,一旦有任何一个iterable里面的promise对象失败则立即触发该promise对象的失败。这个新的promise对象在触发成功状态以后,会把一个包含iterable里所有promise返回值的数组作为成功回调的返回值,顺序跟iterable的顺序保持一致;如果这个新的promise对象触发了失败状态,它会把iterable里第一个触发失败的promise对象的错误信息作为它的失败错误信息。Promise.all方法常被用于处理多个promise对象的状态集合。
Promise.race(iterable) 当iterable参数里的任意一个子promise被成功或失败后,父promise马上也会用子promise的成功返回值或失败详情作为参数调用父promise绑定的相应句柄,并返回该promise对象。
Promise.reject(reason) 返回一个状态为失败的Promise对象,并将给定的失败信息传递给对应的处理方法
Promise.resolve(value) 返回一个状态由给定value决定的Promise对象。如果该值是一个Promise对象,则直接返回该对象;如果该值是thenable(即,带有then方法的对象),返回的Promise对象的最终状态由then方法执行决定;否则的话(该value为空,基本类型或者不带then方法的对象),返回的Promise对象状态为fulfilled,并且将该value传递给对应的then方法。通常而言,如果你不知道一个值是否是Promise对象,使用Promise.resolve(value) 来返回一个Promise对象,这样就能将该value以Promise对象形式使用。

Promise.prototype.then
Promise.prototype.catch

  1. let p1 = new Promise((resolve, reject) => {
  2. reject(2);
  3. });
  4. p1.then((value) => {
  5. console.log(`成功${value}`);
  6. }, (value) => {
  7. console.log(`失败${value}`);
  8. });
  9. // 成功2

通过Promise包装异步读取文件方法:

  1. const fs = require("fs");
  2. function read(fileName) {
  3. return new Promise((resolve, reject) => {
  4. fs.readFile(fileName, (err, data) => {
  5. if (err) {
  6. reject(err);
  7. } else {
  8. resolve(data);
  9. }
  10. })
  11. });
  12. }
  13. read("test2.js").then((data) => {
  14. console.log(data.toString());
  15. }, (err) => {
  16. console.log(err);
  17. });

Generator、yield

  1. function* show() {
  2. yield "hello";
  3. yield "world";
  4. yield "ES6";
  5. }
  6. let val = show();
  7. console.log(val.next()); // { value: 'hello', done: false }
  8. console.log(val.next()); // { value: 'world', done: false }
  9. console.log(val.next()); // { value: 'ES6', done: false }
  10. console.log(val.next()); // { value: undefined, done: true }

Class

  1. class Point {
  2. constructor(x, y) {
  3. this.x = x
  4. this.y = y
  5. }
  6. toString() {
  7. return '[X=' + this.x + ', Y=' + this.y + ']'
  8. }
  9. }
  10. class ColorPoint extends Point {
  11. // 这段代码存疑。
  12. static default() {
  13. return new ColorPoint(0, 0, 'black')
  14. }
  15. constructor(x, y, color) {
  16. super(x, y)
  17. this.color = color
  18. }
  19. toString() {
  20. return '[X=' + this.x + ', Y=' + this.y + ', color=' + this.color + ']'
  21. }
  22. }
  23. console.log('The first point is ' + new Point(2, 10))
  24. console.log('The second point is ' + new ColorPoint(2, 10, 'green'))
  25. /** The first point is [X=2, Y=10]
  26. The second point is [X=2, Y=10, color=green]
  27. **/

Buffer

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注