@hx
2018-04-14T15:26:28.000000Z
字数 10022
阅读 1422
前端
JavaScript不区分整数和浮点数,统一用Number表示。
JavaScript允许对任意数据类型做比较:
false == 0; // truefalse === 0; // false
因为JavaScript使用==时会出现非常诡异的结果,所以不要使用==,始终坚持使用===。
多行字符串
由于多行字符串用\n写起来比较费事,所以最新的ES6标准新增了一种多行字符串的表示方法,用` ... `表示:
var s = `多行字符串表示`;
模版字符串
ES6新增了一种模板字符串,表示方法和上面的多行字符串一样,但是它会自动替换字符串中的变量:
var name = '小明';var age = 20;var message = '你好, ' + name + ', 你今年' + age + '岁了!';
等同于
var name = '小明';var age = 20;var message = `你好, ${name}, 你今年${age}岁了!`;
操作字符串
获取字符串某个指定位置的字符,使用类似Array的下标操作,索引号从0开始:
var s = 'Hello, world!';s[0]; // 'H's[6]; // ' 's[13]; // undefined 超出范围的索引不会报错,但一律返回undefined
需要特别注意的是,字符串是不可变的,如果对字符串的某个索引赋值,不会有任何错误,但是,也没有任何效果:
var s = 'Test';s[0] = 'X';alert(s); // s仍然为'Test'
1.直接给Array的length赋一个新的值会导致Array大小的变化。
var arr = [1, 2, 3];arr.length; // 3arr.length = 6;arr; // arr变为[1, 2, 3, undefined, undefined, undefined]arr.length = 2;arr; // arr变为[1, 2]
2.Array可以通过索引把对应的元素修改为新的值,因此,对Array的索引进行赋值会直接修改这个Array:
var arr = ['A', 'B', 'C'];arr[1] = 99;arr; // arr现在变为['A', 99, 'C']
3.如果通过索引赋值时,索引超过了范围,同样会引起Array大小的变化:
var arr = [1, 2, 3];arr[5] = 'x';arr; // arr变为[1, 2, 3, undefined, undefined, 'x']
常用方法
.push(新元素) 从末尾添加
var arr = [3, 4, 5];arr.push(6); // 4 返回修改后的长度console.log(arr); // [3, 4, 5, 6]
.unshift(新元素)从开头添加
var arr = [3, 4, 5];arr.unshift(2); // 4 返回修改后的长度console.log(arr); // [2, 3, 4, 5]
.pop() 从末尾删
var arr = [3, 4, 5, 6];arr.pop(); // 6 返回被删除的数console.log(arr); // [3, 4, 5]
.shift() 从开头删
var arr = [2, 3, 4, 5];arr.shift(); // 2 返回被删除的数console.log(arr); // [3, 4, 5]
.reverse() 颠倒顺序
[1, 2, 3].reverse(); // [3, 2, 1]
.splice(从哪剪, 剪多长, 替换元素1, 替换元素2) 剪接
var 片儿 = ['a', 'b', '辣鸡1', '辣鸡2', 'c'];// 从第3格开始剪,剪2格片儿.splice(2, 2); // ["辣鸡1", "辣鸡2"] 返回减掉的东西console.log(片儿); // ["a", "b", "c"]// 注意,现在片儿已经剪成了['a', 'b', 'c']// 从第2格开始剪,剪1格,进两个广告片儿.splice(1, 1, '广告1', '广告2');console.log(片儿); // ["a", "广告1", "广告2", "c"]
.slice(从哪剪,在哪停) 剪裁
返回剪裁的新数组,不影响原数组。
var 片儿 = ['a', 'b', '辣鸡1', '辣鸡2', 'c'];// 从第3格开始剪,剪2格var 垃圾堆 = 片儿.slice(2, 4); // ["辣鸡1", "辣鸡2"] 返回减掉的东西console.log(垃圾堆); // ["辣鸡1", "辣鸡2"]

map 映射
let b = [1, 2, 3, 4, "5"];let c = b.map(String); // [ '1', '2', '3', '4', '5' ]let d = b.map(fun); // [ 201, 202, 203, 204, '5200' ]let e = b.map((e, i) => e + 100); // [ 101, 102, 103, 104, '5100' ]function fun(x) {return x + 200;}
reduce 依次
let b = [1, 2, 3, 4, "5"];let w = b.reduce(function (x, y) {console.log(`x = ${x}, y = ${y}`);return parseInt(x) + parseInt(y);});/**x = 1, y = 2x = 3, y = 3x = 6, y = 4x = 10, y = 5he: 15**/
filter 过滤filter也是一个常用的操作,它用于把Array的某些元素过滤掉,然后返回剩下的元素。和map()类似,Array的filter()也接收一个函数。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是true还是false决定保留还是丢弃该元素。
let b = [1, 2, 3, 4, "5"];let c = b.filter(function (x) {return x >= 3;});// [ 3, 4, '5' ]
filter()接收的回调函数,其实可以有多个参数。通常我们仅使用第一个参数,表示Array的某个元素。回调函数还可以接收另外两个参数,表示元素的位置和数组本身。
用filter()去重:
var r,arr = ['apple', 'strawberry', 'banana', 'pear', 'apple', 'orange', 'orange', 'strawberry'];r = arr.filter(function (element, index, self) {return self.indexOf(element) === index;});console.log(r); // [ 'apple', 'strawberry', 'banana', 'pear', 'orange' ]
sort 排序Array的sort()方法默认把所有元素先转换为String再排序,sort()方法会直接对Array进行修改,它返回的结果仍是当前Array。
var arr = ['apple', 'strawberry', 'banana', 'pear', 'apple', 'orange', 'orange', 'strawberry'], newarr;// 按字符串长度排序newarr = arr.sort(function (x, y) {let code = 0;if (x.length > y.length) {code = 1;}if (x.length < y.length) {code = -1;}return code;});console.log(arr === newarr); // trueconsole.log(newarr);/**[ 'pear','apple','apple','banana','orange','orange','strawberry','strawberry' ]**/
find找到通过传入的函数测试的第一个元素,该函数应该返回true或false。
var people = [{name: 'Jack', age: 50},{name: 'Michael', age: 9},{name: 'John', age: 40},{name: 'Ann', age: 19},{name: 'Elisabeth', age: 16}]function teenager(person) {return person.age > 10 && person.age < 20}var firstTeenager = people.find(teenager)console.log('First found teenager:', firstTeenager.name)// First found teenager: Ann
every检查数组的每个元素是否通过传入函数的测试,该函数应该返回true或false(每个函数都返回true,则结果为true,否则为false)。
var people = [{name: 'Jack', age: 50},{name: 'Michael', age: 9},{name: 'John', age: 40},{name: 'Ann', age: 19},{name: 'Elisabeth', age: 16}]function teenager(person) {return person.age > 10 && person.age < 20}var everyoneIsTeenager = people.every(teenager)console.log('Everyone is teenager: ', everyoneIsTeenager)// Everyone is teenager: false
some检查数组的任何元素是否通过由提供的函数实现的测试,该函数应该返回true或false。(有一个函数返回true,则结果true。否则结果为false)
var people = [{name: 'Jack', age: 50},{name: 'Michael', age: 9},{name: 'John', age: 40},{name: 'Ann', age: 19},{name: 'Elisabeth', age: 16}]function teenager(person) {return person.age > 10 && person.age < 20}var thereAreTeenagers = people.some(teenager)console.log('There are teenagers:', thereAreTeenagers)// There are teenagers: true
JavaScript的对象是一种无序的集合数据类型,它由若干键值对组成。用一个{...}表示一个对象,键值对以xxx: xxx形式申明,用,隔开。
如果属性名包含特殊字符,就必须用''括起来,访问这个属性也无法使用.操作符,必须用['xxx']来访问。
由于JavaScript的对象是动态类型,你可以自由地给一个对象添加或删除属性:
var xiaoming = {name: '小明'};xiaoming.age; // undefinedxiaoming.age = 18; // 新增一个age属性xiaoming.age; // 18delete xiaoming.age; // 删除age属性xiaoming.age; // undefineddelete xiaoming['name']; // 删除name属性xiaoming.name; // undefineddelete xiaoming.school; // 删除一个不存在的school属性也不会报错
如果我们要检测xiaoming是否拥有某一属性,可以用in操作符
'name' in xiaoming; // true
如果in判断一个属性存在,这个属性不一定是xiaoming的,它可能是xiaoming继承得到的,要判断一个属性是否是xiaoming自身拥有的,而不是继承得到的,可以用hasOwnProperty()方法。
var xiaoming = {name: '小明'};xiaoming.hasOwnProperty('name'); // truexiaoming.hasOwnProperty('toString'); // false
JavaScript把null、undefined、0、NaN和空字符串''视为false,其他值一概视为true,因此上述代码条件判断的结果是true。
Object.assign()
用于对对象的合并和拷贝。
let a = {a: 1};let b = {b: 2};let c = Object.assign([], a, b);console.log(c); // [ a: 1, b: 2 ]
for循环的一个变体是for ... in循环,它可以把一个对象的所有属性依次循环出来;请注意,for ... in对Array的循环得到的是String而不是Number。
Map是一组键值对的结构,具有极快的查找速度,一个key只能对应一个value,所以,多次对一个key放入value,后面的值会把前面的值冲掉。
var m = new Map(); // 空Mapvar m2 = new Map([['Michael', 95], ['Bob', 75], ['Tracy', 85]]);m.set('Adam', 67); // 添加新的key-valuem.set('Bob', 59);m.has('Adam'); // 是否存在key 'Adam': truem.get('Adam'); // 67m.delete('Adam'); // 删除key 'Adam'm.get('Adam'); // undefined
Set和Map类似,也是一组key的集合,但不存储value。由于key不能重复,所以,在Set中,没有重复的key。
要创建一个Set,需要提供一个Array作为输入,或者直接创建一个空Set。
for ... of循环和for ... in循环有何区别?
for ... in循环由于历史遗留问题,它遍历的实际上是对象的属性名称。一个Array数组实际上也是一个对象,它的每个元素的索引被视为一个属性。
当我们手动给Array对象添加了额外的属性后,for ... in循环将带来意想不到的意外效果:
var a = ['A', 'B', 'C'];a.name = 'Hello';for (var x in a) {alert(x); // '0', '1', '2', 'name'}
for ... in循环将把name包括在内,但Array的length属性却不包括在内。
for ... of循环则完全修复了这些问题,它只循环集合本身的元素:
var a = ['A', 'B', 'C'];a.name = 'Hello';for (var x of a) {alert(x); // 'A', 'B', 'C'}
forEach()方法
var a = ['A', 'B', 'C'];a.forEach(function (element, index, array) {// element: 指向当前元素的值// index: 指向当前索引// array: 指向Array对象本身alert(element);});
所以数组使用
for of或者forEach,对象使用for in。
for of只能遍历有Iterable接口的数据。
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]]) |
对象序列化 |
arguments、 rest、 let、 const关键字arguments,它只在函数内部起作用,并且永远指向当前函数的调用者传入的所有参数。arguments类似Array但它不是一个Array。
function foo(x) {alert(x); // 10for (var i=0; i<arguments.length; i++) {alert(arguments[i]); // 10, 20, 30}}foo(10, 20, 30);
ES6引入关键字参数rest,获取已知参数外的参数:
function foo(a, b, ...rest) {}foo(1);// a = 1// b = undefined// rest = Array[] ,是一个空数组!!!
为了解决块级作用域,ES6引入了新的关键字let,用let替代var可以申明一个块级作用域的变量:
function foo() {var sum = 0;for (let i=0; i<100; i++) {sum += i;}i += 1; // SyntaxError}
ES6标准引入了新的关键字const来定义常量,const与let都具有块级作用域:
const PI = 3.14;PI = 3; // 某些浏览器不报错,但是无效果!PI; // 3.14
传入参数为基本类型时,为值传递;传入参数为对象时,为共享传递。
function Point(x, y) {this.x = x;this.y = y;}// 原型放公共方法Point.prototype.getX = function() {return this.x;};var p = new Point(1, 2);var p2 = new Point(2, 3);console.log(p.getX()); // 1console.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);可以识别标准类型以及内置对象类型。
console.log(Object.prototype.toString.call([]).slice(8,-1));// Array
constructor判别标准类型、内置和自定义对象对象。
// 获得构造函数名称function getConstructorName(obj) {return obj && obj.constructor && obj.constructor.toString().match(/function\s*([^(]*)/)[1];}
| 方法 | 说明 |
|---|---|
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
let p1 = new Promise((resolve, reject) => {reject(2);});p1.then((value) => {console.log(`成功${value}`);}, (value) => {console.log(`失败${value}`);});// 成功2
通过Promise包装异步读取文件方法:
const fs = require("fs");function read(fileName) {return new Promise((resolve, reject) => {fs.readFile(fileName, (err, data) => {if (err) {reject(err);} else {resolve(data);}})});}read("test2.js").then((data) => {console.log(data.toString());}, (err) => {console.log(err);});
function* show() {yield "hello";yield "world";yield "ES6";}let val = show();console.log(val.next()); // { value: 'hello', done: false }console.log(val.next()); // { value: 'world', done: false }console.log(val.next()); // { value: 'ES6', done: false }console.log(val.next()); // { value: undefined, done: true }
class Point {constructor(x, y) {this.x = xthis.y = y}toString() {return '[X=' + this.x + ', Y=' + this.y + ']'}}class ColorPoint extends Point {// 这段代码存疑。static default() {return new ColorPoint(0, 0, 'black')}constructor(x, y, color) {super(x, y)this.color = color}toString() {return '[X=' + this.x + ', Y=' + this.y + ', color=' + this.color + ']'}}console.log('The first point is ' + new Point(2, 10))console.log('The second point is ' + new ColorPoint(2, 10, 'green'))/** The first point is [X=2, Y=10]The second point is [X=2, Y=10, color=green]**/