js编程学习复习
基本语法
数据类型
number 基本上分为这6种
1
2
3
4
5
6
7
8
9
10
11
|
123; // 整数123
0.456; // 浮点数0.456
1.2345e3; // 科学计数法表示1.2345x1000,等同于1234.5
-99; // 负数
NaN; // NaN表示Not a Number,当无法计算结果时用NaN表示
Infinity; // Infinity表示无限大,当数值超过了JavaScript的Number所能表示的最大值时,就表示为Infinity
|
- number 算术运算跟数学上的一致 注意%是求余运算。
- 字符串 字符串是以单引号’或双引号"括起来的任意文本
- 布尔值 布尔值和布尔代数的表示完全一致,一个布尔值只有true、false两种值,要么是true *** 或 与 非 比较***
- null和undefined ***null 就是空 不是0 和‘’ *** undefined仅仅在判断函数参数是否传递的情况下有用
- 数组 *** 组是一组按顺序排列的集合,集合的每个值称为元素。*** 创建方式 可以用 new Array(); 和 var str = [1,2,4,’’,obj]
- 对象 JavaScript的对象是一组由键-值组成的无序集合
- 变量 变量的概念基本上和初中代数的方程变量是一致的,只是在计算机程序中,变量不仅可以是数字,还可以是任意数据类型 但申明变量不可以是**$** 和**_**
- strict模式
启用strict模式的方法是在JavaScript代码的第一行写上:
1
2
|
'use strict';
function hello(){}
|
条件判断与循环
1
2
3
4
5
|
if()else{...}
for(){...}
for ....in
while (){...}
do{...}while()
|
map、set和iterable
1
2
3
4
|
'use strict';
var m = new Map();
var s = new Set();
alert('你的浏览器支持Map和Set!');
|
Map是一组键值对的结构,具有极快的查找速度。 里面提供了: set get delete has 方法
1
2
3
4
5
6
7
|
var m = new Map(); // 空Map
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。提供了 add get delete 方法
1
2
3
4
|
var s = new Set([1, 2, 3]);
s; // Set {1, 2, 3}
s.delete(3);
s; // Set {1, 2}
|
iterable
1
2
3
4
5
|
'use strict';
var a = [1, 2, 3];
for (var x of a) {
}
alert('你的浏览器支持for ... of');
|
更好的方式是直接使用iterable内置的forEach方法
1
2
3
4
5
6
7
|
var a = ['A', 'B', 'C'];
a.forEach(function (element, index, array) {
// element: 指向当前元素的值
// index: 指向当前索引
// array: 指向Array对象本身
alert(element);
});
|
函数
1
|
函数定义 function fun_name (args){ ... return}
|
arguments 你可以获得调用者传入的所有参数。
1
2
3
4
5
6
7
8
9
10
11
|
function abs() {
if (arguments.length === 0) {
return 0;
}
var x = arguments[0];
return x >= 0 ? x : -x;
}
abs(); // 0
abs(10); // 10
abs(-9); // 9
|
rest参数
1
|
function fun_name(a, b, ...rest) {....}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
function foo(a, b, ...rest) {
console.log('a = ' + a);
console.log('b = ' + b);
console.log(rest);
}
foo(1, 2, 3, 4, 5);
// 结果:
// a = 1
// b = 2
// Array [ 3, 4, 5 ]
foo(1);
// 结果:
// a = 1
// b = undefined
// Array []
|
常量
var和let申明的是变量,如果要申明一个常量,在ES6之前是不行的,我们通常用全部大写的变量来表示这是一个常量,不要修改它的值
方法: 在一个对象中绑定函数,称为这个对象的方法。
1
2
3
4
5
6
7
8
9
10
11
|
var xiaoming = {
name: '小明',
birth: 1990,
age: function () {
var y = new Date().getFullYear();
return y - this.birth;
}
};
xiaoming.age; // function xiaoming.age()
xiaoming.age(); // 今年调用是25,明年调用就变成26了
|
apply
根据是否是strict模式,this指向undefined或window
1
2
3
4
5
6
7
8
9
10
11
12
13
|
function getAge() {
var y = new Date().getFullYear();
return y - this.birth;
}
var xiaoming = {
name: '小明',
birth: 1990,
age: getAge
};
xiaoming.age(); // 25
getAge.apply(xiaoming, []); // 25, this指向xiaoming, 参数为空
|
利用apply(),我们还可以动态改变函数的行为。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
var count = 0;
var oldParseInt = parseInt; // 保存原函数
window.parseInt = function () {
count += 1;
return oldParseInt.apply(null, arguments); // 调用原函数
};
// 测试:
parseInt('10');
parseInt('20');
parseInt('30');
count; // 3
|
高阶函数 也就是函数的函数
map
1
2
3
4
5
6
|
function pow(x) {
return x * x;
}
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
arr.map(pow); // [1, 4, 9, 16, 25, 36, 49, 64, 81]
|
1
2
|
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
arr.map(String); // ['1', '2', '3', '4', '5', '6', '7', '8', '9']
|
reduce 这个函数必须接收两个参数,reduce()把结果继续和序列的下一个元素做累积计算
[x1, x2, x3, x4].reduce(f) = f(f(f(x1, x2), x3), x4)
1
2
3
4
|
var arr = [1, 3, 5, 7, 9];
arr.reduce(function (x, y) {
return x + y;
}); // 25
|
filter 它用于把Array的某些元素过滤掉,然后返回剩下的元素。
filter()把传入的函数依次作用于每个元素,然后根据返回值是true还是false决定保留还是丢弃该元素。
在一个Array中,删掉偶数,只保留奇数,可以这么写:
1
2
3
4
5
|
var arr = [1, 2, 4, 5, 6, 9, 10, 15];
var r = arr.filter(function (x) {
return x % 2 !== 0;
});
r; // [1, 5, 9, 15]
|
把一个Array中的空字符串删掉,可以这么写:
1
2
3
4
5
|
var arr = ['A', '', 'B', null, undefined, 'C', ' '];
var r = arr.filter(function (s) {
return s && s.trim(); // 注意:IE9以下的版本没有trim()方法
});
r; // ['A', 'B', 'C']
|
回调函数
filter()接收的回调函数,其实可以有多个参数。通常我们仅使用第一个参数,表示Array的某个元素。回调函数还可以接收另外两个参数,表示元素的位置和数组本身:
1
2
3
4
5
6
7
|
var arr = ['A', 'B', 'C'];
var r = arr.filter(function (element, index, self) {
console.log(element); // 依次打印'A', 'B', 'C'
console.log(index); // 依次打印0, 1, 2
console.log(self); // self就是变量arr
return true;
});
|
去除重复元素依靠的是indexOf总是返回第一个元素的位置,后续的重复元素位置与indexOf返回的位置不相等,因此被filter滤掉了。
sort
排序算法
通常规定,对于两个元素x和y,如果认为x < y,则返回-1,如果认为x == y,则返回0,如果认为x > y,则返回1
1
2
3
4
5
6
7
8
|
// 看上去正常的结果:
['Google', 'Apple', 'Microsoft'].sort(); // ['Apple', 'Google', 'Microsoft'];
// apple排在了最后:
['Google', 'apple', 'Microsoft'].sort(); // ['Google', 'Microsoft", 'apple']
// 无法理解的结果:
[10, 20, 1, 2].sort(); // [1, 10, 2, 20]
|
因为字符'1’比字符'2’的ASCII码小 也就是说sort按照的是ascii来排序
sort()方法也是一个高阶函数,它还可以接收一个比较函数来实现自定义的排序。
1
2
3
4
5
6
7
8
9
10
11
12
|
var arr = ['Google', 'apple', 'Microsoft'];
arr.sort(function (s1, s2) {
x1 = s1.toUpperCase();
x2 = s2.toUpperCase();
if (x1 < x2) {
return -1;
}
if (x1 > x2) {
return 1;
}
return 0;
}); // ['apple', 'Google', 'Microsoft']
|
闭包(Closure)
闭包 (matosiki:首先要把函数当作元数据看待,其次,函数和元素的区分可以看看lisp 主要是闭包返回函数 而此函数引用的变量还没使用 或者还在使用局部变量 )
高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。
返回闭包时牢记的一点就是:返回函数不要引用任何循环变量,或者后续会发生变化的变量
如果不需要立刻求和,而是在后面的代码中,根据需要再计算怎么办?可以不返回求和的结果,而是返回求和的函数!
1
2
3
4
5
6
7
8
9
10
|
function lazy_sum(arr) {
var sum = function () {
return arr.reduce(function (x, y) {
return x + y;
});
}
return sum;
}
// var f = lazy_sum([1, 2, 3, 4, 5]); // function sum()
|
这就是闭包的魅力
当一个函数返回了一个函数后,其内部的局部变量还被新函数引用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
function count() {
var arr = [];
for (var i=1; i<=3; i++) {
arr.push(
//存放3次匿名函数到arr数组中,并且在调用count方法时已经将i绑定到匿名函数。
(function (n) {
return function () {
return n * n;
}
})(i));
}
return arr;
}
var results = count();
var f1 = results[0];
var f2 = results[1];
var f3 = results[2];
f1(); // 1
f2(); // 4
f3(); // 9
|
创建一个匿名函数并立刻执行的语法:
1
2
3
|
(function (x) {
return x * x;
})(3); // 9
|
在没有class机制,只有函数的语言里,借助闭包,同样可以封装一个私有变量。我们用JavaScript创建一个计数器:
1
2
3
4
5
6
7
8
9
10
|
'use strict';
function create_counter(initial) {
var x = initial || 0;
return {
inc: function () {
x += 1;
return x;
}
}
}
|
1
2
3
4
|
var c1 = create_counter();
c1.inc(); // 1
c1.inc(); // 2
c1.inc(); // 3
|
1
2
3
4
5
6
7
8
9
10
11
12
|
function make_pow(n) {
return function (x) {
return Math.pow(x, n);
}
}
// 创建两个新函数:
var pow2 = make_pow(2);
var pow3 = make_pow(3);
pow2(5); // 25
pow3(7); // 343
|
脑洞大开 (在函数的世界里,一切皆函数)
很久很久以前,有个叫阿隆佐·邱奇的帅哥,发现只需要用函数,就可以用计算机实现运算,而不需要0、1、2、3这些数字和+、-、*、/这些符号。
JavaScript支持函数,所以可以用JavaScript用函数来写这些计算。来试试:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
|
'use strict';
// 定义数字0:
var zero = function (f) {
return function (x) {
return x;
}
};
// 定义数字1:
var one = function (f) {
return function (x) {
return f(x);
}
};
// 定义加法:
function add(n, m) {
return function (f) {
return function (x) {
return m(f)(n(f)(x));
}
}
}
// 定义乘法,n运行m次
function mult(n,m){
return function (f){
return function (x) {
return m((n)(f))(x);
}
}
}
// 定义乘方,乘法运行m次
function power(n,m){
return function (f){
return function (x) {
return (n)(m)(f)(x);
}
}
}
// 定义前趋(返回n-1),建一个数组[n,m]然后把它迭代到[n+1,n]再通过返回右支,对[0,0]运算n次就是[n,n-1],返回右支用数字0的定义.其实这是在抵消f就是加法.....
function dec(n){
return function(f){
return function(x){
n(function(g){
return function(h){
return h((g)(f))
}
})(function(u){
return x
})(function(u){
return u
})
}
}
}
// 定义减法n>m
function subb(n,m){
return m(dec)(n); // 对n运行m次前趋运算,既n-1运行m次,相当于n-m
}
// 最后,亲,你要的除法
divide = (\n.((\f.(\x.x x) (\x.f (x x))) (\c.\n.\m.\f.\x.(\d.(\n.n (\x.(\a.\b.b)) (\a.\b.a)) d ((\f.\x.x) f x) (f (c d m f x))) ((\m.\n.n (\n.\f.\x.n (\g.\h.h (g f)) (\u.x) (\u.u)) m) n m))) ((\n.\f.\x. f (n f x)) n))
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
// 计算数字2 = 1 + 1:
var two = add(one, one);
// 计算数字3 = 1 + 2:
var three = add(one, two);
// 计算数字5 = 2 + 3:
var five = add(two, three);
// 你说它是3就是3,你说它是5就是5,你怎么证明?
// 呵呵,看这里:
// 给3传一个函数,会打印3次:
(three(function () {
console.log('print 3 times');
}))();
// 给5传一个函数,会打印5次:
(five(function () {
console.log('print 5 times');
}))();
// 继续接着玩一会...
//自己测试 发现输出
one(function(test){console.log('good-'+test)})('taste') //good-taste
two(function(x){console.log('good-'+x)})('boy') //good-boy good-undefined
three(function(x){console.log('good-'+x)})('boy') //good-boy good-undefined good-undefined
|
Arrow Function(箭头函数)
x = x* x;
function(x){ return x* x;}
var fn = x => x * x;
箭头函数相当于匿名函数,并且简化了函数定义。箭头函数有两种格式,一种像上面的,只包含一个表达式,连{ … }和return都省略掉了。还有一种可以包含多条语句,这时候就不能省略{ … }和return:
1
2
3
4
5
6
7
8
|
x => {
if (x > 0) {
return x * x;
}
else {
return - x * x;
}
}
|
如果参数不是一个,就需要用括号()括起来:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
// 两个参数:
(x, y) => x * x + y * y
// 无参数:
() => 3.14
// 可变参数:
(x, y, ...rest) => {
var i, sum = x + y;
for (i=0; i<rest.length; i++) {
sum += rest[i];
}
return sum;
}
|
如果要返回一个对象,就要注意,如果是单表达式
x => ({ foo: x })
箭头函数和匿名函数有个明显的区别:箭头函数内部的this是词法作用域,由上下文确定。
1
2
3
4
5
6
7
8
9
|
var obj = {
birth: 1990,
getAge: function () {
var b = this.birth; // 1990
var fn = () => new Date().getFullYear() - this.birth; // this指向obj对象
return fn();
}
};
obj.getAge(); // 25
|
由于this在箭头函数中已经按照词法作用域绑定了,所以,用call()或者apply()调用箭头函数时,无法对this进行绑定,即传入的第一个参数被忽略:
1
2
3
4
5
6
7
8
9
|
var obj = {
birth: 1990,
getAge: function (year) {
var b = this.birth; // 1990
var fn = (y) => y - this.birth; // this.birth仍是1990
return fn.call({birth:2000}, year);
}
};
obj.getAge(2015); // 25
|
generator
generator(生成器)是ES6标准引入的新的数据类型。一个generator看上去像一个函数,但可以返回多次。
函数在执行过程中,如果没有遇到return语句(函数末尾如果没有return,就是隐含的return undefined;),控制权无法交回被调用的代码。
1
2
3
4
5
|
function* foo(x) {
yield x + 1;
yield x + 2;
return x + 3;
}
|
我们以一个著名的斐波那契数列为例,它由0,1开头:
0 1 1 2 3 5 8 13 21 34 ...
要编写一个产生斐波那契数列的函数,可以这么写:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
function fib(max) {
var
t,
a = 0,
b = 1,
arr = [0, 1];
while (arr.length < max) {
t = a + b;
a = b;
b = t;
arr.push(t);
}
return arr;
}
|
测试:
1
2
|
fib(5); // [0, 1, 1, 2, 3]
fib(10); // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
function* fib(max) {
var
t,
a = 0,
b = 1,
n = 1;
while (n < max) {
yield a;
t = a + b;
a = b;
b = t;
n ++;
}
return a;
}
|
直接调用试试:
1
|
fib(5); // fib {[[GeneratorStatus]]: "suspended", [[GeneratorReceiver]]: Window}
|
调用generator对象有两个方法,一是不断地调用generator对象的next()方法:
1
2
3
4
5
6
|
var f = fib(5);
f.next(); // {value: 0, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 2, done: false}
f.next(); // {value: 3, done: true}
|
1
2
3
|
for (var x of fib(5)) {
console.log(x); // 依次输出0, 1, 1, 2, 3
}
|
用一个对象来保存状态,得这么写:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
var fib = {
a: 0,
b: 1,
n: 0,
max: 5,
next: function () {
var
r = this.a,
t = this.a + this.b;
this.a = this.b;
this.b = t;
if (this.n < this.max) {
this.n ++;
return r;
} else {
return undefined;
}
}
};
|
generator 还有另一个巨大的好处,就是把异步回调代码变成同步代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
ajax('http://url-1', data1, function (err, result) {
if (err) {
return handle(err);
}
ajax('http://url-2', data2, function (err, result) {
if (err) {
return handle(err);
}
ajax('http://url-3', data3, function (err, result) {
if (err) {
return handle(err);
}
return success(result);
});
});
});
|
有了generator的美好时代,用AJAX时可以这么写:
1
2
3
4
5
6
7
8
9
|
try {
r1 = yield ajax('http://url-1', data1);
r2 = yield ajax('http://url-2', data2);
r3 = yield ajax('http://url-3', data3);
success(r3);
}
catch (err) {
handle(err);
}
|
标准对象
包装对象
1
2
3
4
5
6
7
8
9
|
typeof 123; // 'number'
typeof NaN; // 'number'
typeof 'str'; // 'string'
typeof true; // 'boolean'
typeof undefined; // 'undefined'
typeof Math.abs; // 'function'
typeof null; // 'object'
typeof []; // 'object'
typeof {}; // 'object'
|
1
2
3
|
var n = new Number(123); // 123,生成了新的包装类型
var b = new Boolean(true); // true,生成了新的包装类型
var s = new String('str'); // 'str',生成了新的包装类型
|
闲的蛋疼也不要使用包装对象!
123.toString(); // SyntaxError
遇到这种情况,要特殊处理一下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
123..toString(); // '123', 注意是两个点!
(123).toString(); // '123'
var now = new Date();
now; // Wed Jun 24 2015 19:49:22 GMT+0800 (CST)
now.getFullYear(); // 2015, 年份
now.getMonth(); // 5, 月份,注意月份范围是0~11,5表示六月
now.getDate(); // 24, 表示24号
now.getDay(); // 3, 表示星期三
now.getHours(); // 19, 24小时制
now.getMinutes(); // 49, 分钟
now.getSeconds(); // 22, 秒
now.getMilliseconds(); // 875, 毫秒数
now.getTime(); // 1435146562875, 以number形式表示的时间戳
var d = Date.parse('2015-06-24T19:49:22.875+08:00');
|
时区
1
2
3
4
5
6
7
8
9
|
var d = new Date(1435146562875);
d.toLocaleString(); // '2015/6/24 下午7:49:22',本地时间(北京时区+8:00),显示的字符串与操作系统设定的格式有关
d.toUTCString(); // 'Wed, 24 Jun 2015 11:49:22 GMT',UTC时间,与本地时间相差8小时
if (Date.now) {
alert(Date.now()); // 老版本IE没有now()方法
} else {
alert(new Date().getTime());
}
|
正则表达式 regExp
创建正则表达式
1
2
3
4
|
var re1 = /ABC\-001/;
var re2 = new RegExp('ABC\\-001');
re1; // /ABC\-001/
re2; // /ABC\-001/
|
匹配正则表达式
1
2
3
4
|
var re = /^\d{3}\-\d{3,8}$/;
re.test('010-12345'); // true
re.test('010-1234x'); // false
re.test('010 12345'); // false
|
切分字符串split()
1
|
'a b c'.split(' '); // ['a', 'b', '', '', 'c']
|
无法识别连续的空格,用正则表达式试试:
1
|
'a b c'.split(/\s+/); // ['a', 'b', 'c']
|
无论多少个空格都可以正常分割。加入,试试:
1
|
'a,b, c d'.split(/[\s\,]+/); // ['a', 'b', 'c', 'd']
|
再加入;试试:
1
|
'a,b;; c d'.split(/[\s\,\;]+/); // ['a', 'b', 'c', 'd']
|
分组group
1
2
3
|
var re = /^(\d{3})-(\d{3,8})$/;
re.exec('010-12345'); // ['010-12345', '010', '12345']
re.exec('010 12345'); // null
|
贪婪匹配
1
2
|
var re = /^(\d+)(0*)$/;
re.exec('102300'); // ['102300', '102300', '']
|
加个?就可以让\d+采用非贪婪匹配:
1
2
|
var re = /^(\d+?)(0*)$/;
re.exec('102300'); // ['102300', '1023', '00']
|
1
2
3
|
var r1 = /test/g;
// 等价于:
var r2 = new RegExp('test', 'g');
|
当我们指定g标志后,每次运行exec(),正则表达式本身会更新lastIndex属性,表示上次匹配到的最后索引:
var s = ‘JavaScript, VBScript, JScript and ECMAScript’;
var re=/[a-zA-Z]+Script/g;
1
2
3
4
5
6
7
8
9
10
|
// 使用全局匹配:
re.exec(s); // ['JavaScript']
re.lastIndex; // 10
re.exec(s); // ['VBScript']
re.lastIndex; // 20
re.exec(s); // ['JScript']
re.lastIndex; // 29
re.exec(s); // ['ECMAScript']
re.lastIndex; // 44
re.exec(s); // null,直到结束仍没有匹配到
|
json
1
2
3
4
5
6
|
number:和JavaScript的number完全一致;
boolean:就是JavaScript的true或false;
string:就是JavaScript的string;
null:就是JavaScript的null;
array:就是JavaScript的Array表示方式 ---- [];
object:就是JavaScript的{ ... }表示方式。
|
序列化
1
2
3
4
5
6
7
8
9
10
|
var xiaoming = {
name: '小明',
age: 14,
gender: true,
height: 1.65,
grade: null,
'middle-school': '\"W3C\" Middle School',
skills: ['JavaScript', 'Java', 'Python', 'Lisp']
};
JSON.stringify(xiaoming); // '{"name":"小明","age":14,"gender":true,"height":1.65,"grade":null,"middle-school":"\"W3C\" Middle School","skills":["JavaScript","Java","Python","Lisp"]}'
|
JSON.stringify(xiaoming, null, ’ ‘);
输出的格式很好
如果我们只想输出指定的属性,可以传入Array:
1
2
3
4
5
6
7
8
9
|
{
"name": "小明",
"skills": [
"JavaScript",
"Java",
"Python",
"Lisp"
]
}
|
还可以传入一个函数,这样对象的每个键值对都会被函数先处理:
1
2
3
4
5
6
7
|
function convert(key, value) {
if (typeof value === 'string') {
return value.toUpperCase();
}
return value;
}
JSON.stringify(xiaoming, convert, ' ');
|
上面的代码把所有属性值都变成大写:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
{
"name": "小明",
"age": 14,
"gender": true,
"height": 1.65,
"grade": null,
"middle-school": "\"W3C\" MIDDLE SCHOOL",
"skills": [
"JAVASCRIPT",
"JAVA",
"PYTHON",
"LISP"
]
}
|
如果我们还想要精确控制如何序列化小明,可以给xiaoming定义一个toJSON()的方法,直接返回JSON应该序列化的数据:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
var xiaoming = {
name: '小明',
age: 14,
gender: true,
height: 1.65,
grade: null,
'middle-school': '\"W3C\" Middle School',
skills: ['JavaScript', 'Java', 'Python', 'Lisp'],
toJSON: function () {
return { // 只输出name和age,并且改变了key:
'Name': this.name,
'Age': this.age
};
}
};
JSON.stringify(xiaoming); // '{"Name":"小明","Age":14}'
|
反序列化
拿到一个JSON格式的字符串,我们直接用JSON.parse()把它变成一个JavaScript对象:
1
2
3
4
|
JSON.parse('[1,2,3,true]'); // [1, 2, 3, true]
JSON.parse('{"name":"小明","age":14}'); // Object {name: '小明', age: 14}
JSON.parse('true'); // true
JSON.parse('123.45'); // 123.45
|
JSON.parse()还可以接收一个函数,用来转换解析出的属性:
1
2
3
4
5
6
7
|
JSON.parse('{"name":"小明","age":14}', function (key, value) {
// 把number * 2:
if (key === 'name') {
return value + '同学';
}
return value;
}); // Object {name: '小明同学', age: 14}
|
yahoo api
面向对象编程
定义对象 申明对象用{} 大括号 声明方法用 fun_name: function(){….} 声明属性 键值对
1
2
3
4
5
6
7
|
var robot = {
name: 'Robot',
height: 1.6,
run: function () {
console.log(this.name + ' is running...');
}
};
|
对象实例化
基于原型 创建一个新对象:
//var s = Object.create(Student);
创建对象
JavaScript对每个创建的对象都会设置一个原型,指向它的原型对象。
原型链是javascript 继承的标志
函数也是对象
foo ----> Function.prototype ----> Object.prototype ----> null
构造函数
除了直接用{ ... }创建一个对象外,JavaScript还可以用一种构造函数的方法来创建对象。
1
2
3
4
5
6
|
function Student(name) {
this.name = name;
this.hello = function () {
alert('Hello, ' + this.name + '!');
}
}
|
但是实例化的时候必须用new 不然就是普通函数
1
2
3
|
var xiaoming = new Student('小明');
xiaoming.name; // '小明'
xiaoming.hello(); // Hello, 小明!
|
我们还可以编写一个createStudent()函数,在内部封装所有的new操作。一个常用的编程模式像这样:
1
2
3
4
5
6
7
8
9
10
|
function Student(props) {
this.name = props.name || '匿名'; // 默认值为'匿名'
this.grade = props.grade || 1; // 默认值为1
}
Student.prototype.hello = function () {
alert('Hello, ' + this.name + '!');
};
function createStudent(props) {
return new Student(props || {})
}
|
原型继承
原型继承 由于这类语言严格区分类和实例,继承实际上是类型的扩展。
//发明json的道琼格拉斯 发明了 利用空函数 f function(){} 做桥梁实现原型链
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
// PrimaryStudent构造函数:
function PrimaryStudent(props) {
Student.call(this, props);
this.grade = props.grade || 1;
}
// 空函数F:
function F() {
}
// 把F的原型指向Student.prototype:
F.prototype = Student.prototype;
// 把PrimaryStudent的原型指向一个新的F对象,F对象的原型正好指向Student.prototype:
PrimaryStudent.prototype = new F();
// 把PrimaryStudent原型的构造函数修复为PrimaryStudent:
PrimaryStudent.prototype.constructor = PrimaryStudent;
// 继续在PrimaryStudent原型(就是new F()对象)上定义方法:
PrimaryStudent.prototype.getGrade = function () {
return this.grade;
};
// 创建xiaoming:
var xiaoming = new PrimaryStudent({
name: '小明',
grade: 2
});
xiaoming.name; // '小明'
xiaoming.grade; // 2
// 验证原型:
xiaoming.__proto__ === PrimaryStudent.prototype; // true
xiaoming.__proto__.__proto__ === Student.prototype; // true
// 验证继承关系:
xiaoming instanceof PrimaryStudent; // true
xiaoming instanceof Student; // true
|
把继承这个动作用一个inherits()函数封装起来,还可以隐藏F的定义,并简化代码:
1
2
3
4
5
6
|
function inherits(Child, Parent) {
var F = function () {};
F.prototype = Parent.prototype;
Child.prototype = new F();
Child.prototype.constructor = Child;
}
|
class 继承
新的关键字class从ES6开始正式被引入到JavaScript中。class的目的就是让定义类更简单。
1
2
3
4
5
6
7
8
9
|
class Student {
constructor(name) {
this.name = name;
}
hello() {
alert('Hello, ' + this.name + '!');
}
}
|
实例化对象
var xiaoming = new Student(‘小明’);xiaoming.hello();
继承实现
1
2
3
4
5
6
7
8
9
10
|
class PrimaryStudent extends Student {
constructor(name, grade) {
super(name); // 记得用super调用父类的构造方法!
this.grade = grade;
}
myGrade() {
alert('I am at grade ' + this.grade);
}
}
|
对class 继承转原型链 可使用https://babeljs.io/ 的 Babel
好了关于js基本编程复习到这里 往后是浏览器dom操作复习