@hx
2018-04-14T23:26:28.000000Z
字数 10022
阅读 1166
前端
JavaScript不区分整数和浮点数,统一用Number表示。
JavaScript允许对任意数据类型做比较:
false == 0; // true
false === 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; // 3
arr.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 = 2
x = 3, y = 3
x = 6, y = 4
x = 10, y = 5
he: 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); // true
console.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; // undefined
xiaoming.age = 18; // 新增一个age属性
xiaoming.age; // 18
delete xiaoming.age; // 删除age属性
xiaoming.age; // undefined
delete xiaoming['name']; // 删除name属性
xiaoming.name; // undefined
delete xiaoming.school; // 删除一个不存在的school属性也不会报错
如果我们要检测xiaoming
是否拥有某一属性,可以用in
操作符
'name' in xiaoming; // true
如果in
判断一个属性存在,这个属性不一定是xiaoming
的,它可能是xiaoming
继承得到的,要判断一个属性是否是xiaoming
自身拥有的,而不是继承得到的,可以用hasOwnProperty()
方法。
var xiaoming = {
name: '小明'
};
xiaoming.hasOwnProperty('name'); // true
xiaoming.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(); // 空Map
var m2 = new Map([['Michael', 95], ['Bob', 75], ['Tracy', 85]]);
m.set('Adam', 67); // 添加新的key-value
m.set('Bob', 59);
m.has('Adam'); // 是否存在key 'Adam': true
m.get('Adam'); // 67
m.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); // 10
for (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()); // 1
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);
可以识别标准类型以及内置对象类型。
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 = x
this.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]
**/