ZetCode-JavaScript-教程-一-
ZetCode JavaScript 教程(一)
原文:ZetCode
协议:CC BY-NC-SA 4.0
Ramda 教程
原文: http://zetcode.com/javascript/ramda/
Ramda 教程展示了如何使用 Ramda 库,该库为 JavaScript 中的高级函数编程提供了工具。 在本教程中,我们可以互换使用术语列表和数组。
Ramda
Ramda 是 JavaScript 程序员的实用函数库。 该库专注于不变性和无副作用的函数。 Ramda 函数也会自动进行更新,从而只需不提供最终参数就可以从旧函数中构建新函数。
在本教程中,我们在 Node 应用中使用 Ramda。
安装 Ramda
首先,我们安装 Ramda。
$ nodejs -v
v9.11.2
我们使用 Node 版本 9.11.2。
$ npm init
我们启动一个新的 Node 应用。
$ npm i ramda
我们使用npm i ramda
命令安装 Ramda。
const R = require('ramda');
按照惯例,该库使用 R 字母。
Ramda add()
,subtract()
函数
add()
函数将两个值相加,subtract()
函数将两个值相减。
add_sub.js
const R = require('ramda');
console.log(R.add(2, 5));
console.log(R.subtract(2, 5));
let res = R.add(R.add(2, 5), R.subtract(2, 10));
console.log(res);
该示例同时使用add()
和subtract()
函数。
let res = R.add(R.add(2, 5), R.subtract(2, 10));
在这里,我们结合了这些函数。
$ node add_sub.js
7
-3
-1
这是输出。
Ramda flip()
函数
flip()
函数从提供的函数返回一个新函数,该函数的参数相反。
flipfun.js
const R = require('ramda');
let val = R.subtract(2, 10);
console.log(val);
let val2 = R.flip(R.subtract)(2, 10);
console.log(val2);
该示例使用flip()
反转subtract()
函数的参数。
$ node flipfun.js
-8
8
这是输出。
Ramda call()
函数
call()
函数在用逗号分隔的参数上调用提供的函数。
calling.js
const R = require('ramda');
let res = R.call(R.add, 1, 2);
console.log(res);
console.log(R.call(R.repeat, 'x')(5));
R.call(console.log, [1, 2, 3]);
该示例使用call()
函数。
let res = R.call(R.add, 1, 2);
我们调用add()
函数将两个整数相加。
console.log(R.call(R.repeat, 'x')(5));
我们调用repeat()
函数来生成五个"x"
字母的列表。
R.call(console.log, [1, 2, 3]);
最后,我们使用call()
函数输出列表。
$ node calling.js
3
[ 'x', 'x', 'x', 'x', 'x' ]
[ 1, 2, 3 ]
这是输出。
Ramda apply()
函数
apply()
函数在参数列表上调用提供的函数。
applyfun.js
const R = require('ramda');
let nums = [3, 5, 7, 8, 2, 1];
let res = R.apply(Math.min, nums);
console.log(res);
let res2 = R.apply(Math.max, nums);
console.log(res2);
该示例使用apply()
函数来计算最小值和最大值。
let res = R.apply(Math.min, nums);
我们在nums
列表上调用Math.min
函数。 我们从这些值中获得最小值。
$ node applyfun.js
1
8
我们得到最小和最大。
Ramda 自动柯里
柯里化是将需要多个参数的函数转换为另一个函数的过程,当提供较少的参数时,该函数将返回一个等待其余参数的新函数。
currying.js
const R = require('ramda');
let addOneToAll = R.map(R.add(1));
let res = addOneToAll([1,2,3]);
console.log(res);
在示例中,我们创建了一个addOneToAll()
函数,该函数将列表中的每个元素加 1。
$ node currying.js
[ 2, 3, 4 ]
这是输出。
Ramda head()
,tail()
,init()
,last()
函数
head()
返回给定列表或字符串的第一个元素。 tail()
返回给定列表或字符串的除第一个元素外的所有元素。 init()
返回给定列表或字符串的最后一个元素以外的所有元素。 last()
返回给定列表或字符串的最后一个元素。
head_tail.js
const R = require('ramda');
let nums = [2, 4, 6, 8, 10];
console.log(R.head(nums));
console.log(R.tail(nums));
console.log(R.init(nums));
console.log(R.last(nums));
该示例在值数组上使用head()
,tail()
,init()
和last()
函数。
$ node head_tail.js
2
[ 4, 6, 8, 10 ]
[ 2, 4, 6, 8 ]
10
这是输出。
Ramda length()
函数
length()
函数返回列表中的元素数。
lengthfun.js
const R = require('ramda');
let nums = [1, 2, 2, 2, 3, 3, 4, 5, 5, 5, 6, 7];
let n1 = R.length(nums);
console.log(n1);
let n2 = R.length(R.uniq(nums));
console.log(n2);
在示例中,我们计算列表中的元素数和列表中的唯一元素数。
$ node lengthfn.js
12
7
列表中有十二个元素,列表中有七个唯一元素。
Ramda prop()
函数
prop()
函数返回对象的指定属性(如果存在)。
propfun.js
const R = require('ramda');
console.log(R.prop('name', { name: 'John', age: 25 }));
console.log(R.prop('age', { name: 'John', age: 25 }));
使用prop()
函数,我们可以获得name
和age
属性的值。
$ node propfun.js
John
25
这是输出。
Ramda pluck()
函数
pluck()
函数通过从提供的列表中的所有对象上拔出指定的属性来返回新列表。
plucking.js
const R = require('ramda');
const users = [
{ name: 'John', age: 25 },
{ name: 'Lenny', age: 51 },
{ name: 'Andrew', age: 43 },
{ name: 'Peter', age: 81 },
{ name: 'Anna', age: 43 },
{ name: 'Albert', age: 76 },
{ name: 'Adam', age: 47 },
{ name: 'Robert', age: 72 }
];
console.log(R.pluck('age', users));
console.log(R.pluck('name', users));
通过pluck()
函数,我们获得name
和age
属性,并形成两个新列表。
$ node plucking.js
[ 25, 51, 43, 81, 43, 76, 47, 72 ]
[ 'John',
'Lenny',
'Andrew',
'Peter',
'Anna',
'Albert',
'Adam',
'Robert' ]
在下面的示例中,我们将使用形成的列表。
plucking2.js
const R = require('ramda');
const users = [
{ name: 'John', age: 25 },
{ name: 'Lenny', age: 51 },
{ name: 'Andrew', age: 43 },
{ name: 'Peter', age: 81 },
{ name: 'Anna', age: 43 },
{ name: 'Albert', age: 76 },
{ name: 'Adam', age: 47 },
{ name: 'Robert', age: 72 }
];
let maxAge = R.apply(Math.max, R.pluck('age', users));
// let maxAge = Math.max(... R.pluck('age', users));
console.log(`The oldest person is ${maxAge} years old.`);
在示例中,我们找出一个人的最大年龄。
let maxAge = R.apply(Math.max, R.pluck('age', users));
通过在年龄列表上调用Math.max()
函数,我们可以获得最老的年龄。
// let maxAge = Math.max(... R.pluck('age', users));
另一种带注释的解决方案使用扩展运算符代替apply()
函数。
$ node plucking2.js
The oldest person is 81 years old.
这是输出。
Ramda 拆分列表
使用splitEvery()
函数,我们可以将列表分成指定长度的块。
chunks.js
const R = require('ramda');
let nums = [1, 2, 3, 4, 5, 6];
console.log(R.splitEvery(2, nums));
console.log(R.splitEvery(3, nums));
在示例中,我们将数组分为 2 个元素和 3 个元素的块。
$ node chunks.js
[ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ] ]
[ [ 1, 2, 3 ], [ 4, 5, 6 ] ]
这是输出。
Ramda contains()
函数
如果指定的值在列表中,则contains()
函数返回true
。
containsfun.js
const R = require('ramda');
const users = [
{ name: 'John', age: 25 },
{ name: 'Lenny', age: 51 },
{ name: 'Andrew', age: 43 },
{ name: 'Peter', age: 81 },
{ name: 'Anna', age: 43 },
{ name: 'Albert', age: 76 },
{ name: 'Adam', age: 47 },
{ name: 'Robert', age: 72 }
];
let isJohn = R.contains('John', R.pluck('name', users));
if (isJohn) {
console.log('There is John in the list');
}
在示例中,我们检查指定的用户是否在列表中。
let isJohn = R.contains('John', R.pluck('name', users));
首先,我们使用pluck()
函数从name
属性中形成一个列表。 然后我们用contains()
检查'John'是否在列表中。
$ node containsfun.js
There is John in the list
这是输出。
Ramda range()
函数
range()
函数返回从起始值(包含)到结束值(不含)的数字列表。
rangefun.js
const R = require('ramda');
console.log(R.range(1, 10));
let vals = R.range(2, 12);
vals.forEach(x => console.log(x));
该示例显示了如何使用range()
函数。
console.log(R.range(1, 10));
在这一行中,我们创建一个1..9
整数列表。 我们将它们打印到控制台。
let vals = R.range(2, 12);
vals.forEach(x => console.log(x));
在这里,我们生成一个2..11
值的列表。 我们使用forEach()
函数浏览列表。
$ node rangefun.js
[ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
2
3
4
5
6
7
8
9
10
11
这是输出。
Ramda sum()
函数
sum()
函数对列表的所有元素求和。
summation.js
const R = require('ramda');
let nums = [2, 4, 6, 8, 10];
console.log(R.sum(nums));
console.log(R.sum(R.range(1, 11)));
该示例使用sum()
函数对整数值求和。
let nums = [2, 4, 6, 8, 10];
console.log(R.sum(nums));
在这里,我们对nums
数组的值求和。
console.log(R.sum(R.range(1, 11)));
在这一行中,我们对range()
函数生成的列表的值求和。
$ node summation.js
30
55
这是输出。
Ramda product()
函数
product()
函数将列表的所有元素相乘。
productfun.js
const R = require('ramda');
let nums = [2, 4, 6, 8, 10];
console.log(R.product(nums));
该示例计算整数列表的乘积。
$ node productfun.js
3840
这是输出。
Ramda sort()
,reverse()
函数
sort()
函数返回列表的副本,该列表根据比较器函数排序。 比较器函数一次接受两个值,如果第一个值较小,则返回一个负数;如果较大,则返回一个正数;如果相等,则返回零。
reverse()
函数以相反的顺序返回带有元素或字符的新列表或字符串。
sort_reverse.js
const R = require('ramda');
let nums = [3, 1, 4, 2, 8, 5, 6];
console.log('sorting:')
// sort ascending
console.log(R.sort((x, y) => x - y , nums));
// sort descending
console.log(R.sort((x, y) => y - x , nums));
console.log('reversing:')
// reversing
console.log(R.reverse(nums));
console.log(R.reverse('forest'));
该示例按升序和降序对整数进行排序,并反转整数和字符串。
$ node sort_reverse.js
sorting:
[ 1, 2, 3, 4, 5, 6, 8 ]
[ 8, 6, 5, 4, 3, 2, 1 ]
reversing:
[ 6, 5, 8, 2, 4, 1, 3 ]
tserof
这是输出。
我们还可以使用内置的R.lt
和R.gt
比较器。
sort_comp.js
const R = require('ramda');
let nums = [3, 1, 4, 2, 8, 5, 6];
console.log('sorting:')
// sort ascending
console.log(R.sort(R.comparator(R.lt), nums));
// sort descending
console.log(R.sort(R.comparator(R.gt), nums));
该示例按升序和降序对整数进行排序。
Ramda sortBy
函数
sortBy()
函数根据提供的函数对列表进行排序。
sorting_objects.js
const R = require('ramda');
const users = [
{ name: 'John', age: 25 },
{ name: 'Lenny', age: 51 },
{ name: 'Andrew', age: 43 },
{ name: 'Peter', age: 81 },
{ name: 'Anna', age: 43 },
{ name: 'Albert', age: 76 },
{ name: 'Adam', age: 47 },
{ name: 'Robert', age: 72 }
];
console.log('Sorted by age:');
let sortedByAge = R.sortBy(R.prop('age'), users);
console.log(sortedByAge);
console.log('Sorted by name:');
let sortedByName = R.sortBy(R.prop('name'), users);
console.log(sortedByName);
在示例中,我们按age
和name
属性以升序对用户列表进行排序。
$ node sorting_objects.js
Sorted by age:
[ { name: 'John', age: 25 },
{ name: 'Andrew', age: 43 },
{ name: 'Anna', age: 43 },
{ name: 'Adam', age: 47 },
{ name: 'Lenny', age: 51 },
{ name: 'Robert', age: 72 },
{ name: 'Albert', age: 76 },
{ name: 'Peter', age: 81 } ]
Sorted by name:
[ { name: 'Adam', age: 47 },
{ name: 'Albert', age: 76 },
{ name: 'Andrew', age: 43 },
{ name: 'Anna', age: 43 },
{ name: 'John', age: 25 },
{ name: 'Lenny', age: 51 },
{ name: 'Peter', age: 81 },
{ name: 'Robert', age: 72 } ]
这是输出。
Ramda find
,findLast
函数
find()
函数返回与谓词匹配的列表的第一个元素;如果不匹配,则返回undefined
。 findLast()
函数返回列表中与谓词匹配的最后一个元素,如果没有元素匹配,则返回undefined
。
finding.js
const R = require('ramda');
const isPositive = x => x > 0;
let values = [-1, 0, -4, 5, 6, -1, 9, -2]
let val = R.find(isPositive, values);
console.log(val);
let val2 = R.findLast(isPositive, values);
console.log(val2);
在示例中,我们找到第一个和最后一个正值。
const isPositive = x => x > 0;
isPositive()
是一个谓词函数,对于大于零的值返回true
。
let val = R.find(isPositive, values);
使用find()
,我们发现第一个出现的正数。
let val2 = R.findLast(isPositive, values);
使用findLast()
,我们找到最后一个正数。
$ node finding.js
5
9
第一个正值为 5,最后为 9。
在下面的示例中,我们在对象列表上使用find()
函数。
finding2.js
const R = require('ramda');
const users = [
{ name: 'John', age: 25 },
{ name: 'Lenny', age: 51 },
{ name: 'Andrew', age: 43 },
{ name: 'Peter', age: 81 },
{ name: 'Anna', age: 43 },
{ name: 'Albert', age: 76 },
{ name: 'Adam', age: 47 },
{ name: 'Robert', age: 72 },
{ name: 'Robert', age: 26 },
];
console.log(R.find(R.propEq('name', 'Robert'))(users));
console.log(R.find(R.propEq('age', 81))(users));
通过find()
和propEq()
函数的组合,我们寻找具有指定属性的用户。
console.log(R.find(R.propEq('name', 'Robert'))(users));
在这里,我们寻找一个名叫罗伯特的人。 有两个罗伯茨(Roberts),并且第一场比赛被返回。
$ node finding2.js
{ name: 'Robert', age: 72 }
{ name: 'Peter', age: 81 }
这是输出。
Ramda map()
函数
map()
函数将提供的函数映射到每个容器的值。
mapping.js
const R = require('ramda');
nums = [2, 4, 5, 6, 7, 8, 9];
let res = R.map(x => x * 2, nums);
console.log(res);
const isEven = x => x % 2 === 0;
let res2 = R.map(isEven, nums);
console.log(res2);
let repeated = R.map(R.call, R.repeat(Math.random, 5));
console.log(repeated);
该示例演示了map()
的用法。
let res = R.map(x => x * 2, nums);
我们将匿名函数映射到整数列表上。 生成一个新列表,其中每个值都乘以 2。
const isEven = x => x % 2 === 0;
let res2 = R.map(isEven, nums);
在这里,我们在每个元素上应用isEven()
函数。 res2
是正确和错误值的列表。 如果我们只想选择事件号,则可以使用filter()
函数。
let repeated = R.map(R.call, R.repeat(Math.random, 5));
在第三种情况下,我们生成五个随机值的列表。
$ node mapping.js
[ 4, 8, 10, 12, 14, 16, 18 ]
[ true, true, false, true, false, true, false ]
[ 0.22019193556521865,
0.415950206671615,
0.8770997167119405,
0.23393806619678315,
0.8181008680173825 ]
这是输出。
Ramda filter()
函数
filter()
函数根据提供的谓词函数过滤可过滤对象(例如列表或普通对象)。 (谓词是一个返回布尔值的函数)。
filtering.js
const R = require('ramda');
nums = [-3, -1, 0, 2, 3, 4, 5, 6, 7]
let res = R.filter(x => x > 0, nums);
console.log(res);
let res2 = R.filter(x => x < 0, nums);
console.log(res2);
const isEven = x => x % 2 === 0;
let filtered = R.filter(isEven, nums);
console.log(filtered);
在示例中,我们有一个整数值列表。 我们使用filter()
函数过滤出正,负和偶数值。
let res = R.filter(x => x > 0, nums);
此行中的filter()
函数采用匿名函数,该函数对于所有大于零的值都返回true
。 然后将谓词应用于列表的每个元素。 这样,我们形成一个仅包含正值的新列表。
$ node filtering.js
[ 2, 3, 4, 5, 6, 7 ]
[ -3, -1 ]
[ 0, 2, 4, 6 ]
这是输出。
在下面的示例中,我们将filter()
函数应用于用户列表。
filtering2.js
const R = require('ramda');
// senior is a person who is 70+
const users = [
{ name: 'John', age: 25 },
{ name: 'Lenny', age: 51 },
{ name: 'Andrew', age: 43 },
{ name: 'Peter', age: 81 },
{ name: 'Anna', age: 43 },
{ name: 'Albert', age: 76 },
{ name: 'Adam', age: 47 },
{ name: 'Robert', age: 72 }
];
console.log(R.filter(user => user.age >= 70, users));
该示例将高级用户过滤掉。 我们将年长者定义为 70 岁以上的人。
$ node filtering2.js
[ { name: 'Peter', age: 81 },
{ name: 'Albert', age: 76 },
{ name: 'Robert', age: 72 } ]
我们有三个高级用户。
reject()
函数
reject()
是filter()
的补充。 它排除谓词为其返回true
的可过滤元素。
rejecting.js
const R = require('ramda');
const users = [
{ name: 'John', city: 'London', born: '2001-04-01' },
{ name: 'Lenny', city: 'New York', born: '1997-12-11' },
{ name: 'Andrew', city: 'Boston', born: '1987-02-22' },
{ name: 'Peter', city: 'Prague', born: '1936-03-24' },
{ name: 'Anna', city: 'Bratislava', born: '1973-11-12' },
{ name: 'Albert', city: 'Bratislava', born: '1940-18-19' },
{ name: 'Adam', city: 'Trnava', born:'1983-12-01' },
{ name: 'Robert', city: 'Bratislava', born: '1935-05-15' },
{ name: 'Robert', city: 'Prague', born:'1998-03-14' }
];
let res = R.reject(R.propEq('city', 'Bratislava'))(users);
console.log(res);
let res2 = R.filter(R.propEq('city', 'Bratislava'))(users);
console.log(res2);
在示例中,我们使用reject()
函数形成不包含布拉迪斯拉发城市的对象的新列表。 我们还使用filter()
函数形成包含布拉迪斯拉发城市的对象的新列表。
$ node rejecting.js
[ { name: 'John', city: 'London', born: '2001-04-01' },
{ name: 'Lenny', city: 'New York', born: '1997-12-11' },
{ name: 'Andrew', city: 'Boston', born: '1987-02-22' },
{ name: 'Peter', city: 'Prague', born: '1936-03-24' },
{ name: 'Adam', city: 'Trnava', born: '1983-12-01' },
{ name: 'Robert', city: 'Prague', born: '1998-03-14' } ]
[ { name: 'Anna', city: 'Bratislava', born: '1973-11-12' },
{ name: 'Albert', city: 'Bratislava', born: '1940-18-19' },
{ name: 'Robert', city: 'Bratislava', born: '1935-05-15' } ]
这是输出。 第一个列表包含不包含布拉迪斯拉发城市属性的所有对象。第二个列表仅包含具有布拉迪斯拉发城市属性的对象。
partition()
函数
partition()
函数将filter
分为两个独立的对象:一个满足谓词,另一个不满足。
partitionfun.js
const R = require('ramda');
let nums = [4, -5, 3, 2, -1, 7, -6, 8, 9];
let [ neg, pos ] = R.partition(e => e < 0, nums);
console.log(neg);
console.log(pos);
使用partition()
函数,我们将整数列表分为两个单独的列表:负数和正数。
$ node partitionfun.js
[ -5, -1, -6 ]
[ 4, 3, 2, 7, 8, 9 ]
第一个列表包含负值,第二个列表包含正值。
Ramda groupBy
函数
groupBy()
函数基于在每个元素上调用String
返回函数并根据返回的值对结果进行分组的结果,将列表分为存储在对象中的子列表。
grouping.js
const R = require('ramda');
let students = [
{ name: 'Adam', score: 84 },
{ name: 'Eddy', score: 58 },
{ name: 'Peter', score: 69 },
{ name: 'Roman', score: 93 },
{ name: 'Jane', score: 56 },
{ name: 'Lucy', score: 76 },
{ name: 'Jack', score: 88 },
];
var groupByGrade = R.groupBy((student) => {
let score = student.score;
return score < 65 ? 'F' :
score < 70 ? 'D' :
score < 80 ? 'C' :
score < 90 ? 'B' : 'A';
});
let grouped = groupByGrade(students);
console.log('Student(s) having A grade:');
console.log(grouped['A']);
console.log('Student(s) having B grade:');
console.log(grouped['B']);
console.log('Student(s) having C grade:');
console.log(grouped['D']);
console.log('Student(s) having D grade:');
console.log(grouped['D']);
console.log('Student(s) having F grade:');
console.log(grouped['F']);
在此示例中,我们将学生按分数分组到成绩子列表中。
$ node grouping.js
Student(s) having A grade:
[ { name: 'Roman', score: 93 } ]
Student(s) having B grade:
[ { name: 'Adam', score: 84 }, { name: 'Jack', score: 88 } ]
Student(s) having C grade:
[ { name: 'Peter', score: 69 } ]
Student(s) having D grade:
[ { name: 'Peter', score: 69 } ]
Student(s) having F grade:
[ { name: 'Eddy', score: 58 }, { name: 'Jane', score: 56 } ]
这是输出。
Ramda reduce()
函数
reduce()
函数将列表值聚合为一个值。 它对一个累加器和列表中的每个元素(从左到右)应用一个函数,以将其减少为单个值。
reducefun.js
const R = require('ramda');
let nums = [2, 3, 4, 5, 6, 7];
let sum = R.reduce((x, y) => x+y, 0, nums);
console.log(sum);
let product = R.reduce((x, y) => x*y, 1, nums);
console.log(product);
该示例使用reduce()
函数来计算整数列表的总和。
let sum = R.reduce((x, y) => x+y, 0, nums);
在这一行中,我们计算值的总和。 第一个参数是应用于值的函数。 第二个是累加器,它是起始值。 第三是包含值的列表。
let product = R.reduce((x, y) => x*y, 1, nums);
在这里,我们计算列表值的乘积。
$ node reducefun.js
27
5040
这是输出。
下面的示例计算表达式:1*2 + 3*4 + 5*6
。
reduce_fun2.js
const R = require('ramda');
let nums = [1, 2, 3, 4, 5, 6];
let ret = R.reduce((acc, x) => acc + x[0] * x[1], 0, R.splitEvery(2, nums));
console.log(ret);
在示例中,我们将列表分成几对,并对这些对应用归约操作。
$ node reduce_fun2.js
44
这是输出。
where()
函数
where()
函数允许在对象上创建复杂的查询。
wherefun.js
const R = require('ramda');
const moment = require('moment');
const users = [
{ name: 'John', city: 'London', born: '2001-04-01' },
{ name: 'Lenny', city: 'New York', born: '1997-12-11' },
{ name: 'Andrew', city: 'Boston', born: '1987-02-22' },
{ name: 'Peter', city: 'Prague', born: '1936-03-24' },
{ name: 'Anna', city: 'Bratislava', born: '1973-11-18' },
{ name: 'Albert', city: 'Bratislava', born: '1940-12-11' },
{ name: 'Adam', city: 'Trnava', born: '1983-12-01' },
{ name: 'Robert', city: 'Bratislava', born: '1935-05-15' },
{ name: 'Robert', city: 'Prague', born: '1998-03-14' }
];
let res1 = R.filter(R.where({ city: R.equals('Bratislava') }))(users);
console.log(res1);
let res2 = R.filter(R.where({
city: R.equals('Bratislava'),
name: R.startsWith('A')
}))(users);
console.log(res2);
let res3 = R.filter(R.where({
born: (dt) => getAge(dt) > 40}))(users);
console.log(res3);
function getAge(dt) {
return moment.duration(moment() - moment(dt, 'YYYY-MM-DD', true)).years();
}
在示例中,我们在用户列表上使用where()
创建查询。
let res1 = R.filter(R.where({ city: R.equals('Bratislava') }))(users);
在这里,我们找出居住在布拉迪斯拉发的所有用户。
let res2 = R.filter(R.where({
city: R.equals('Bratislava'),
name: R.startsWith('A')
}))(users);
在此代码中,我们找到了居住在布拉迪斯拉发的用户,其名称以"A"
开头。
let res3 = R.filter(R.where({
born: (dt) => getAge(dt) > 40}))(users);
最后,我们找出 40 岁以上的用户。
function getAge(dt) {
return moment.duration(moment() - moment(dt, 'YYYY-MM-DD', true)).years();
}
要从提供的出生日期算起年龄,我们使用矩模块。
$ node where_fun.js
[ { name: 'Anna', city: 'Bratislava', born: '1973-11-18' },
{ name: 'Albert', city: 'Bratislava', born: '1940-12-11' },
{ name: 'Robert', city: 'Bratislava', born: '1935-05-15' } ]
[ { name: 'Anna', city: 'Bratislava', born: '1973-11-18' },
{ name: 'Albert', city: 'Bratislava', born: '1940-12-11' } ]
[ { name: 'Peter', city: 'Prague', born: '1936-03-24' },
{ name: 'Anna', city: 'Bratislava', born: '1973-11-18' },
{ name: 'Albert', city: 'Bratislava', born: '1940-12-11' },
{ name: 'Robert', city: 'Bratislava', born: '1935-05-15' } ]
这是输出。
在本教程中,我们使用了Ramda
库。
您可能也会对以下相关教程感兴趣: Lodash 教程, Collect.js 教程, JavaScript 数组, Moment.js 教程 。
Lodash 教程
原文: http://zetcode.com/javascript/lodash/
Lodash 教程涵盖了 Lodash JavaScript 库。 在这个 Lodash 入门教程中,我们在多个示例中介绍 Lodash 函数。
Lodash
Lodash 是一个 JavaScript 库,为常见的编程任务提供工具函数。 它使用函数式编程范例。 Lodash 受Underscore.js
的启发。
Lodash 帮助程序员编写更简洁,更易于维护的 JavaScript 代码。 Lodash 包含一些工具,可简化使用字符串,数字,数组,函数和对象的编程。
按照惯例,Lodash 模块被映射到下划线字符。
Lodash 安装
首先,我们安装 Lodash 库。
$ npm init
$ npm i lodash
Lodash 库与npm
一起本地安装。
$ cat package.json
{
"name": "lodash-lib",
"version": "1.0.0",
"description": "",
"main": "lo_sample.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"lodash": "^4.17.11"
}
}
我们使用 Lodash 版本 4.17.11。
<script src="lodash.js"></script>
在浏览器内部,我们将库包含在<script>
标签中。
Lodash 版本
在第一个示例中,我们确定 Lodash 库的版本。
version.js
const _ = require("lodash")
const ver = _.VERSION
console.log(ver);
该示例打印 Lodash 库的版本。
const _ = require("lodash")
按照惯例,Lodash 库被映射到下划线字符。
const ver = _.VERSION
console.log(ver);
版本存储在VERSION
变量中。
$ node version.js
4.17.11
我们使用 Lodash 版本 4.17.5。
Lodash 第一个和最后一个数组元素
_.first()
/ _.head()
函数返回第一个数组元素; _.last()
函数返回最后一个数组元素。
first_last.js
const _ = require("lodash")
words = ['sky', 'wood', 'forest', 'falcon',
'pear', 'ocean', 'universe'];
let fel = _.first(words);
let lel = _.last(words);
console.log(`First element: ${fel}`);
console.log(`Last element: ${lel}`);
该示例输出单词数组的第一个和最后一个元素。
$ node first_last.js
First element: sky
Last element: universe
这是输出。
Lodash 分块数组
_.chunk()
函数创建一个元素数组,将指定长度的元素分成几组。
chunking.js
const _ = require("lodash")
nums = [1, 2, 3, 4, 5, 6, 7, 8, 9];
let c1 = _.chunk(nums, 2);
console.log(c1);
let c2 = _.chunk(nums, 3);
console.log(c2);
该示例将nums
数组分为两个和三个元素子数组的数组。
$ node chunking.js
[ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ], [ 7, 8 ], [ 9 ] ]
[ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ] ]
这是输出。
获取数组切片
_.slice()
方法从数组获取切片。 它有两个索引:开始索引和结束索引,其中开始索引是包含端点的,结束索引是互斥的。
slice_fun.js
const _ = require("lodash")
nums = [1, 2, 3, 4, 5, 6, 7, 8, 9];
let c1 = _.slice(nums, 2, 6);
console.log(c1);
let c2 = _.slice(nums, 0, 8);
console.log(c2);
该示例从nums
数组创建两个切片。
$ node slice_fun.js
[ 3, 4, 5, 6 ]
[ 1, 2, 3, 4, 5, 6, 7, 8 ]
这是输出。
Lodash 随机数
_.random()
函数在上下限之间产生随机值。
random_vals.js
const _ = require("lodash")
var r = _.random(10);
console.log(r);
r = _.random(5, 10);
console.log(r);
该示例打印两个随机值。
var r = _.random(10);
我们产生 0 到 10 之间的随机值。
r = _.random(5, 10);
在这里,我们产生 5 到 10 之间的随机值。
Lodash 随机数组元素
使用_.sample()
函数,我们可以从数组中选择随机元素。
sample_fun.js
const _ = require("lodash")
words = ['sky', 'wood', 'forest', 'falcon',
'pear', 'ocean', 'universe'];
let word = _.sample(words);
console.log(word);
该示例使用_.sample()
从数组中选择一个随机单词。
$ node sample_fun.js
falcon
这是一个示例输出。
Lodash 改组数组元素
_.shuffle()
函数可对集合进行混洗。
shuffle_fun.js
const _ = require("lodash")
words = ['sky', 'wood', 'forest', 'falcon',
'pear', 'ocean', 'universe'];
console.log(_.shuffle(words));
console.log(_.shuffle(words));
console.log(_.shuffle(words));
console.log(words);
该示例从初始单词数组创建三个新的随机重组的数组。
$ node shuffle_fun.js
[ 'sky', 'ocean', 'universe', 'falcon', 'pear', 'wood', 'forest' ]
[ 'wood', 'ocean', 'falcon', 'forest', 'sky', 'universe', 'pear' ]
[ 'forest', 'ocean', 'sky', 'wood', 'falcon', 'universe', 'pear' ]
[ 'sky', 'wood', 'forest', 'falcon', 'pear', 'ocean', 'universe' ]
这是输出。 原始数组未修改; _.shuffle()
函数创建一个新数组。
Lodash _.times
函数
_.times()
执行该函数 n 次。
times_fun.js
const _ = require("lodash");
_.times(4, () => {
console.log("brave");
})
在示例中,我们执行了内部函数四次。 该函数将单词打印到控制台。
$ node times_fun.js
brave
brave
brave
brave
这是输出。
Lodash _.delay
函数
_.delay()
函数将函数的执行延迟指定的毫秒数。
delay_fun.js
const _ = require("lodash")
function message()
{
console.log("Some message");
}
_.delay(message, 150);
console.log("Some other message");
该示例输出两个消息。 第一个延迟 150ms。
$ node delay_fun.js
Some other message
Some message
这是输出。
Lodash 确定数据类型
Lodash 包含确定值的数据类型的函数。
datatype.js
const _ = require("lodash");
const vals = [1, 2, 'good', [1, 2], {name: 'Peter', age: 32}];
vals.forEach( (e) => {
if (_.isNumber(e)) {
console.log(`${e} is a number`);
}
if (_.isString(e)) {
console.log(JSON.stringify(e) + ' is a string');
}
if (_.isArray(e)) {
console.log(JSON.stringify(e) + ' is an array');
}
if (_.isObject(e)) {
console.log(JSON.stringify(e) + ' is an object');
}
});
在示例中,我们确定数组元素的数据类型。
const vals = [1, 2, 'good', [1, 2], {name: 'Peter', age: 32}];
我们有一个值数组,包括数字,字符串,数组和对象。
if (_.isNumber(e)) {
console.log(`${e} is a number`);
}
_.isNumber()
函数检查值是否为数字。
if (_.isString(e)) {
console.log(JSON.stringify(e) + ' is a string');
}
_.isString()
函数检查值是否为字符串。
if (_.isArray(e)) {
console.log(JSON.stringify(e) + ' is an array');
}
_.isArray()
函数检查值是否为数组。
if (_.isObject(e)) {
console.log(JSON.stringify(e) + ' is an object');
}
_.isObject()
函数检查值是否为对象。
$ node index.js
1 is a number
2 is a number
"good" is a string
[1,2] is an array
[1,2] is an object
{"name":"Peter","age":32} is an object
这是程序的输出。
Lodash _.range
函数
Lodash _.range()
函数创建一个数字数组。 该函数接受start
,end
和step
参数。
range_fun.js
const _ = require("lodash");
const vals = _.range(10);
console.log(vals);
const vals2 = _.range(0, 15);
console.log(vals2);
const vals3 = _.range(0, 15, 5);
console.log(vals3);
在代码示例中,我们创建了三个值范围。
const vals = _.range(10);
该行创建一个值0..9
的数组。 end
值是必需的,start
和step
是可选的。 end
不包含在内; 因此,不包括值 10。
const vals2 = _.range(0, 15);
在这里,我们指定start
和step
参数。 我们创建一个值数组0..14
。
const vals3 = _.range(0, 15, 5);
最后,我们提供所有三个参数。 将创建一个包含 0、5 和 10 个值的数组。
$ node range_fun.js
[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 ]
[ 0, 5, 10 ]
这是输出。
Lodash 最大值和最小值
Lodash 允许计算数组的最大值和最小值。
min_max.js
const _ = require("lodash");
const vals = [-3, 4, 0, 12, 43, 9, -12];
var min = _.min(vals);
console.log(min);
var max = _.max(vals);
console.log(max);
max = _.max(_.range(5, 25));
console.log(max);
const obs = [{n: 12}, {n: -4}, {n: 4}, {n: -11}];
min = _.minBy(obs, 'n');
console.log(min);
max = _.maxBy(obs, 'n');
console.log(max);
该示例计算数组的最小值和最大值。
var min = _.min(vals);
console.log(min);
_.min()
函数返回数组的最小值。
var max = _.max(vals);
console.log(max);
._max()
函数返回数组的最大值。
min = _.minBy(obs, 'n');
console.log(min);
max = _.maxBy(obs, 'n');
console.log(max);
要计算对象属性的最小和最大值,我们使用_.minBy()
和.maxBy()
函数。
$ node min_max.js
-12
43
24
{ n: -11 }
{ n: 12 }
这是输出。
Lodash _.sum
函数
_.sum()
函数计算数组值的总和。
sum_fun.js
const _ = require("lodash");
const vals = [-2, 0, 3, 7, -5, 1, 2];
const sum = _.sum(vals);
console.log(sum);
在代码示例中,我们计算并打印数组值的总和。
$ node sum_fun.js
6
这是输出。
Lodash 集合过滤器
_.filter()
函数返回其谓词函数返回true
的元素数组。
col_filter.js
const _ = require("lodash");
const nums = [4, -5, 3, 2, -1, 7, -6, 8, 9];
const pos_nums = _.filter(nums, (e) => e > 0);
console.log(pos_nums);
在代码示例中,我们过滤掉数组的正值。
const pos_nums = _.filter(nums, (e) => e > 0);
谓词是一个返回布尔值的函数。 在我们的例子中,我们有一个匿名函数,该函数对于大于 0 的值返回true
。
$ node col_filter.js
[ 4, 3, 2, 7, 8, 9 ]
这是输出。
Lodash 集合分区
分区操作将原始集合拆分为一对数组。 第一个数组包含其指定谓词产生true
的元素,而第二个列表包含其谓词产生false
的元素。
col_partition.js
const _ = require("lodash");
const nums = [4, -5, 3, 2, -1, 7, -6, 8, 9];
const [nums2, nums3] = _.partition(nums, (e) => e < 0);
console.log(nums2);
console.log(nums3);
使用_.partition()
函数,我们将数组分为两个数组; 第一个包含正值,第二个包含负值。
const [nums2, nums3] = _.partition(nums, (e) => e < 0);
_.partition()
函数根据谓词函数创建两个数组。 通过数组解构操作,我们将创建的数组分配给两个变量:nums2
和nums3
。
$ node col_partition.js
[ -5, -1, -6 ]
[ 4, 3, 2, 7, 8, 9 ]
这是输出。
Lodash 集合归约
归约是将列表值聚合为单个值的终端操作。 _.reduce()
函数对累加器和数组中的每个元素(从左到右)应用一个函数,以将其减小为单个值。
col_reduce.js
const _ = require("lodash");
const nums = [4, 5, 3, 2, 1, 7, 6, 8, 9];
const sum = _.reduce(nums, (total, next) => { return total + next });
console.log(sum);
const colours = ["red", "green", "white", "blue", "black"];
const res = _.reduceRight(colours, (next, total) => { return `${total}-${next}` });
console.log(res);
在示例中,我们对整数和字符串列表使用归约操作。
const sum = _.reduce(nums, (total, next) => { return total + next });
console.log(sum);
我们计算值的总和。 total
是累加器,next
是列表中的下一个值。
const res = _.reduceRight(colours, (next, total) => { return `${total}-${next}` });
_.reduceRight()
累加一个从最后一个元素开始的值,并将从右到左的操作应用于每个元素和当前累加器值。
$ node col_reduce.js
45
red-green-white-blue-black
这是输出。
Lodash 字符串大小写
Locash 库包含几个针对单词大小写的函数。
string_case.js
const _ = require("lodash");
const words = ["sky", "Sun", "Blue Island"];
console.log(_.map(words, _.camelCase));
console.log(_.map(words, _.capitalize));
console.log(_.map(words, _.kebabCase));
console.log(_.map(words, _.lowerCase));
console.log(_.map(words, _.upperCase));
在示例中,我们用_.camelCase()
,_.capitalize()
,._kebabCase()
,_lowerCase()
和_.upperCase()
修改单词的大小写。
$ node string_case.js
[ 'sky', 'sun', 'blueIsland' ]
[ 'Sky', 'Sun', 'Blue island' ]
[ 'sky', 'sun', 'blue-island' ]
[ 'sky', 'sun', 'blue island' ]
[ 'SKY', 'SUN', 'BLUE ISLAND' ]
这是输出。
Lodash 字符串_.startsWith
和_.endsWith
_.startsWith()
函数确定字符串是否以指定的字符串开头。 _.endsWith()
函数确定字符串是否以指定的字符串结尾。
string_startend.js
const _ = require("lodash");
const words = ["tank", "boy", "tourist", "ten",
"pen", "car", "marble", "sonnet", "pleasant",
"ink", "atom"]
console.log("Starting with 't'");
words.forEach( e => {
if (_.startsWith(e, 't')) {
console.log(e);
}
});
console.log("Ending with 'k'");
words.forEach( e => {
if (_.endsWith(e, 'k')) {
console.log(e);
}
});
在示例中,我们打印以"t"
开头和以"k"
结尾的单词。
$ nodejs string_startend.js
Starting with 't'
tank
tourist
ten
Ending with 'k'
tank
ink
这是输出。
Lodash 字符串填充
如果字符串小于指定的数字,则可以用字符填充字符串。
string_pad.js
const _ = require("lodash");
const nums = [657, 122, 3245, 345, 99, 18];
nums.forEach( e => {
console.log(_.padStart(e.toString(), 20, '.'));
});
该示例使用_.padStart()
将数字用点字符填充。
$ node string_pad.js
.................657
.................122
................3245
.................345
..................99
..................18
这是输出。
Lodash 对象键和值
_.keys()
函数返回 JavaScript 对象的属性名称的数组,_.values()
函数返回其值的数组。
keys_values.js
const _ = require("lodash");
const p = {age: 24, name: "Rebecca", occupation: "teacher"};
const keys = _.keys(p);
console.log(keys);
const values = _.values(p);
console.log(values);
在示例中,我们打印人员对象的键和值。
$ node keys_values.js
[ 'age', 'name', 'occupation' ]
[ 24, 'Rebecca', 'teacher' ]
这是输出。
Lodash 迭代对象属性
_.forIn()
函数可用于遍历对象属性。
iter_object_props.js
const _ = require("lodash");
const p = {age: 24, name: "Rebecca", occupation: "teacher"};
_.forIn(p, (value, key) => {
console.log(`${key}: ${value}`);
})
在示例中,我们使用_.forIn()
遍历人员对象的属性。
$ node iter_object_props.js
age: 24
name: Rebecca
occupation: teacher
这是输出。
在本教程中,我们介绍了 Lodash JavaScript 库。
您可能也对以下相关教程感兴趣: Ramda 教程, Collect.js 教程, JSON 服务器教程, Moment.js 教程,从 JavaScript 中的 URL 读取 JSON , JavaScript 贪食蛇教程, JQuery 教程, jQuery 自动完成教程或使用 jQuery DatePicker
。
Collect.js 教程
原文: http://zetcode.com/javascript/collectjs/
Collect.js 教程展示了如何使用 Collect.js 库处理 JavaScript 中的数组和对象。
Collect.js
Collect.js 是用于处理数组和对象的流畅,便捷的包装器。 它是 Laravel 集合的接口。 它包含许多使数据处理更加容易的函数。
Collect.js 帮助程序员编写更简洁,更易于维护的 JavaScript 代码。
Collect.js 安装
首先,我们安装 Collect.js 库。
$ npm init
$ npm i collect.js
collect.js
库与npm
一起本地安装。
collect()
函数
我们将带有collect()
的 JavaScript 数组转换为一个集合,并对该集合应用函数。 最后,我们使用all()
或toArray()
返回底层数组。
Collect.js all()
与toArray
all()
和toArray()
函数从集合中返回基础数组。 这两个函数之间的区别在于toArray()
函数还将嵌套的集合转换为数组(如果存在)。
all_toarray.js
const collect = require('collect.js');
const nums1 = [1, 2, 3];
const nums2 = [4, 5, 6];
const data = collect([collect(nums1),
collect(nums2)]);
console.log(data.all());
console.log(data.toArray());
该示例显示了两个函数之间的区别。
$ node all_toarray.js
[ Collection { items: [ 1, 2, 3 ] },
Collection { items: [ 4, 5, 6 ] } ]
[ [ 1, 2, 3 ], [ 4, 5, 6 ] ]
这是输出。 我们可以看到在第二个示例中,嵌套集合被转换为数组。
Collect.js count()
count()
函数计算集合中元素的数量。
count_elements.js
const collect = require('collect.js');
const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const data = collect(nums);
const nOfElements = data.count();
console.log(`There are ${nOfElements} elements`);
该示例计算数组中值的数量。
$ node count_elements.js
Therea are 10 elements
Collect.js unique()
unique()
函数返回集合中的所有唯一项。
unique.js
const collect = require('collect.js');
const nums = [1, 1, 1, 2, 4, 4, 5];
const data = collect(nums);
const unique_data = data.unique();
console.log(unique_data.all());
该示例显示数组的唯一值。
const unique_data = data.unique();
我们使用unique()
从集合中获取所有唯一值。
console.log(unique_data.all());
all()
函数返回该集合表示的基础数组。
$ node unique.js
[ 1, 2, 4, 5 ]
这是输出。
first
第一个函数返回通过给定真值测试的集合中的第一个元素,或者仅返回第一个值。
first_fun.js
const collect = require('collect.js');
const nums = [1, 2, -3, 4, -5, 6, 7, 8];
const data = collect(nums);
let fval = data.first();
console.log(fval);
let fneg = data.first(e => e < 0);
console.log(fneg);
该示例打印第一个值和第一个负值。
$ node first_fun.js
1
-3
这是输出。
firstWhere
firstWhere
函数返回具有给定键/值对的集合中的第一个元素。
firstwhere_fun.js
const collect = require('collect.js');
const users = [
{ name: 'John', city: 'London', born: '2001-04-01' },
{ name: 'Lenny', city: 'New York', born: '1997-12-11' },
{ name: 'Andrew', city: 'Boston', born: '1987-02-22' },
{ name: 'Peter', city: 'Prague', born: '1936-03-24' },
{ name: 'Anna', city: 'Bratislava', born: '1973-11-18' },
{ name: 'Albert', city: 'Bratislava', born: '1940-12-11' },
{ name: 'Adam', city: 'Trnava', born: '1983-12-01' },
{ name: 'Robert', city: 'Bratislava', born: '1935-05-15' },
{ name: 'Robert', city: 'Prague', born: '1998-03-14' }
];
const data = collect(users);
let fval = data.firstWhere('city', 'Bratislava');
console.log(fval);
该示例打印出居住在布拉迪斯拉发的第一位用户。
$ node firstwhere_fun.js
{ name: 'Anna', city: 'Bratislava', born: '1973-11-18' }
这是输出。
Collect.js avg()
avg()
函数返回集合中所有项目的平均值。
average.js
const collect = require('collect.js');
const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const data = collect(nums);
console.log(data.avg());
该程序将打印数字数组的平均值。
min
和max()
min
和max()
函数分别返回最小值和最大值。
min_max.js
const collect = require('collect.js');
const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const data = collect(nums);
console.log(`Minimum: ${data.min()}`);
console.log(`Maximum: ${data.max()}`);
程序打印数字数组的最小值和最大值。
$ node min_max.js
Minimum: 1
Maximum: 10
这是输出。
Collect.js median
median()
函数返回中位数。 中位数是数据集的中间值。
median_fun.js
const collect = require('collect.js');
const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const data = collect(nums);
console.log(data.median());
该示例显示数字数组的中位数。
$ node median.js
5.5
如果没有中间值,则按照我们的情况计算中间两个值的平均值。
Collect.js each
each()
函数遍历集合中的项目,并将每个项目传递给回调。
each_fun.js
const collect = require('collect.js');
const nums = [1, 2, 3, 4, 5];
let sum = 0;
const data = collect(nums);
data.each((item) => {
sum += item;
});
console.log(`The sum of values: ${sum}`);
我们使用each()
函数计算值的总和。
$ node each_fun.js
The sum of values: 15
这是输出。
Collect.js eachSpread
eachSpread()
函数遍历集合的项目,将每个嵌套的项目值传递给给定的回调。
eachspread_fun.js
const collect = require('collect.js');
const users = [
['John Doe', 'gardener'], ['Peter Smith', 'programmer'],
['Lucy Black', 'teacher']
];
const data = collect(users);
data.eachSpread((user, occupation) => {
console.log(`${user} is a ${occupation}`);
});
该示例使用eachSpread()
函数对嵌套数组进行迭代。
$ node eachspread_fun.js
John Doe is a gardener
Peter Smith is a programmer
Lucy Black is a teacher
这是输出。
Collect.js map()
map()
函数将给定的回调函数应用于每个元素,从而形成新的修改项集合。
map_fun.js
const collect = require('collect.js');
const nums = [1, 2, 3, 4, 5];
const data = collect(nums);
const tr_data = data.map(e => e * 2);
console.log(tr_data.all());
在示例中,我们通过将每个值乘以 2 来创建修改后的集合。
$ node map_fun.js
[ 2, 4, 6, 8, 10 ]
这是输出。
Collect.js mapInto
mapInto()
函数遍历集合并根据元素创建对象。
mapinto_fun.js
const collect = require('collect.js');
const User = function (name, age) {
this.name = name;
this.age = age;
};
const users = [
{ name: 'John Doe', age: 34 },
{ name: 'Peter Smith', age: 43 },
{ name: 'Bruce Long', age: 40 },
{ name: 'Lucy White', age: 54 },
];
const data = collect(users);
const objects = data.mapInto(User);
console.log(objects.all());
在示例中,我们借助mapInto()
函数将 JSON 对象文字转换为 JavaScript 对象。
$ node mapinto_fun.js
[ User { name: { name: 'John Doe', age: 34 }, age: 0 },
User { name: { name: 'Peter Smith', age: 43 }, age: 1 },
User { name: { name: 'Bruce Long', age: 40 }, age: 2 },
User { name: { name: 'Lucy White', age: 54 }, age: 3 } ]
这是输出。
Collect.js filter()
filter()
函数使用给定的回调函数过滤集合,仅保留那些通过给定的真实性测试的项目。
finter_fun.js
const collect = require('collect.js');
const nums = [-1, 2, -3, 4, -5, 6, 7, 8, -9, 0];
const data = collect(nums);
const filtered = data.filter((val, key) => val > 0);
console.log(filtered.all());
该示例滤除正值。
$ node finter_fun.js
[ 2, 4, 6, 7, 8 ]
这是输出。
$ npm i moment
在下面的示例中,我们还需要moment.js
库。
filter_fun2.js
const collect = require('collect.js');
const moment = require('moment');
const users = [
{ name: 'John', city: 'London', born: '2001-04-01' },
{ name: 'Lenny', city: 'New York', born: '1997-12-11' },
{ name: 'Andrew', city: 'Boston', born: '1987-02-22' },
{ name: 'Peter', city: 'Prague', born: '1936-03-24' },
{ name: 'Anna', city: 'Bratislava', born: '1973-11-18' },
{ name: 'Albert', city: 'Bratislava', born: '1940-12-11' },
{ name: 'Adam', city: 'Trnava', born: '1983-12-01' },
{ name: 'Robert', city: 'Bratislava', born: '1935-05-15' },
{ name: 'Robert', city: 'Prague', born: '1998-03-14' }
];
const data = collect(users);
let res = data.filter((val, key) => getAge(val.born) > 40);
console.log(res.all());
function getAge(dt) {
return moment.duration(moment() - moment(dt, 'YYYY-MM-DD', true)).years();
}
该示例过滤出年龄超过 40 岁的用户。
$ node filter_fun2.js
[ { name: 'Peter', city: 'Prague', born: '1936-03-24' },
{ name: 'Anna', city: 'Bratislava', born: '1973-11-18' },
{ name: 'Albert', city: 'Bratislava', born: '1940-12-11' },
{ name: 'Robert', city: 'Bratislava', born: '1935-05-15' } ]
列表中有四个人大于四十岁。
Collect.js shuffle()
shuffle()
函数随机重组集合中的项目。
shuffle.js
const collect = require('collect.js');
const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const data = collect(nums);
const shuffled = data.shuffle();
console.log(shuffled.all());
该示例重新排列数组。
$ node shuffling.js
[ 6, 4, 3, 7, 5, 10, 1, 9, 8, 2 ]
这是一个示例输出。
Collect.js random()
random()
函数从集合中返回一个随机元素。
random_fun.js
const collect = require('collect.js');
let nums = [1, 2, 3, 4, 5, 6, 7, 8];
const data = collect(nums);
let r1 = data.random();
console.log(r1);
let r2 = data.random(2);
console.log(r2.all());
该示例从一个数字数组中选择一个随机值和两个随机值。
$ node random_fun.js
6
[ 4, 2 ]
这是输出。
Collect.js sortBy()
sortBy()
函数通过给定的键对集合进行排序。
sortby_fun.js
const collect = require('collect.js');
const users = [
{ name: 'John Doe', occupation: 'gardener' },
{ name: 'Adam Forsythe', occupation: 'writer' },
{ name: 'Peter Smith', occupation: 'programmer' },
{ name: 'Lucy Black', occupation: 'teacher' }
];
const data = collect(users);
const sorted1 = data.sortBy('name');
console.log(sorted1.all());
const sorted2 = data.sortBy('occupation');
console.log(sorted2.all());
该程序通过提供的键对对象数组进行排序。
$ node sortby_fun.js
[ { name: 'Adam Forsythe', occupation: 'writer' },
{ name: 'John Doe', occupation: 'gardener' },
{ name: 'Lucy Black', occupation: 'teacher' },
{ name: 'Peter Smith', occupation: 'programmer' } ]
[ { name: 'John Doe', occupation: 'gardener' },
{ name: 'Peter Smith', occupation: 'programmer' },
{ name: 'Lucy Black', occupation: 'teacher' },
{ name: 'Adam Forsythe', occupation: 'writer' } ]
数组通过name
和occupation
键排序。
nth()
nth()
函数返回集合中的每个第 n 个元素。
nth_fun.js
const collect = require('collect.js');
const nums = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
const data = collect(nums);
console.log(data.nth(2).all());
console.log(data.nth(3).all());
console.log(data.nth(4).all());
该示例返回数组的第二,第三和第四个元素。
$ node nth_fun.js
[ 'a', 'c', 'e', 'g' ]
[ 'a', 'd', 'g' ]
[ 'a', 'e' ]
这是输出。
Collect.js chunk()
chunk()
函数将集合分成给定大小的较小部分。
chunk_fun.js
const collect = require('collect.js');
const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const data = collect(nums);
const chunks = data.chunk(4);
console.log(chunks.toArray());
该示例将数组分为包含四个元素的部分。
$ node chunk_fun.js
[ [ 1, 2, 3, 4 ], [ 5, 6, 7, 8 ], [ 9, 10 ] ]
这是输出。
node flatten_fun.js
[ 4, 5, 6, 7, 8, 9, 10 ]
这是输出。
Collect.js dif()
dif()
函数将一个集合与另一个集合进行比较。 它从原始集合中返回第二个集合中不存在的值。
diff_fun.js
const collect = require('collect.js');
const nums = [1, 2, 3, 4];
const nums2 = [3, 4, 5, 6];
const data = collect(nums);
const data2 = collect(nums2);
const difference = data.diff(data2);
console.log(difference.all());
该示例返回两个数组之间的差。
$ node diff_fun.js
[ 1, 2 ]
这是输出。
Collect.js partition()
partition()
函数将集合的元素分为两部分:通过给定条件的元素和不通过给定条件的元素。
partition_fun.js
const collect = require('collect.js');
const nums = [-1, 2, 3, -4, 5, 7, -2];
const data = collect(nums);
const [positive, negative] = data.partition(e => {
return e < 0 && e != 0;
});
console.log(positive.all());
console.log(negative.all());
该示例使用partition
函数将正值与负值分开。
$ node partition_fun.js
[ -1, -4, -2 ]
[ 2, 3, 5, 7 ]
这是输出。
Collect.js pluck()
pluck()
函数检索给定键的所有值。
pluck_fun.js
const collect = require('collect.js');
const users = [
{ name: 'John', city: 'London', born: '2001-04-01' },
{ name: 'Lenny', city: 'New York', born: '1997-12-11' },
{ name: 'Andrew', city: 'Boston', born: '1987-02-22' },
{ name: 'Peter', city: 'Prague', born: '1936-03-24' },
{ name: 'Anna', city: 'Bratislava', born: '1973-11-18' },
{ name: 'Albert', city: 'Bratislava', born: '1940-12-11' },
{ name: 'Adam', city: 'Trnava', born: '1983-12-01' },
{ name: 'Robert', city: 'Bratislava', born: '1935-05-15' },
{ name: 'Robert', city: 'Prague', born: '1998-03-14' }
];
let data = collect(users);
let names = data.pluck('name');
console.log(names.all());
let cities = data.pluck('city');
console.log(cities.all());
该示例从users
对象的数组中打印所有名称和城市。 由于名称和城市在重复,因此我们使用unique()
使其具有唯一性。
$ node pluck_fun.js
[ 'John',
'Lenny',
'Andrew',
'Peter',
'Anna',
'Albert',
'Adam',
'Robert' ]
[ 'London', 'New York', 'Boston', 'Prague', 'Bratislava', 'Trnava' ]
这是输出。
Collect.js implode()
implode()
函数通过给定字符将集合的元素连接在一起。
implode_fun.js
const collect = require('collect.js');
const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const data = collect(nums);
let output = data.implode('-');
console.log(output);
该示例使用'-'字符连接元素。
当我们处理对象时,我们需要指定用于连接元素的键。
implode_fun2.js
const collect = require('collect.js');
const users = [
{ name: 'John Doe', occupation: 'gardener' },
{ name: 'Adam Forsythe', occupation: 'writer' },
{ name: 'Peter Smith', occupation: 'programmer' },
{ name: 'Lucy Black', occupation: 'teacher' }
];
const data = collect(users);
let output = data.implode('name', ',');
console.log(output);
该示例将对象users
数组中的名称连接在一起。
$ node implode_fun2.js
John Doe,Adam Forsythe,Peter Smith,Lucy Black
这是输出。
Collect.js reduce
reduce
函数将集合减小为单个值,将每次迭代的结果传递到后续迭代中。 该函数的第一个参数是累加器或进位,第二个参数是当前元素。
reduce_fun.js
const collect = require('collect.js');
const nums = [1, 2, 3, 4, 5, 6];
const data = collect(nums);
const val = data.reduce((c, e) => { return e += c });
console.log(val);
const val2 = data.chunk(2).reduce((c, e) => {
return c + e.get(0) * e.get(1)
}, 0);
console.log(val2);
该程序使用reduce()
函数来计算总和和值乘积之和。
const val2 = data.chunk(2).reduce((c, e) => {
return c + e.get(0) * e.get(1)
}, 0);
借助chunk()
函数,我们计算对的乘积之和:1 * 2 + 3 * 4 + 5 * 6
。
$ node reduce_fun.js
21
44
这是输出。
Collect.js tap
tap
函数将集合传递给给定的回调,使我们可以在特定点挂接到集合中,并在不影响集合本身的情况下对项目执行某些操作。
tap_fun.js
const collect = require('collect.js');
const nums = [1, 3, 2, 6, 5, 4];
const data = collect(nums);
const val = data.sort()
.tap((col) => console.log(col.all()))
.chunk(2)
.tap((col) => console.log(col.toArray()))
.reduce((c, e) => c + e.get(0) * e.get(1));
console.log(val);
该示例对集合进行排序,将其分块并最终缩小它。 在此过程中,我们会挂接操作以查看结果。
$ node tap_fun.js
[ 1, 2, 3, 4, 5, 6 ]
[ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ] ]
44
这是输出。
every
every
函数验证集合中的所有元素均通过给定的真实性测试。
every_fun.js
const collect = require('collect.js');
const words = ['forest', 'wood', 'sky', 'cloud'];
const data = collect(words);
if (data.every(e => e.length > 2)){
console.log('Each word has more than 2 letters');
} else {
console.log('There is at least one word that does not have more than 2 letters');
}
该程序将验证集合中的每个单词是否包含两个以上的字符。
$ node every_fun.js
Each word has more than 2 letters
该集合通过了真相测试。
Collect.js groupBy()
groupBy()
函数通过给定的键对集合的项目进行分组。
groupby_fun.js
const collect = require('collect.js');
const users = [
{ name: 'John', city: 'London', born: '2001-04-01' },
{ name: 'Lenny', city: 'New York', born: '1997-12-11' },
{ name: 'Andrew', city: 'Boston', born: '1987-02-22' },
{ name: 'Peter', city: 'Prague', born: '1936-03-24' },
{ name: 'Anna', city: 'Bratislava', born: '1973-11-18' },
{ name: 'Albert', city: 'Bratislava', born: '1940-12-11' },
{ name: 'Adam', city: 'Trnava', born: '1983-12-01' },
{ name: 'Robert', city: 'Bratislava', born: '1935-05-15' },
{ name: 'Robert', city: 'Prague', born: '1998-03-14' }
];
const data = collect(users);
let cityGroups = data.groupBy('city');
cityGroups.each((group, city) => {
console.log(city);
group.each(e => {
let { name, city, born } = e;
console.log(`${name} ${born}`);
});
});
该示例按城市对用户进行分组。
$ node groupby_fun.js
London
John 2001-04-01
New York
Lenny 1997-12-11
Boston
Andrew 1987-02-22
Prague
Peter 1936-03-24
Robert 1998-03-14
Bratislava
Anna 1973-11-18
Albert 1940-12-11
Robert 1935-05-15
Trnava
Adam 1983-12-01
这是输出。
在本教程中,我们介绍了 Collect.js JavaScript 库。
您可能也对以下相关教程感兴趣: Ramda 教程, JSON 服务器教程, Moment.js 教程, Lodash 教程。
Node.js 简介
原文: http://zetcode.com/javascript/nodejs/
Node.js 教程是 Node.js 的入门教程。 我们描述 Node.js 并提供一些 Node.js 代码示例。
Nojde.js
Node.js 是一个开源,跨平台的 JavaScript 运行时环境。 它基于 Chrome 的 V8 JavaScript 引擎构建。 Node.js 使用事件驱动的非阻塞 I / O 模型,从而使其轻巧高效。 Node.js 最初由 Ryan Dahl 在 2009 年编写。
Node.js 提供了各种 JavaScript 模块的丰富库,例如用于文件系统的fs
或用于 HTTP 请求和响应的http
。
Node.js 应用是用 JavaScript 编写的,可以在 OS X,Microsoft Windows 和 Linux 上的 Node.js 运行时中运行。
Node.js 有一个名为npm
的包管理器,它是一个庞大的开源 JavaScript 库生态系统。
Node.js 安装
我们安装了最新版本的 Node.js。 Node.js 版本 9 实现了大多数 ECMAScript 6 规范。 请遵循适用于您平台的 Node.js 网站上提供的安装说明。
$ curl -sL https://deb.nodesource.com/setup_9.x | sudo -E bash -
$ sudo apt-get install -y nodejs
这就是我们在 Debian Linux 上安装 Node.js 的方式。
$ nodejs -v
v9.11.1
我们显示 Node.js 的版本。
Node.js 第一个示例
我们创建一个简单的控制台应用。
first.js
console.log("This is our first application");
该程序将消息打印到控制台。
$ node first.js
This is our first application
这是输出。
Node.js 读取文件内容
Node.js 包含用于处理文件的fs
模块。
words.txt
blue
book
pen
dog
computer
screen
我们有一个文本文件。
Node.js 中的大多数函数都是异步的。 是非阻塞的; 也就是说,它们不会阻止脚本的执行。
read_file.js
const fs = require('fs')
fs.readFile('words.txt', 'utf-8', (err, data) => {
if (err) throw err;
console.log(data);
});
console.log("Script continues...")
该示例读取words.txt
文件的内容。
const fs = require('fs');
我们加载fs
模块。
fs.readFile('words.txt', 'utf-8', (err, data) => {
readFile()
异步读取文件的全部内容。 我们在方法的第二个参数中指定编码。
$ node read_file.js
Script continues
blue
book
pen
dog
computer
screen
这是输出。 文件内容之前显示"Script continues"
。
Node.js 同步读取目录
现在,我们将读取目录的内容。
readdir_syn.js
const fs = require('fs');
readDirContentSync('.');
console.log("Ready.");
function readDirContentSync(mydir) {
const filenames = fs.readdirSync(mydir);
for (var i = 0; i < filenames.length; i++) {
console.log(filenames[i]);
}
}
该代码示例同步读取目录的内容。
const filenames = fs.readdirSync(mydir);
我们与readdirSync()
同步读取目录。
for (var i = 0; i < filenames.length; i++) {
console.log(filenames[i]);
}
我们遍历文件名数组,并将它们打印到控制台。
$ node readdir_syn.js
builtins.js
first.js
links
read_file.js
readdir_asyn.js
readdir_syn.js
server.js
todo
words.txt
Ready.
通过同步函数调用,"Ready."
。 函数完成执行后,显示消息。
Node.js 异步读取目录
在下一个示例中,我们异步读取目录。
readdir_async.js
var fs = require('fs');
fs.readdir(".", (err, filenames) => {
for (var i = 0; i < filenames.length; i++) {
console.log(filenames[i]);
}
console.log("Ready.");
});
readdir()
异步读取当前工作目录的内容。 它用目录中文件的名称(不包括.
和..
)填充数组。
Node.js 读取网页
在下面的示例中,我们使用内置的http
模块读取网页。
read_page.js
const http = require('http');
const request = http.request({ hostname: 'www.something.com' }, (res) => {
res.setEncoding('utf8');
res.on('data', (chunk) => {
console.log(chunk);
});
});
request.end();
request.on('error', (err) => {
console.log("Error occured\n");
console.error(err);
});
在示例中,我们使用http
模块创建对小型网页的请求。 返回的 HTML 页面将打印到控制台。
$ node read_site.js
<html><head><title>Something.</title></head>
<body>Something.</body>
</html>
我们已经收到了这个小的 HTML 页面。
使用npm
安装 Node.js 模块
可以使用npm
(节点包管理器)安装其他模块。 现在,我们将安装一个名为builtin-modules
的新模块。 通过此模块,我们将列出所有可用的 Node.js 内置模块。
$ mkdir builtmodtest
$ cd builtmodtest/
$ npm init
我们创建一个新的项目目录。 使用npm init
命令创建一个package.json
文件。 它包含与项目相关的元数据,例如应用名称,作者或依赖项。
$ cat package.json
{
"name": "builtmodtest",
"version": "1.0.0",
"description": "Testing builtin modules",
"main": "main.js",
"scripts": {
"start": "node main.js"
},
"author": "Jan Bodnar",
"license": "ISC"
}
这是初始的package.json
文件。 我们选择了main.js
作为主文件。
$ npm install builtin-modules
$ tree -L 1
.
├── main.js
├── node_modules
├── package.json
└── package-lock.json
使用npm install builtin-modules
,我们可以在本地安装builtin-modules
模块。 创建一个新的node_modules
目录,在其中存储模块及其依赖项。 npm 自动创建了一个package-lock.json
文件。 它用于确保队友,部署和持续集成的依赖项安装的一致性。 该文件必须提交到源存储库。
$ cat package.json
{
"name": "builtmodtest",
"version": "1.0.0",
"description": "Testing builtin modules",
"main": "main.js",
"scripts": {
"start": "node main.js"
},
"author": "Jan Bodnar",
"license": "ISC",
"dependencies": {
"builtin-modules": "^2.0.0"
}
}
builtin-modules
也被写入package.json
文件。
main.js
const builtmods = require('builtin-modules');
console.log(builtmods);
这是main.js
文件。 它将所有内置模块打印到控制台。
$ npm start
> builtmod@1.0.0 start /home/janbodnar/prog/nodejs/builtmod
> node main.js
[ 'assert',
'async_hooks',
'buffer',
'child_process',
'cluster',
'config',
'console',
'constants',
...
]
这是程序的输出。
Node.js 服务器
我们使用 Node.js http
模块创建一个简单的服务器。
server.js
const http = require('http');
const server = http.createServer((req, res) => {
res.writeHead(200, {"Content-Type": "text/plain"});
res.end("Hello there\n");
});
server.listen(8000);
console.log("Server running at http://127.0.0.1:8000/");
服务器向客户端发送一条简单的文本消息。
const http = require('http');
我们加载http
模块以创建 http 服务器。
const server = http.createServer((req, res) => {
res.writeHead(200, {"Content-Type": "text/plain"});
res.end("Hello there\n");
});
服务器已创建。 它向客户端发送一条短信。
server.listen(8000);
服务器监听 localhost 上的端口 8000。
$ node server.js &
$ curl localhost:8000
Hello there
我们运行服务器并使用curl
创建一个请求。
在本教程中,我们介绍了 Node.js。 我们已经使用 Node.js 创建了一些代码示例。
您可能也对以下相关教程感兴趣: JSON 服务器教程, Liquid.js 教程,从 JavaScript 中的 URL 读取 JSON , JavaScript 贪食蛇教程, jQuery 教程, Lodash 教程, jQuery 自动完成教程或使用 jQuery DatePicker
。
Node HTTP 教程
原文: http://zetcode.com/javascript/http/
Node HTTP 教程展示了如何使用带有 HTTP 模块的 JavaScript 创建 HTTP 服务器和客户端应用。
HTTP
HTTP 是一个 Node.js 模块,可用于在 JavaScript 中创建 HTTP 服务器和客户端应用。 流行的 JavaScript 框架(包括 Express 和 HapiJS)建立在 HTTP 模块的顶部。
本教程教您 HTTP 交互的基础知识。 要创建真实的 Web 应用,我们应该使用完整的 Web 框架,例如 JavaScript 的 Express 或 PHP 的 Symfony。
安装 HTTP
首先,我们安装 HTTP 模块。
$ node -v
v11.5.0
我们使用 Node.js 11.5 版。
$ npm init -y
我们启动一个新的 Node.js 应用。
$ npm i http
我们使用npm i http
命令安装 HTTP。
Node HTTP 简单服务器
使用createServer()
创建服务器应用。
simple.js
const http = require('http');
http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('Hello there');
res.end();
}).listen(8080);
console.log('server running on port 8080');
该示例创建了一个非常简单的 HTTP 服务器,该服务器将文本消息发送到客户端。 服务器在端口 8080 上运行。
const http = require('http');
首先,我们包括 HTTP 模块。
http.createServer((req, res) => {
我们使用createServer()
函数创建一个 Web 应用。 它接受一个接收两个参数的处理函数:请求和响应对象。
res.writeHead(200, { 'Content-Type': 'text/plain' });
使用writeHead()
方法,我们将标头写入响应。 我们指定状态码和内容类型。
res.write('Hello there');
我们将数据写入响应。
res.end();
我们将回复发送给客户。
$ node simple.js
server running on port 8080
我们启动服务器。
$ curl localhost:8080
Hello there
使用curl
工具,我们向服务器创建 GET 请求并接收消息。
Node HTTP 发送 JSON
在下一个示例中,我们创建一个发送 JSON 响应的服务器。 JSON(JavaScript 对象表示法)是一种轻量级的数据交换格式。
send_json.js
const http = require('http');
const server = http.createServer((req, res) => {
if (req.url == '/now') {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.write(JSON.stringify({ now: new Date() }));
res.end();
} else {
res.end('Invalid request');
}
});
server.listen(8080);
console.log('server running on port 8080');
应用通过以 JSON 发送当前日期来响应/now
请求路径。
if (req.url == '/now') {
我们检查请求 URL 是否等于/now
。
res.writeHead(200, { 'Content-Type': 'application/json' });
我们通知客户端,我们在标头中使用适当的内容类型发送 JSON 响应。
res.write(JSON.stringify({ now: new Date() }));
我们将 JSON 中的当前日期写入响应中。
Node HTTP 发送 HTML
接下来,我们将向客户端发送 HTML 数据。
send_html.js
const http = require('http');
const server = http.createServer(function (req, res) {
if (req.url == '/') {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.write('<html><body><p>This is home page.</p></body></html>');
res.end();
} else if (req.url == "/contact") {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.write('<html><body><p>This is contact page</p></body></html>');
res.end();
} else if (req.url == "/admin") {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.write('<html><body><p>This is admin page</p></body></html>');
res.end();
} else {
res.end('Invalid request');
}
});
server.listen(8080);
console.log('server running on port 8080');
我们指定text/html
内容类型,并将 HTML 标记写入响应。
注意:在实际应用中,我们不会在响应中编写 HTML 代码。 我们使用模板。
Node HTTP 查询参数
客户端可以通过向 URL 添加查询参数来与服务器通信。
query_params.js
const http = require('http');
const url = require('url');
http.createServer((req, res) => {
let q = url.parse(req.url, true).query;
let msg = `${q.name} is ${q.age} years old`;
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write(msg);
res.end();
}).listen(8080);
console.log('server running on port 8080');
在该示例中,服务器以根据查询参数构建的消息作为响应。
const url = require('url');
为了解析查询参数,我们使用url
模块。
let q = url.parse(req.url, true).query;
我们得到具有值的查询对象。
let msg = `${q.name} is ${q.age} years old`;
我们根据查询参数构建消息。
$ curl "localhost:8080/?name=Peter&age=34"
Peter is 34 years old
启动服务器后,我们使用curl
创建请求。 我们指定查询参数。
Node HTTP 服务器
下面的示例创建一个更复杂的 HTTP 服务器。 docs
子目录中有三个 HTML 文件。
docs/about.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>About page</title>
</head>
<body>
<p>This is about page.</p>
</body>
</html>
这是about.html
文件。
docs/contact.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Contact page</title>
</head>
<body>
<p>This is contact page.</p>
</body>
</html>
这是contact.html
文件。
docs/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Home page</title>
</head>
<body>
<p>
This is home page.
</p>
</body>
</html>
这是index.html
文件。
http_server.js
const http = require('http');
const fs = require('fs');
const url = require('url');
const server = http.createServer((req, res) => {
let pathname = url.parse(req.url).pathname;
console.log(`Request for ${pathname} received`);
if (pathname == '/') {
pathname = '/index.html';
}
fs.readFile('docs/' + pathname.substr(1), (err, data) => {
if (err) {
console.error(err);
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.write('404 - file not found');
} else {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.write(data.toString());
}
res.end();
});
});
server.listen(8080);
console.log('server running on port 8080');
const fs = require('fs');
我们使用fs
模块读取 HTML 文件。
该示例从文件系统读取 HTML 文件。
let pathname = url.parse(req.url).pathname;
我们确定路径名,即要加载的文件名。
if (pathname == '/') {
pathname = '/index.html';
}
对于根页面,我们发送index.html
。
fs.readFile('docs/' + pathname.substr(1), (err, data) => {
使用readFile()
方法,我们读取 HTML 文件的内容。
if (err) {
console.error(err);
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.write('404 - file not found');
} ...
发生错误时,我们会将 404 代码发送给客户端。
} else {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.write(data.toString());
}
如果找到并读取了文件,我们会将文件的内容发送给客户端。
Node HTTP GET 请求
我们也可以使用 HTTP 模块来创建客户端请求。
http_get.js
const http = require('http');
const options = {
hostname: 'webcode.me',
port: 80,
path: '/',
method: 'GET'
};
const req = http.request(options, (res) => {
console.log(`statusCode: ${res.statusCode}`);
res.on('data', (d) => {
process.stdout.write(d);
});
});
req.on('error', (err) => {
console.error(err);
});
req.end();
该示例向webcode.me
创建 HTTP GET 请求。
const options = {
hostname: 'webcode.me',
port: 80,
path: '/',
method: 'GET'
};
这些选项包含所生成请求的主机名,端口,路径和 HTTP 方法。
const req = http.request(options, (res) => {
使用request()
生成请求。
res.on('data', (d) => {
process.stdout.write(d);
});
我们不断将传入的数据写入数据事件处理器中的控制台。
$ node http_get.js
statusCode: 200
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My html page</title>
</head>
<body>
<p>
Today is a beautiful day. We go swimming and fishing.
</p>
<p>
Hello there. How are you?
</p>
</body>
</html>
这是输出。
另外,我们可以使用get()
方法。
http_get.js
const http = require('http')
const req = http.get({ host: 'webcode.me', path: '/' }, (res) => {
// Continuously update stream with data
let content = '';
res.on('data', (chunk) => {
content += chunk;
});
res.on('end', () => {
console.log(content);
});
});
req.end();
我们生成对同一网站的 GET 请求。
// Continuously update stream with data
let content = '';
res.on('data', (chunk) => {
content += chunk;
});
我们不断将检索到的数据块添加到content
变量中。
res.on('end', () => {
console.log(content);
});
最后,我们将变量打印到控制台。
Node HTTP POST 请求
下面的示例向httpbin.org
网站创建 POST 请求。 这是一个免费的网站,我们可以在其中测试我们的请求。 由于站点使用 HTTPS 协议,因此我们使用https
模块。
http_post.js
const https = require('https');
let payload = JSON.stringify({
"name": "Peter",
"age": 34
});
let headers = {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(payload, 'utf8')
};
let options = {
host: 'httpbin.org',
port: 443,
path: '/post',
method: 'POST',
headers: headers
};
let reqPost = https.request(options, (res) => {
console.log("status code: ", res.statusCode);
res.on('data', (chunks) => {
process.stdout.write(chunks);
});
});
reqPost.write(payload);
reqPost.end();
reqPost.on('error', (err) => {
console.error(err);
});
该示例将数据发送到测试网站。 服务器以包含我们已发送的有效负载的数据进行响应。
const https = require('https');
我们使用https
模块。
payload = JSON.stringify({
"name": "Peter",
"age": 34
});
这是要发送的有效负载。
let headers = {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(payload, 'utf8')
};
这些是标题。 我们发送 JSON 数据。 我们指定内容的长度。
let options = {
host: 'httpbin.org',
port: 443,
path: '/post',
method: 'POST',
headers: headers
};
这些是 POST 请求的选项。 HTTPS 标准端口为 443。
let reqPost = https.request(options, (res) => {
console.log("status code: ", res.statusCode);
res.on('data', (chunks) => {
process.stdout.write(chunks);
});
});
在 post 调用的数据事件处理器中,我们将数据写入控制台。
reqPost.write(payload);
我们将有效载荷数据写入 POST 请求。
reqPost.end();
请求已发送。
在本教程中,我们使用了 JavaScript HTTP 模块。
列出 JavaScript 教程。
Node-config 教程
标题: http://zetcode.com/javascript/nodeconfig/
Node-config 教程展示了如何使用 node-config 模块为 Node 应用创建配置文件。
Node-config
Node-config 创建用于应用部署的配置文件。
Node-config 允许我们定义一组默认参数,并将它们扩展为不同的部署环境(开发,质量保证,登台,生产等)。
配置文件位于默认的config
目录中。 可以使用NODE_CONFIG_DIR
环境变量覆盖该位置。 NODE_ENV
环境变量包含我们应用的部署环境的名称; 默认为development
。
Node-config 支持各种配置文件格式,包括 JSON,YAML,属性或 XML。 默认配置文件为default.json
(或default.yaml
和default.xml
)。 如果我们使用生产部署,那么将从production.json
加载配置。
安装 Node-config
首先,我们安装node-config
。
$ node -v
v11.5.0
我们使用 Node 版本 11.5.0。
$ npm init -y
我们启动一个新的 Node 应用。
$ npm i config
我们使用nmp i config
安装 node-config。
$ npm i js-yaml
此外,我们安装了js-yaml
以支持 YAML。
Node-config 示例
以下示例使用config
包检索配置数据。
config/default.json
{
"app": {
"port": 3000
},
"db": {
"host": "localhost",
"port": 27017,
"name": "ydb"
}
}
我们在config
目录中有default.json
。
simple.js
const config = require('config');
let appPort = config.get('app.port');
console.log(`Application port: ${appPort}`);
let dbHost = config.get('db.host');
console.log(`Database host: ${dbHost}`);
let dbPort = config.get('db.port');
console.log(`Database port: ${dbPort}`);
let dbName = config.get('db.name');
console.log(`Database name: ${dbName}`);
console.log('NODE_ENV: ' + config.util.getEnv('NODE_ENV'));
我们加载config
包,并使用config.get()
函数获取值。 默认部署类型在NODE_ENV
中指定。
$ node simple.js
Application port: 3000
Database host: localhost
Database port: 27017
Database name: ydb
NODE_ENV: development
这是输出。
Node-config 示例 II
我们将配置文件更改为 YAML 并设置生产部署环境。
config/default.yaml
app:
port: 3000
db:
host: localhost
port: 27017
name: ydb
这是default.yaml
文件。
config/production.yaml
app:
port: 3300
db:
host: localhost
port: 27017
name: mydb
这是production.yaml
文件。
simple.js
const config = require('config');
let appPort = config.get('app.port');
console.log(`Application port: ${appPort}`);
...
simple.js
文件是相同的。
$ node simple.js
Application port: 3000
Database host: localhost
Database port: 27017
Database name: ydb
NODE_ENV: development
这是默认环境的输出。 从default.yaml
加载配置。
$ set NODE_ENV=production
$ node simple.js
Application port: 3300
Database host: localhost
Database port: 27017
Database name: mydb
NODE_ENV: production
我们使用set
命令更改NODE_ENV
变量。 (在 Linux 上使用export
。)现在,从production.yaml
文件加载配置数据。
在本教程中,我们使用node-config
包为 Node.js 应用创建配置文件。
您可能也对以下相关教程感兴趣: Node.js 教程。 列出所有 JavaScript 教程。
dotenv
教程
原文: http://zetcode.com/javascript/dotenv/
dotenv
教程展示了如何使用dotenv
模块在 JavaScript 中加载环境变量。
dotenv
模块
dotenv
是一个零依赖模块,可将环境变量从.env
文件加载到process.env
中。 将配置存储在与代码分开的环境中是基于十二因子应用方法的。
环境变量
环境变量使我们能够与代码库分开管理应用的配置。 分开的配置使我们的应用更容易在不同的环境中部署。
环境变量是应用外部的变量,它们驻留在运行生产应用的 OS 或容器中。 由于开发大部分是在本地计算机上完成的,因此环境变量可以通过set
或export
等命令放置到本地环境变量中,或者存储在本地.env
文件中。
按照惯例,这些变量都写在大写字母(例如端口)。
存储在环境变量中的配置数据的常见示例包括:
- HTTP 端口
- 数据库连接字符串
- 静态文件的位置
- 外部服务的端点
绝对不要将.env
文件提交到源代码存储库。 我们必须将文件放入.gitignore
文件。 (使用 git 时。)
现代编辑器支持.env
文件。 例如,code
具有 DotENV 扩展名。
dotenv
解析规则
以下是一些基本的解析引擎规则:
BASIC=basic
变为{BASIC: 'basic'}
- 空行被跳过
- 注释以
#
开头 - 空值变成空字符串;
BASIC=
变为{BASIC: ''}
- 内部引用保持不变
现有的环境变量不会被修改; 他们被跳过。
Dotenv 设置
我们将dotenv
模块与npm
一起安装。
$ node -v
v11.5.0
我们使用 Node 版本 11.5.0。
$ npm init -y
我们启动一个新的 Node 应用。
$ npm i dotenv
我们使用npm i dotenv
命令安装dotenv
。
dotenv
简单示例
在第一个示例中,从.env
文件中读取配置数据。
.env
HOST = localhost
DATABASE = ydb
PORT = 5432
我们有三个变量:HOST
,DATABASE
和PORT
。 我们使用大写字母来遵守命名约定。
simple.js
require('dotenv').config()
const hostname = process.env.HOST;
const database = process.env.DATABASE;
const port = process.env.PORT;
console.log(hostname);
console.log(database);
console.log(port);
在示例中,我们读取了三个变量并将它们打印到控制台。
require('dotenv').config()
我们加载dotenv
库,并调用config()
的方法,它加载变量进入process.env
。
const hostname = process.env.HOST;
const database = process.env.DATABASE;
const port = process.env.PORT;
我们从process.env
中读取了三个变量。
console.log(hostname);
console.log(database);
console.log(port);
最后,变量被打印到终端。
$ node simple.js
localhost
ydb
5432
这是输出。
dotenv
预加载
我们可以使用--require
(-r
)命令行选项来预加载dotenv
。 这样,我们不需要在应用中要求和加载dotenv
。
.env
HOST = localhost
DATABASE = ydb
PORT = 5432
我们有相同的变量。
preload.js
const hostname = process.env.HOST;
const database = process.env.DATABASE;
const port = process.env.PORT;
const user = process.env.USER;
console.log(hostname);
console.log(database);
console.log(port);
console.log(user);
在此示例中,我们不需要dotenv
模块。 另外,我们读取在 OS 环境中设置的变量。
$ set USER=user7
$ node -r dotenv/config preload.js
localhost
ydb
5432
user7
在 Windows 上,我们使用set
定义环境变量。 (在 Linux 上使用export
)。 变量打印确定。
在本教程中,我们使用了dotenv
模块从.env
文件读取环境变量。
您可能也对以下相关教程感兴趣: Moment.js 教程,从 JavaScript 中的 URL 读取 JSON , Node Sass 教程, Lodash 教程 或列出所有 JavaScript 教程。
Joi 教程
原文: http://zetcode.com/javascript/hapijoi/
Joi 教程展示了如何使用 Hapi Joi 模块验证 JavaScript 中的值。
Joi
Hapi Joi 是一种对象模式描述语言,也是 JavaScript 对象的验证器。
使用 Hapi Joi,我们可以为 JavaScript 对象(存储信息的对象)创建蓝图或架构,以确保验证关键信息。
Hapi 是一个易于使用的以配置为中心的框架,具有对输入验证,缓存,认证以及用于构建 Web 和服务应用的其他基本函数的内置支持。
Joi 安装
首先,我们安装库。
$ node -v
v11.5.0
我们使用 Node 版本 11.5.0。
$ npm init -y
$ npm i @hapi/js
我们启动项目,并使用nmp i @hapi/joi
安装 Hapi Joi。
Joi 验证
验证通过validate()
函数执行:
validate(value, schema, [options], [callback])
value
是要验证的值,schema
是验证模式。
options
是验证选项。 在abortEarly
选项停在第一个错误的验证,否则返回发现的所有错误。 默认为true
。 convert
选项尝试将值转换为所需的类型。 它也默认为true
。
callback
是使用签名function(err, value)
的可选同步回调方法。 如果验证失败,则err
包含错误原因,否则为null
。 value
是应用了任何类型转换和其他修饰符的值。
Joi 版本
在第一个示例中,我们打印 Hapi Joi 的版本。
version.js
const Joi = require('@hapi/joi');
console.log(Joi.version)
Joi 的版本存储在Joi.version
中。
const Joi = require('@hapi/joi');
我们包括 Hapi Joi 模块。
$ node version.js
15.0.3
这是一个示例输出。
Joi 同步函数
在下面的示例中,我们在同步函数内部执行验证。
sync_fun.js
const Joi = require('@hapi/joi');
const schema = Joi.object().keys({
username: Joi.string().required(),
email: Joi.string().email().required()
});
let username = 'Roger Brown';
let email = 'roger@example';
let data = { username, email };
Joi.validate(data, schema, (err, value) => {
if (err) {
console.log(err.details);
} else {
console.log(value);
}
});
我们有两个值可以验证:用户名和电子邮件。
const schema = Joi.object().keys({
username: Joi.string().required(),
email: Joi.string().email().required()
});
这是验证模式。 用户名必须是字符串,并且是必需的。 该电子邮件必须是有效的电子邮件地址,并且也是必需的。
let username = 'Roger Brown';
let email = 'roger@example';
let data = { username, email };
这是要验证的数据。
Joi.validate(data, schema, (err, value) => {
if (err) {
console.log(err.details);
} else {
console.log(value);
}
});
Joi.validate()
使用提供的模式验证数据。
$ node sync_fun.js
[ { message: '"email" must be a valid email',
path: [ 'email' ],
type: 'string.email',
context: { value: 'roger@example', key: 'email', label: 'email' } } ]
这是示例输出。
Joi 返回值
在下一个示例中,我们不使用同步函数。 我们使用返回的值。
ret_vals.js
const Joi = require('@hapi/joi');
const schema = Joi.object().keys({
username: Joi.string().required(),
born: Joi.date().required()
});
let username = 'Roger Brown';
let born = '1988-12-11';
let data = { username, born };
const { err, value } = Joi.validate(data, schema);
if (err) {
console.log(err.details);
} else {
console.log(value);
}
该示例验证两个值:用户名和生日。
const { err, value } = Joi.validate(data, schema);
使用validate()
的另一种方法是获取其返回值。
if (err) {
console.log(err.details);
} else {
console.log(value);
}
根据返回的值,我们将打印错误详细信息或原始值。
$ node ret_vals.js
{ username: 'Roger Brown', born: 1988-12-11T00:00:00.000Z }
我们没有错误,因此会打印验证值。
Joi abortEarly
默认情况下,Joi 会在第一个错误时停止验证。 如果要获取所有错误,则必须将abortEarly
选项设置为true
。
abort_early.js
const Joi = require('@hapi/joi');
const schema = Joi.object().keys({
username: Joi.string().min(2).max(30).required(),
password: Joi.string().regex(/^[\w]{8,30}$/),
registered: Joi.number().integer().min(2012).max(2019),
married: Joi.boolean().required()
});
let username = 'Roger Brown';
let password = 's#cret12';
let registered = '2011';
let married = false;
let data = { username, password, registered, married };
let options = { abortEarly: false };
const { error, value } = Joi.validate(data, schema, options);
if (error) {
console.log(error.details);
} else {
console.log(value);
}
在示例中,我们将打印所有已发生的错误。
const schema = Joi.object().keys({
username: Joi.string().min(2).max(30).required(),
password: Joi.string().regex(/^[\w]{8,30}$/),
registered: Joi.number().integer().min(2012).max(2019),
married: Joi.boolean().required()
});
我们有四个值可以验证。
let options = { abortEarly: false };
const { error, value } = Joi.validate(data, schema, options);
我们将abortEarly
选项设置为false
。
$ node abort_early.js
[ { message:
'"password" with value "s#cret12" fails to match the required pattern: /^[\\w]{8,30}$/',
path: [ 'password' ],
type: 'string.regex.base',
context:
{ name: undefined,
pattern: /^[\w]{8,30}$/,
value: 's#cret12',
key: 'password',
label: 'password' } },
{ message: '"registered" must be larger than or equal to 2012',
path: [ 'registered' ],
type: 'number.min',
context:
{ limit: 2012,
value: 2011,
key: 'registered',
label: 'registered' } } ]
我们有两个验证错误。
Joi convert
Joi 默认情况下强制转换值; 要禁用投射,我们将convert
选项设置为false
。
casting.js
const Joi = require('@hapi/joi');
const schema = Joi.object().keys({
timestamp: Joi.date().timestamp(),
val: Joi.number()
});
let val = '23543';
let timestamp = 1559761841;
let data = { val, timestamp };
const { error, value } = Joi.validate(data, schema);
if (error) {
console.log(error.details);
} else {
console.log(value);
}
在示例中,我们有两个 Joi 自动转换的值。
let val = '23543';
let timestamp = 1559761841;
该字符串将强制转换为数字,而时间戳则转换为 ISO 字符串。
$ node casting.js
{ val: 23543, timestamp: 1970-01-19T01:16:01.841Z }
这是输出。
Joi 验证数字
使用Joi.number()
,我们可以验证数字。
numbers.js
const Joi = require('@hapi/joi');
const schema = Joi.object().keys({
age: Joi.number().min(18).max(129),
price: Joi.number().positive(),
experience: Joi.number().greater(5)
});
let age = 35;
let price = -124.3;
let experience = 6;
let data = { age, price, experience };
const { error, value } = Joi.validate(data, schema);
if (error) {
console.log(error.details);
} else {
console.log(value);
}
在示例中,我们验证了三个数字。
const schema = Joi.object().keys({
age: Joi.number().min(18).max(129),
price: Joi.number().positive(),
experience: Joi.number().greater(5)
});
age
值必须是 18-129 之间的数字。 price
必须为正,experience
必须大于五。
$ node numbers.js
[ { message: '"price" must be a positive number',
path: [ 'price' ],
type: 'number.positive',
context: { value: -124.3, key: 'price', label: 'price' } } ]
由于价格为负,因此我们得到此错误详细信息。
Joi 验证日期
使用Joi.date()
,我们可以验证日期。
dates.js
const Joi = require('@hapi/joi');
const schema = Joi.object().keys({
timestamp: Joi.date().timestamp(),
isodate: Joi.date().iso(),
registered: Joi.date().greater('2018-01-01')
});
let timestamp = 1559761841;
let isodate = '1970-01-19T01:16:01.841Z';
let registered = '2019-02-12';
let data = { timestamp, isodate, registered };
const { error, value } = Joi.validate(data, schema);
if (error) {
console.log(error.details);
} else {
console.log(value);
}
该示例验证三个日期值。
const schema = Joi.object().keys({
timestamp: Joi.date().timestamp(),
isodate: Joi.date().iso(),
registered: Joi.date().greater('2018-01-01')
});
在模式中,我们具有规则来验证值是时间戳,具有 ISO 格式并且大于指定值。
$ node dates.js
{ timestamp: 1970-01-19T01:16:01.841Z,
isodate: 1970-01-19T01:16:01.841Z,
registered: 2019-02-12T00:00:00.000Z }
所有值均已通过验证。 请注意,这些值已自动转换为 ISO 格式。
Joi 验证数组
可以使用array()
验证数组。
arrays.js
const Joi = require('@hapi/joi');
const schema = Joi.array().min(2).max(10);
let data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ];
const { error, value } = Joi.validate(data, schema);
if (error) {
console.log(error.details);
} else {
console.log(value);
}
在示例中,我们验证了整数数组。
const schema = Joi.array().min(2).max(10);
我们验证数组至少有两个元素,最多有十个元素。
$ node arrays.js
[ { message: '"value" must contain less than or equal to 10 items',
path: [],
type: 'array.max',
context:
{ limit: 10, value: [Array], key: undefined, label: 'value' } } ]
这是输出。
Joi 验证函数
可以使用func()
验证函数。
functions.js
const Joi = require('@hapi/joi');
const schema = Joi.func().arity(2);
function add2int(x, y) {
return x + y;
}
const { error, value } = Joi.validate(add2int, schema);
if (error) {
console.log(error.details);
} else {
console.log(value);
}
在示例中,我们验证了一个函数。
const schema = Joi.func().arity(2);
我们验证函数的参数(参数数量)。
在本教程中,我们已经使用 Hapi Joi 模块在 JavaScript 中进行了验证。
列出所有 JavaScript 教程。
{% raw %}
Liquid.js 教程
原文: http://zetcode.com/javascript/liquidjs/
Liquid.js 教程展示了如何在 JavaScript 应用中使用 Liquid 模板引擎。
Liquid.js
Liquid.js 是 JavaScript 模板引擎。 它由 Shopify 创建。 临时文件的扩展名为.liquid
; 它们混合了静态数据,例如 HTML 和 Liquid 结构。
Liquid 使用双花括号定界符{{ }}
作为输出,并使用大括号百分比定界符{% %}
作为逻辑。
{% if user != null %}
Hello {{ user.name }}
{% endif %}
此代码是示例 Liquid 语法。
模板引擎
模板引擎或模板处理器是一个旨在将模板与数据模型结合以生成文档的库。 模板引擎通常用于在源代码预处理中生成大量电子邮件,或生成动态 HTML 页面。
我们创建一个模板引擎,在其中定义静态零件和动态零件。 动态部分随后将替换为数据。 渲染功能随后将模板与数据结合在一起。
安装 Liquid.js
首先,我们安装 Liquid.js。
$ node -v
v11.5.0
我们使用 Node 版本 11.5.0。
$ npm init -y
我们启动一个新的 Node 应用。
$ npm i liquidjs
我们将liquidjs
模块与nmp i liquidjs
一起安装。
Liquid.js 字符串渲染
我们从一个非常简单的示例开始,该示例从字符串进行渲染。
simple.js
const Liquid = require('liquidjs');
const engine = new Liquid();
engine
.parseAndRender('{{name | capitalize}}', {name: 'lucy'})
.then(console.log);
该示例显示了字符串模板的输出。 它还使用过滤器。
const Liquid = require('liquidjs');
const engine = new Liquid();
我们加载Liquid.js
模块并启动引擎。
engine
.parseAndRender('{{name | capitalize}}', {name: 'lucy'})
.then(console.log);
parseAndRender()
函数采用模板字符串和上下文数据。 在模板字符串中,我们有一个名称变量,该变量传递给capitalize
过滤器。 过滤器在输出之前修改数据。
$ node simple.js
Lucy
这是输出。
Liquid.js 排序过滤器
sort
是可用的数组过滤器之一。
sort_filter.js
const Liquid = require('liquidjs');
const engine = new Liquid();
nums = [5, 3, 2, 4, 1]
ctx = { data: nums}
engine
.parseAndRender('Sorted data: {{ data | sort }}', ctx)
.then(console.log);
该示例对传递给模板字符串的数据进行排序。
$ node sort_filter.js
Sorted data: [1,2,3,4,5]
这是输出。
Liquid.js 从文件进行渲染
要渲染文件的输出,我们使用renderFile()
函数。
$ mkdir views
我们创建一个目录,在其中放置模板文件。
from_file.js
const Liquid = require('liquidjs');
const path = require('path');
const engine = new Liquid({
root: path.resolve(__dirname, 'views/'),
extname: '.liquid'
});
engine
.renderFile('hello', { name: 'Peter' })
.then(console.log)
该示例从文本文件生成输出。
const engine = new Liquid({
root: path.resolve(__dirname, 'views/'),
extname: '.liquid'
});
在Liquid
构造器中,我们提供模板目录位置和扩展名。 扩展名通常是.liquid
。
engine
.renderFile('hello', { name: 'Peter' })
.then(console.log)
renderFile()
的第一个参数是模板名称。 第二个参数是上下文数据。
views/hello.liquid
Hello {{ name }}!
在模板文件中,我们使用{{}}
输出上下文变量。
$ node from_file.js
Hello Peter!
这是输出。
Liquid.js 标签
液体for
是一个反复执行代码块的迭代标签。
users.js
const Liquid = require('liquidjs');
const path = require('path');
const engine = new Liquid({
root: path.resolve(__dirname, 'views/'),
extname: '.liquid'
});
ctx = { users: [{ name: "Peter", age: 24 }, { name: "Lucy", age: 34 }] };
engine
.renderFile("users", ctx)
.then(console.log);
在示例中,我们定义了一个用户数组。 数组通过for
在模板中循环。
views/users.liquid
There are {{ users | size }} users
{% for user in users -%}
{{ user.name }} is {{ user.age }} years old
{% endfor -%}
模板文件输出使用size
过滤器的用户数以及上下文变量中的所有用户。
{% for user in users -%}
{{ user.name }} is {{ user.age }} years old
{% endfor -%}
我们遍历用户数组并打印属性。 空格输出可以用破折号字符控制。
$ node users.js
There are 2 users
Peter is 24 years old
Lucy is 34 years old
这是输出。
Liquid.js 部分
部分是可重用的模板,包含在其他模板中。 部分用于重复的内容,例如页脚或页眉。
使用include
指令插入部分。
partials.js
const Liquid = require('liquidjs');
const path = require('path');
const engine = new Liquid({
root: path.resolve(__dirname, 'views/'),
extname: '.liquid'
});
ctx = { name: 'Peter' };
engine
.renderFile("home", ctx)
.then(console.log);
本示例显示了home.liquid
模板的输出,该模板包括液体部分。
views/footer.liquid
{{ "now" | date: "%Y-%m-%d %H:%M" }}, ZetCode 2007 - 2019
这是页脚的一部分。 借助date
过滤器,它可以显示当前日期和时间。
views/home.liquid
Hello {{ name }}!
{% include 'footer' %}
include
伪指令包含footer
部分。
$ node partials.js
Hello Peter!
2019-02-13 22:52, ZetCode 2007 - 2019
这是输出。
Liquid.js 继承
Liquid 支持模板继承。 模板继承是一项强大的功能,可减少代码重复并改善代码组织。 我们定义了一个基本模板,其他模板文件也从中继承。 这些模板文件将覆盖基本模板文件的特定块。
inheritance.js
const Liquid = require('liquidjs');
const path = require('path');
const engine = new Liquid({
root: path.resolve(__dirname, 'views/'),
extname: '.liquid'
});
engine
.renderFile("derived", { content: 'Some content' })
.then(console.log)
该示例从derived.liquid
模板生成输出,该模板使用继承技术。
views/base.liquid
Header
{% block content %}My default content{% endblock %}
Footer
这是其他模板继承的base.liquid
文件。 block/endblock
指令用于声明一个内容块,该内容块将在子模板中替换。
views/derived.liquid
{% layout "base" %}
{% block content %} {{ content }} {% endblock %}
这是子模板。 使用layout
指令,我们继承自base.liquid
模板。 我们使用block/endblock
指令定义内容。
$ node inheritance.js
Header
Some content
Footer
这是输出。
Liquid.js Express 示例
在下面的示例中,我们在 Express 应用中使用 Liquid。
$ npm i express
我们安装 Express Web 框架。
express-demo.js
const express = require("express");
const path = require("path");
const Liquid = require('liquidjs');
const engine = new Liquid();
const app = express();
app.engine('liquid', engine.express());
app.set('views', path.resolve(__dirname, "views"));
app.set('view engine', 'liquid');
app.get("/today", (req, res) => {
let today = new Date();
res.render("show_date", {now: today});
});
app.use((req, res) => {
res.statusCode = 404;
res.end("404 - page not found");
});
app.listen(3000, () => {
console.log("Application started on port 3000");
})
该示例是使用 Express 创建的简单 Web 应用。 它显示当前日期。
app.engine('liquid', engine.express());
app.set('views', path.resolve(__dirname, "views"));
app.set('view engine', 'liquid');
我们将 Liquid 集成到 Express 应用中。
app.get("/today", (req, res) => {
let today = new Date();
res.render("show_date", {now: today});
});
对于/today
路径,我们显示当前日期。 show_date.liquid
生成输出。 我们将now
上下文变量传递给模板。
views/show_date.liquid
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Show date</title>
</head>
<body>
<p>
Today is {{ now }}
</p>
</body>
</html>
show_date.liquid
生成 HTML 输出。 它使用{{}}
将当前日期添加到内容中。
$ node express-demo.js
Application started on port 3000
我们启动该应用。
$ curl localhost:3000/today
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Show date</title>
</head>
<body>
<p>
Today is Wed Feb 13 2019 23:19:07 GMT+0100 (Central European Standard Time)
</p>
</body>
</html>
我们使用curl
工具向应用创建请求。
在本教程中,我们使用 Liquid.js 从 Liquid 模板和数据生成文档。 我们介绍了 Liquid 标签,过滤器,局部变量和继承。
您可能也对以下相关教程感兴趣: Moment.js 教程, Axios 教程, Faker.js 教程, JSONServer 教程 , Node Sass 教程, Node.js 教程, Lodash 教程。
{% endraw %}
faker.js 教程
原文: http://zetcode.com/javascript/fakerjs/
faker.js 教程显示了如何使用 faker.js 库在 JavaScript 中生成伪造数据。
faker.js
faker.js 是用于生成伪造数据的 JavaScript 库。 伪数据在构建和测试我们的应用时很有用。 faker.js 可以为各个领域生成伪造数据,包括地址,商业,公司,日期,财务,图像,随机数或名称。
在本教程中,我们在 Node 应用中使用 faker.js。
安装 faker.js
首先,我们安装 faker.js。
$ node -v
v11.5.0
我们使用 Node 版本 11.5.0。
$ npm init -y
我们启动一个新的 Node 应用。
$ npm i faker
我们使用nmp i faker
安装 faker.js 模块。
伪造名称
在第一个示例中,我们伪造了与用户名有关的数据。
names.js
const faker = require('faker');
let firstName = faker.name.firstName();
let lastName = faker.name.lastName();
let jobTitle = faker.name.jobTitle();
let prefix = faker.name.prefix();
let suffix = faker.name.suffix();
let jobArea = faker.name.jobArea();
let phone = faker.phone.phoneNumber();
console.log(`Employee: ${prefix} ${firstName} ${lastName} ${suffix}`);
console.log(`Job title: ${jobTitle}`);
console.log(`Job area: ${jobArea}`);
console.log(`Phone: ${phone}`);
该示例创建一个随机的名字,姓氏,职务,姓名前缀和后缀,职务区域和电话号码。
const faker = require('faker');
我们需要伪造者模块。
let firstName = faker.name.firstName();
我们使用firstName()
函数生成了虚假的名字。 该函数位于名称对象中。
$ node names.js
Employee: Mrs. Vernice Abernathy III
Job title: Customer Data Associate
Job area: Program
Phone: 1-516-716-9832
这是一个示例输出。
伪造日期
在第二个示例中,我们生成假日期。
dates.js
const faker = require('faker');
let futureDate = faker.date.future();
let recentDate = faker.date.recent();
let weekday = faker.date.weekday();
console.log(futureDate);
console.log(recentDate);
console.log(weekday);
该示例选择了将来和最近的日期以及某个工作日。
$ node dates.js
2019-04-13T19:09:43.672Z
2019-01-06T12:28:29.089Z
Saturday
这是一个示例输出。
伪造随机值
伪造者允许生成随机值,例如整数,uuid 或单词。
random_values.js
const faker = require('faker');
let number = faker.random.number();
console.log(number);
let uuid = faker.random.uuid();
console.log(uuid);
let word = faker.random.word();
console.log(word);
let words = faker.random.words(6);
console.log(words);
该示例生成随机数,uuid,单词和一组六个单词。
$ node random_values.js
630
1470356a-1197-4955-b3c1-30302fd1db10
Facilitator
dot-com connect Practical Checking Account Mandatory real-time
这是一个示例输出。
伪造语言环境数据
伪造者在某种程度上支持本地化数据。 请注意,语言环境已完成各种级别。
locale_faker.js
const faker = require('faker/locale/ru');
let firstName = faker.name.firstName();
let lastName = faker.name.lastName();
console.log(`Pаботник: ${firstName} ${lastName}`);
let month = faker.date.month();
let recentDate = faker.date.recent();
let rectentDate = faker.date.weekday();
console.log(month);
console.log(recentDate);
console.log(rectentDate);
该示例使用俄语生成伪造数据。
$ node locale_faker.js
Pаботник: Антон Васильева
май
2019-01-06T19:24:01.283Z
Пятница
这是一个示例输出。
使用 JSON 服务器提供虚假数据
在下一个示例中,我们生成 JSON 数据并将其写入文件。 该文件由 JSON 服务器提供。
$ npm i g json-server
我们安装json-server
模块。
generate_users.js
const faker = require('faker');
const fs = require('fs')
function generateUsers() {
let users = []
for (let id=1; id <= 100; id++) {
let firstName = faker.name.firstName();
let lastName = faker.name.lastName();
let email = faker.internet.email();
users.push({
"id": id,
"first_name": firstName,
"last_name": lastName,
"email": email
});
}
return { "data": users }
}
let dataObj = generateUsers();
fs.writeFileSync('data.json', JSON.stringify(dataObj, null, '\t'));
该示例生成一百个用户,并将它们写入data.json
文件。
$ json-server --watch data.json --port 3004
我们启动 JSON 服务器。 服务器提供来自生成的 JSON 文件的数据。
$ curl localhost:3004/data/3/
{
"id": 3,
"first_name": "Sheila",
"last_name": "Bayer",
"email": "Moshe.Walsh32@yahoo.com"
}
我们使用curl
工具使用 ID 3 检索用户。
我们展示了如何使用 Node request
模块在 JavaScript 中生成 HTTP GET 请求。
$ npm i request
我们安装模块。
get_data.js
const request = require('request');
request('http://localhost:3004/data?_start=4&_end=8', (err, resp, body) => {
if (err) {
console.error('request failed');
console.error(err);
} else {
console.log(body);
}
});
该程序从 JSONServer 获取数据,数据从索引 4(不包括索引)开始,到索引 8(不包括索引)结束。
$ node get_data.js
[
{
"id": 5,
"first_name": "Cheyanne",
"last_name": "Ernser",
"email": "Amber.Spinka62@yahoo.com"
},
{
"id": 6,
"first_name": "Jeff",
"last_name": "Bogisich",
"email": "Bettie.Ritchie60@hotmail.com"
},
{
"id": 7,
"first_name": "Simone",
"last_name": "Zemlak",
"email": "Dorris49@gmail.com"
},
{
"id": 8,
"first_name": "Demond",
"last_name": "Barrows",
"email": "Nestor81@yahoo.com"
}
]
这是一个示例输出。
Faker CLI
faker-cli
是一个节点模块,是faker.js
的包装。 它允许从命令行工具生成假数据。
$ npm install -g faker-cli
我们安装faker-cli
模块。
$ faker-cli -d future
"2019-07-22T06:37:19.032Z"
$ faker-cli -d recent
"2019-01-06T21:46:50.788Z"
$ faker-cli -n firstName
"Tevin"
$ faker-cli -n lastName
"Sawayn"
我们使用faker-cli
程序生成一些虚假数据。
在本教程中,我们使用了 faker.js 在 JavaScript 中生成假数据。
您可能也对以下相关教程感兴趣: Moment.js 教程, JSONServer 教程,从 JavaScript 中的 URL 读取 JSON , JavaScript 贪食蛇教程 , JQuery 教程, Node Sass 教程, Lodash 教程。
Handsontable 教程
原文: http://zetcode.com/javascript/handsontable/
Handsontable 教程展示了如何使用 Handsontable 模块在 JavaScript 中创建数据网格。
可调
Handsontable 是一个 JavaScript 库,用于在 JavaScript 中创建数据网格。 它创造了类似电子表格的体验。
在本教程中,我们将使用 Handsontable 和 Gulp4。我们正在使用 Handsontable 组件的社区版本。
安装 Handsontable
首先,我们安装 Handsontable
$ node -v
v11.5.0
我们使用 Node 版本 11.5.0。
$ npm init -y
我们启动一个新的 Node 应用。
$ npm i handsontable
我们安装 Handsontable。
$ npm i --global gulp-cli
$ npm i gulp --save-dev
$ npm i --save-dev gulp-minify
我们安装gulp-cli
,gulp
和gulp-minify
模块。 您也可以运行npm link gulp
在全局安装的gulp
中创建符号链接。
$ mkdir -p src/js
我们创建src/js
目录。 在src/js
子目录中,我们将具有main.js
文件。
Handsontable 的例子
在下面的示例中,我们使用 Handsontable 生成一个数据网格。 我们使用 Gulp 来管理文件。
├───build
│ │ index.html
│ ├───css
│ │ handsontable.full.min.css
│ └───js
│ handsontable.full.min.js
│ main-min.js
├───node_modules
└───src
│ │ index.html
│ │
└───────js
main.js
gulpfile.js
package-lock.json
package.json
这是使用 Gulp 构建后的项目结构。
src/js/main.js
let data = [
["", "Alex", "Frank", "Robert", "Lucy"],
["2017", 99, 44, 12, 14],
["2018", 22, 21, 44, 67],
["2019", 39, 53, 76, 43]
];
let container = document.getElementById('example');
let hot = new Handsontable(container, {
data: data,
rowHeaders: true,
colHeaders: true,
licenseKey: 'non-commercial-and-evaluation'
});
在main.js
文件中,我们创建Handsontable
的实例。 我们将数据添加到表中并进行配置。
src/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<script src="js/handsontable.full.min.js"></script>
<link rel="stylesheet" href="css/handsontable.full.min.css">
<title>Home page</title>
</head>
<body>
<div id="example"></div>
<script src="js/main-min.js"></script>
</body>
</html>
数据网格显示在此文件中。 它替代了div
组件。 我们包括 Handsontable 依赖项和我们的最小主 JavaScript 文件。
gulpfile.js
const gulp = require("gulp");
const minify = require("gulp-minify");
gulp.task('copyHtml', () => {
return gulp.src('src/index.html')
.pipe(gulp.dest('build'))
})
gulp.task('copyJS', () => {
return gulp.src('node_modules/handsontable/dist/handsontable.full.min.js')
.pipe(gulp.dest('build/js'))
})
gulp.task('copyCSS', () => {
return gulp.src('node_modules/handsontable/dist/handsontable.full.min.css')
.pipe(gulp.dest('build/css'))
})
gulp.task('minify', () => {
return gulp.src('src/js/main.js', { allowEmpty: true })
.pipe(minify({noSource: true}))
.pipe(gulp.dest('build/js'))
})
gulp.task('default', gulp.series(['copyHtml', 'minify', 'copyJS', 'copyCSS']));
gulpfile.js
将文件复制并处理到build
目录中。
$ gulp
[10:30:03] Using gulpfile ~\Documents\javascript\hndstable\gulpfile.js
[10:30:03] Starting 'default'...
[10:30:03] Starting 'copyHtml'...
[10:30:03] Finished 'copyHtml' after 31 ms
[10:30:03] Starting 'minify'...
[10:30:03] Finished 'minify' after 35 ms
[10:30:03] Starting 'copyJS'...
[10:30:03] Finished 'copyJS' after 132 ms
[10:30:03] Starting 'copyCSS'...
[10:30:03] Finished 'copyCSS' after 13 ms
[10:30:03] Finished 'default' after 217 ms
我们运行gulp
命令。 它执行其任务,并在build
目录中准备页面。
$ firefox build/index.html
我们从build
目录运行该页面。
图:在 Handsontable 组件中显示数据
在本教程中,我们使用了 Handsontable 在 JavaScript 中创建数据网格。
您可能也对以下相关教程感兴趣: Moment.js 教程, Datatables JSON 服务器教程, JSONServer 教程,从 URL 中读取 JSON JavaScript , JavaScript 贪食蛇教程, JQuery 教程, Node Sass 教程, Lodash 教程。
PouchDB 教程
原文: http://zetcode.com/javascript/pouchdb/
PouchDB 教程展示了如何在 JavaScript 中使用 PouchDB。 本教程中的 PouchDB 代码示例可在数据库中插入,删除和删除文档。
PouchDB
PouchDB 是 CouchDB 的 JavaScript 实现。 PouchDB 可以在浏览器中,在 Node 中本地使用,也可以通过 HTTP 协议远程使用。
默认情况下,PouchDB 随附用于浏览器的 IndexedDB 适配器,Node.js 中的 LevelDB 适配器和用于远程数据库的 CouchDB 适配器。
Apache CouchDB 是面向文档的开源 NoSQL 数据库。 它以 Erlang 语言实现,并使用 JSON 存储数据,将 JavaScript 作为其查询语言以及用于 API 的 HTTP。
PouchDB 创建数据库
为了创建一个新的数据库,我们实例化了一个新的PouchDB
对象。 如果数据库已经存在,它将创建对数据库的引用。
const db = new PouchDB('mydb');
我们创建一个新的mydb
数据库。 根据运行的位置,它将在浏览器,Node 或远程 CouchDB 数据库服务器中创建一个新数据库。
浏览器中的 PouchDB
我们展示了如何在浏览器中使用 PouchDB。
public/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script src="js/pouchdb-7.0.0.min.js"></script>
<script>
const db = new PouchDB('users');
db.info()
.then((info) => {
console.log(info);
})
</script>
</body>
</html>
我们下载了pouchdb
的缩小版,并将其包含在script
标签中。 然后,我们创建一个新的users
数据库,并将有关该数据库的一些信息写入控制台。 要检查创建的数据库,我们转到浏览器开发者工具的存储检查器。
图:Chrome 中的存储浏览器
这是 Google Chrome 浏览器中的存储浏览器。 只要选项卡存在,数据就是持久的。
在 Node 上安装 PouchDB
我们在 Node 上安装 PouchDB。
$ nodejs -v
v9.11.2
我们使用 Node 版本 9.11.2。
$ npm init -y
$ npm i pouchdb
我们创建一个新的 Node 项目并安装 PouchDB。
PouchDB 创建文档
使用put()
方法创建一个新的 PouchDB 文档。
insert_doc.js
const PouchDB = require('pouchdb');
const db = new PouchDB('mydb');
doc = {
_id: new Date().toISOString(),
name: 'Peter',
age: 23,
occupation: 'designer'
};
db.put(doc).then((res) => {
console.log("Document inserted OK");
}).catch((err) => {
console.error(err);
});
该示例在本地创建一个新的mydb
数据库。
doc = {
_id: new Date().toISOString(),
name: 'Peter',
age: 23,
occupation: 'designer'
}
这是一个要插入数据库的新文档。 我们提供了_id
。
db.put(doc).then((res) => {
console.log("Document inserted OK");
}).catch((err) => {
console.error(err);
});
该文档已插入数据库。
$ ls mydb/
000022.ldb 000024.ldb 000025.log CURRENT LOCK LOG LOG.old MANIFEST-000023
在mydb
目录中本地创建一个新数据库。
或者,我们可以使用post()
创建一个新文档。 使用post()
时,会自动为我们生成_id
。
insert_doc2.js
const PouchDB = require('pouchdb');
const db = new PouchDB('mydb');
doc = {
name: 'Peter',
age: 23,
occupation: 'designer'
};
db.post(doc).then((res) => {
console.log("Document inserted OK");
}).catch((err) => {
console.error(err);
});
在示例中,我们使用post()
创建一个新文档。 为文档提供自动生成的_id
,例如b781309e-0423-4b3e-96ad-238cf50debce
。
PouchDB 获取文档
要从数据库检索文档,我们使用get()
函数。
get_doc.js
const PouchDB = require('pouchdb');
const db = new PouchDB('mydb');
db.get('b781309e-0423-4b3e-96ad-238cf50debce').then((doc) => {
console.log(`${doc.name}, ${doc.age}, ${doc.occupation}`);
}).catch((err) => {
console.error(err);
});
我们从数据库中检索文档。 我们为get()
方法提供了_id
。
$ node get_doc.js
Peter, 23, designer
这是输出。
PouchDB 删除文档
要从数据库中删除文档,我们使用remove()
函数。
get_doc.js
const PouchDB = require('pouchdb');
const db = new PouchDB('mydb');
db.get('b781309e-0423-4b3e-96ad-238cf50debce').then((doc) => {
return db.remove(doc);
}).then((res) => {
console.log("The document has been removed");
}).catch((err) => {
console.error(err);
});
为了删除文档,我们必须先使用get()
进行获取,然后再使用remove()
进行删除。
PouchDB bulkDocs
使用bulkDocs()
方法,我们可以在单个批量操作中将许多文档写入数据库。
create_users.js
const PouchDB = require('pouchdb');
const db = new PouchDB('users');
doc1 = { _id: 'peter43@gmail.com', name: 'Peter', age: 23, occupation: 'designer' };
doc2 = { _id: 'sofia23@gmail.com', name: 'Sofia', age: 44, occupation: 'teacher' };
doc3 = { _id: 'paul54@gmail.com', name: 'Paul', age: 25, occupation: 'driver' };
docs = [doc1, doc2, doc3];
db.bulkDocs(docs).then((res) => {
console.log("Documents inserted OK");
}).catch(() => {
console.error(err);
});
在示例中,我们创建一个新的数据库用户,并使用bulkDocs()
插入三个文档。
PouchDB allDocs
allDocs()
是另一个 PouchDB 批量方法; 一步即可检索许多文档。
all_docs.js
const PouchDB = require('pouchdb');
const db = new PouchDB('users');
db.allDocs({ include_docs: true, descending: true }, (err, doc) => {
doc.rows.forEach(e => {
console.log(e.doc);
});
}).catch((err) => {
console.error(err);
});;
在示例中,我们从users
数据库中获取所有文档。
$ node all_docs.js
{ name: 'Sofia',
age: 44,
occupation: 'teacher',
_id: 'sofia23@gmail.com',
_rev: '1-80b0fba21acf487fc20ac499e928acd7' }
{ name: 'Peter',
age: 23,
occupation: 'designer',
_id: 'peter43@gmail.com',
_rev: '1-182869c3c446731fa8b6106910b87d8e' }
{ name: 'Paul',
age: 25,
occupation: 'driver',
_id: 'paul54@gmail.com',
_rev: '1-31bfc20f010c9a6127cb44d6621cee5c' }
这是输出。
PouchDB 更新文档
在下面的示例中,我们显示了如何更新文档。
update_doc.js
const PouchDB = require('pouchdb');
const db = new PouchDB('users');
db.get('sofia23@gmail.com').then((doc) => {
doc.age = 45;
return db.put(doc);
}).then(() => {
return db.get('sofia23@gmail.com');
}).then((doc) => {
console.log(doc);
}).catch((err) => {
console.error(err);
});
为了更新文档,我们对其进行检索,修改其属性并将其放回数据库。
在本教程中,我们使用了 PouchDB 数据库。 我们创建了一些代码示例,这些示例演示了如何创建与 PouchDB 交互的 JavaScript 程序。
您可能也对以下相关教程感兴趣: JQuery 教程, Moment.js 教程,从 JavaScript 中的 URL 读取 JSON , JavaScript 贪食蛇教程 , Node Sass 教程, Lodash 教程。
Cheerio 教程
原文: http://zetcode.com/javascript/cheerio/
Cheerio 教程展示了如何使用 Cheerio 模块在 JavaScript 中进行网页抓取。 Cheerio 实现了为服务器设计的 jQuery 的核心。
Cheerio
Cheerio 是专门为服务器设计的核心 jQuery 的快速,灵活和精益实现。
在本教程中,我们从本地 Web 服务器上抓取 HTML。 对于本地 Web 服务器,我们使用local-web-server
。
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Home page</title>
<style>
.fpar {
font-family: Georgia;
}
</style>
</head>
<body>
<main>
<h1>My website</h1>
<p class="fpar">
I am a JavaScript programmer.
</p>
<p>
My hobbies are:
</p>
<ul>
<li>Swimming</li>
<li>Tai Chi</li>
<li>Running</li>
<li>Web development</li>
<li>Reading</li>
<li>Music</li>
</ul>
</main>
</body>
</html>
我们将使用此 HTML 文件。
Cheerio 选择器
在 Cherrion 中,我们使用选择器来选择 HTML 文档的标签。 选择器语法是从 jQuery 借用的。
以下是可用选择器的部分列表:
$("*")
- 选择所有元素$("#first")
— 用id="first
选择元素$(".intro")
— 选择带有class="intro"
的所有元素$("div")
- 选择所有<div>
元素$("h2, div, p")
- 选择所有<h2>, <div>, <p>
元素$("li:first")
— 选择第一个<li>
元素$("li:last")
— 选择最后一个<li>
元素$("li:even")
— 选择所有偶数<li>
元素$("li:odd")
- 选择所有奇数<li>
元素$(":empty")
- 选择所有为空的元素$(":focus")
- 选择当前具有焦点的元素
安装 Cheerio 和其他模块
我们安装了cheerio
模块和两个附加模块。
$ nodejs -v
v9.11.2
我们使用 Node 版本 9.11.2。
$ sudo npm i cheerio
$ sudo npm i request
$ sudo npm i -g local-web-server
我们安装cheerio
,request
和local-web-server
。
$ ws
Serving at http://t400:8000, http://127.0.0.1:8000, http://192.168.0.3:8000
在项目目录中,我们有index.html
文件,我们启动了本地 Web 服务器。 它会自动在三个不同的位置提供index.html
文件。
Cheerio 标题
在第一个示例中,我们获得了文档的标题。
get_title.js
const cheerio = require('cheerio');
const request = require('request');
request({
method: 'GET',
url: 'http://localhost:8000'
}, (err, res, body) => {
if (err) return console.error(err);
let $ = cheerio.load(body);
let title = $('title');
console.log(title.text());
});
该示例打印 HTML 文档的标题。
const cheerio = require('cheerio');
const request = require('request');
我们包括cheerio
和request
模块。 使用cheerio
,我们可以进行网页抓取。 使用request
,我们创建 GET 请求。
request({
method: 'GET',
url: 'http://localhost:8000'
}, (err, res, body) => {
我们向本地 Web 服务器提供的 localhost 创建 GET 请求。 该资源在body
参数中可用。
let $ = cheerio.load(body);
首先,我们加载 HTML 文档。 为了模仿 jQuery,我们使用$
变量。
let title = $('title');
选择器返回title
标签。
console.log(title.text());
使用text()
方法,我们获得title
标签的文本。
$ node get_title.js
Home page
该示例打印文档的标题。
Cheerio 获取父元素
使用parent()
检索父元素。
get_parent.js
const cheerio = require('cheerio');
const request = require('request');
request({
method: 'GET',
url: 'http://localhost:8000'
}, (err, res, body) => {
if (err) return console.error(err);
let $ = cheerio.load(body);
let h1El = $('h1');
let parentEl = h1El.parent();
console.log(parentEl.get(0).tagName)
});
我们得到h1
元素的父元素。
$ node get_parent.js
main
h1
的父元素是main
。
Cheerio 第一个&最后一个元素
cheerio
对象的第一个元素可以使用first()
找到,最后一个元素可以使用last()
找到。
first_last.js
const cheerio = require('cheerio');
const request = require('request');
request({
method: 'GET',
url: 'http://localhost:8000'
}, (err, res, body) => {
if (err) return console.error(err);
let $ = cheerio.load(body);
let main = $('main');
let fel = main.children().first();
let lel = main.children().last();
console.log(fel.get(0).tagName);
console.log(lel.get(0).tagName);
});
该示例打印main
标签的第一个和最后一个元素。
let main = $('main');
我们选择main
标签。
let fel = main.children().first();
let lel = main.children().last();
我们从main
子级中获得第一个和最后一个元素。
console.log(fel.get(0).tagName);
console.log(lel.get(0).tagName);
我们找出标签名称。
$ node first_last.js
h1
ul
main
的第一个标签是h1
,最后一个标签是ul
。
Cheerio 添加元素
append()
方法在指定标签的末尾添加一个新元素。
add_element.js
const cheerio = require('cheerio');
const request = require('request');
request({
method: 'GET',
url: 'http://localhost:8000'
}, (err, res, body) => {
if (err) return console.error(err);
let $ = cheerio.load(body);
let ulEl = $('ul');
ulEl.append('<li>Travel</li>');
let lis = $('ul').html();
let items = lis.split('\n');
items.forEach((e) => {
if (e) {
console.log(e.replace(/(\s+)/g, ''));
}
});
});
在示例中,我们向ul
元素添加了一个新列表项,并将其打印到控制台。
ulEl.append('<li>Travel</li>');
我们增加了一个新的爱好。
let lis = $('ul').html();
我们得到ul
标签的 HTML。
let items = lis.split('\n');
items.forEach((e) => {
if (e) {
console.log(e.replace(/(\s+)/g, ''));
}
});
我们去除空格。 元素的文本数据包含大量空间。
$ node add_element.js
<li>Swimming</li>
<li>TaiChi</li>
<li>Running</li>
<li>Webdevelopment</li>
<li>Reading</li>
<li>Music</li>
<li>Travel</li>
在列表的末尾附加了一个新的旅行爱好。
Cheerio 元素后插入
使用after()
,我们可以在标签后插入元素。
insert_after.js
const cheerio = require('cheerio');
const request = require('request');
request({
method: 'GET',
url: 'http://localhost:8000'
}, (err, res, body) => {
if (err) return console.error(err);
let $ = cheerio.load(body);
$('main').after('<footer>This is a footer</footer>')
console.log($.html());
});
在示例中,我们在main
元素之后插入一个footer
元素。
Cheerio 在元素上循环
使用each()
,我们可以循环遍历元素。
loop_elements.js
const cheerio = require('cheerio');
const request = require('request');
request({
method: 'GET',
url: 'http://localhost:8000'
}, (err, res, body) => {
if (err) return console.error(err);
let $ = cheerio.load(body);
let hobbies = [];
$('li').each(function (i, e) {
hobbies[i] = $(this).text();
});
console.log(hobbies);
});
该示例循环访问ul
的li
标签,并打印数组中元素的文本。
$ node loop_elements.js
[ 'Swimming',
'Tai Chi',
'Running',
'Web development',
'Reading',
'Music' ]
这是输出。
Cheerio 获取元素属性
可以使用attr()
函数检索属性。
attributes.js
const cheerio = require('cheerio');
const request = require('request');
request({
method: 'GET',
url: 'http://localhost:8000'
}, (err, res, body) => {
if (err) return console.error(err);
let $ = cheerio.load(body);
let fpEl = $('h1 + p');
let attrs = fpEl.attr();
console.log(attrs);
});
在示例中,我们获得了h1
的直接同级段落的属性。
$ node attributes.js
{ class: 'fpar' }
该段包含fpar
类。
Cheerio 过滤器
我们可以使用filter()
在元素上应用过滤器。
filtering.js
const cheerio = require('cheerio');
const request = require('request');
request({
method: 'GET',
url: 'http://localhost:8000'
}, (err, res, body) => {
if (err) return console.error(err);
let $ = cheerio.load(body);
let allEls = $('*');
let filteredEls = allEls.filter(function (i, el) {
// this === el
return $(this).children().length > 3;
});
let items = filteredEls.get();
items.forEach(e => {
console.log(e.name);
});
});
在示例中,我们找到了包含三个以上子元素的文档的所有元素。
let allEls = $('*');
*
选择器选择所有元素。
let filteredEls = allEls.filter(function (i, el) {
// this === el
return $(this).children().length > 3;
});
在检索到的元素上,我们应用过滤器。 仅当元素包含三个以上的子元素时,该元素才包含在过滤列表中。
let items = filteredEls.get();
items.forEach(e => {
console.log(e.name);
});
我们遍历过滤后的列表并打印元素的名称。
$ node filtering.js
head
main
ul
head
,main
和ul
元素包含三个以上的子代。 不包含body
,因为它仅包含一个直属子代。
在本教程中,我们使用 Cheerio 库在 JavaScript 中完成了 Web 抓取。
您可能也对以下相关教程感兴趣: JQuery 教程, Moment.js 教程,从 JavaScript 中的 URL 读取 JSON , JavaScript 贪食蛇教程 , Node Sass 教程, Lodash 教程。
Axios 教程
原文: http://zetcode.com/javascript/axios/
Axios 教程展示了如何使用 Axios 客户端库在 JavaScript 中生成请求。
Axios
Axios 是用于浏览器和 Node.js 的基于 Promise 的 HTTP 客户端。 Axios 使向 REST 端点发送异步 HTTP 请求和执行 CRUD 操作变得容易。 它可以在普通 JavaScript 中使用,也可以与 Vue 或 React 之类的库一起使用。
在本教程中,我们将在 Node.js 应用中使用 Axios。
安装 Axios
首先,我们安装 Axios。
$ node -v
v11.5.0
我们使用 Node.js 11.5 版。
$ npm init -y
我们启动一个新的 Node.js 应用。
$ npm i axios
我们使用npm i axios
命令安装 Axios。
Axios 响应对象
当我们向服务器发送请求时,它返回一个响应。 Axios 响应对象包括:
data
- 服务器返回的有效负载status
- 服务器返回的 HTTP 代码statusText
- 服务器返回的 HTTP 状态消息header
- 服务器发送的标头config
- 原始请求配置request
- 请求对象
带回调的 Axios GET 请求
在第一个示例中,我们创建一个简单的 GET 请求。 我们使用回调。
simple_get.js
const axios = require('axios');
axios.get('http://webcode.me').then(resp => {
console.log(resp.data);
});
我们生成一个简单的 GET 请求并显示输出。
const axios = require('axios');
包括 Axios 库。
axios.get('http://webcode.me').then(resp => {
console.log(resp.data);
});
使用get()
,我们发送一个 GET 请求。 我们从响应中输出数据。 数据是 HTML 代码。
$node simple_get.js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>My html page</title>
</head>
<body>
<p>
Today is a beautiful day. We go swimming and fishing.
</p>
<p>
Hello there. How are you?
</p>
</body>
</html>
这是输出。
带有异步/等待的 Axios GET 请求
下面的示例创建相同的请求。 这次我们使用async/await
语法。
simple_get.js
const axios = require('axios');
async function makeGetRequest() {
let res = await axios.get('http://webcode.me');
let data = res.data;
console.log(data);
}
makeGetRequest();
该示例使用async/await
语法创建一个简单的 GET 请求。
Axios HEAD 请求
HEAD 请求是没有消息正文的 GET 请求。 在 Axios 中,使用head()
创建 HEAD 请求。
head_request.js
const axios = require('axios');
async function makeHeadRequest() {
let res = await axios.head('http://webcode.me');
console.log(`Status: ${res.status}`)
console.log(`Server: ${res.headers.server}`)
console.log(`Date: ${res.headers.date}`)
}
makeHeadRequest();
该示例显示了通过 HEAD 请求生成的响应的状态,服务器名称,响应日期。
$ node head_request.js
Status: 200
Server: nginx/1.6.2
Date: Mon, 04 Feb 2019 15:08:56 GMT
这是输出。
Axios 基本 API
get()
,post()
或delete()
方法是基本 axios API 的便捷方法:axios(config)
和axios(url, config)
。
basic_api.js
const axios = require('axios');
async function makeRequest() {
const config = {
method: 'get',
url: 'http://webcode.me'
}
let res = await axios(config)
console.log(res.status);
}
makeRequest();
该示例向webcode.me
创建 GET 请求。
const config = {
method: 'get',
url: 'http://webcode.me'
}
我们在配置对象中指定请求的详细信息。
Axios 自定义标头
在下面的示例中,我们发送一个自定义标头。
custom_header.js
const axios = require('axios');
async function makeRequest() {
const config = {
method: 'get',
url: 'http://webcode.me',
headers: { 'User-Agent': 'Console app' }
}
let res = await axios(config)
console.log(res.request._header);
}
makeRequest();
该示例发送一个自定义的标头。
const config = {
method: 'get',
url: 'http://webcode.me',
headers: { 'User-Agent': 'Console app' }
}
自定义数据将添加到配置对象的headers
属性中。
console.log(res.request._header);
我们验证发送的数据。
$ node custom_header.js
GET / HTTP/1.1
Accept: application/json, text/plain, */*
User-Agent: Console app
Host: webcode.me
Connection: close
这是输出。
获取 Github 信息
许多在线服务包含公共 API。 在以下示例中,我们生成对 Github API 的请求。
github.js
const axios = require('axios');
async function getNumberOfFollowers() {
let res = await axios.get('https://api.github.com/users/janbodnar');
let nOfFollowers = res.data.followers;
let location = res.data.location;
console.log(`# of followers: ${nOfFollowers}`)
console.log(`Location: ${location}`)
}
getNumberOfFollowers();
在示例中,我们获得关注者的数量和用户的位置。
$ node github.js
# of followers: 44
Location: Bratislava
这是输出。
Axios POST 请求
使用post()
方法创建 POST 请求。
post_request.php
const axios = require('axios');
async function makePostRequest() {
let res = await axios.post('https://jsonplaceholder.typicode.com/posts');
console.log(`Status code: ${res.status}`);
console.log(`Status text: ${res.statusText}`);
console.log(`Request method: ${res.request.method}`);
console.log(`Path: ${res.request.path}`);
console.log(`Date: ${res.headers.date}`);
console.log(`Data: ${res.data}`);
}
makePostRequest();
该示例创建对在线测试服务的 POST 请求。
$ node post_request.js
Status code: 201
Status text: Created
Request method: POST
Path: /posts
Date: Mon, 04 Feb 2019 16:54:36 GMT
Data: [object Object]
这是输出。
Axios 下载图像
以下示例显示了如何使用 Axios 下载图像。
get_image.js
const axios = require('axios');
const fs = require('fs');
var config = {
responseType: 'stream'
};
let url = 'httpsimg.dog.ceo/breeds/setter-english/n02100735_4870.jpg';
async function getImage() {
let resp = await axios.get(url, config);
resp.data.pipe(fs.createWriteStream('image.jpg'));
}
getImage();
该示例从在线服务中检索图像,该服务保留了狗的图像。
const axios = require('axios');
const fs = require('fs');
我们包括axios
和fs
模块。
var config = {
responseType: 'stream'
};
我们在配置对象中指定响应类型。
let resp = await axios.get(url, config);
我们得到图像。
resp.data.pipe(fs.createWriteStream('image.jpg'));
借助fs
模块,我们将图像保存到磁盘。
Axios 多个请求
我们可以使用 Axios 一次创建多个请求。
multiple_requests.js
const axios = require('axios');
async function makeRequests() {
let [u1, u2] = await Promise.all([
axios.get('https://api.github.com/users/janbodnar'),
axios.get('https://api.github.com/users/symfony')
]);
console.log(`Jan Bodnar: ${u1.data.created_at}`);
console.log(`Symfony: ${u2.data.created_at}`);
}
makeRequests();
要发送多个请求,我们使用Promise.all()
方法。
$ node multiple_requests.js
Jan Bodnar: 2016-01-31T12:12:28Z
Symfony: 2009-10-24T04:05:23Z
这是输出。
将 Axios 与 JSON 服务器一起使用
JSONServer 是一个很棒的工具,它使我们能够轻松创建伪造的 REST API。
$ npm i -g json-server
我们安装json-server
。
users.json
{
"users": [
{
"id": 1,
"first_name": "Robert",
"last_name": "Schwartz",
"email": "rob23@gmail.com"
},
{
"id": 2,
"first_name": "Lucy",
"last_name": "Ballmer",
"email": "lucyb56@gmail.com"
},
{
"id": 3,
"first_name": "Anna",
"last_name": "Smith",
"email": "annasmith23@gmail.com"
},
{
"id": 4,
"first_name": "Robert",
"last_name": "Brown",
"email": "bobbrown432@yahoo.com"
},
{
"id": 5,
"first_name": "Roger",
"last_name": "Bacon",
"email": "rogerbacon12@yahoo.com"
}
]
}
这是我们的测试数据。
启动 JSON 服务器
JSON 服务器从我们已全局安装的json-server
启动。
$ json-server --watch data.json
--watch
选项用于指定服务器的数据。
$ curl localhost:3000/users/2/
{
"id": 2,
"first_name": "Lucy",
"last_name": "Ballmer",
"email": "lucyb56@gmail.com"
}
使用 curl 命令,使用户获得 ID 2。
发布用户
我们发布了一个新用户。
post_user.js
const axios = require('axios');
async function makePostRequest() {
params = {
id: 6,
first_name: 'Fred',
last_name: 'Blair',
email: 'freddyb34@gmail.com'
}
let res = await axios.post('http://localhost:3000/users/', params);
console.log(res.data);
}
makePostRequest();
该示例发布了一个新用户。
let res = await axios.post('http://localhost:3000/users/', params);
将post
参数作为第二个参数传递给post()
方法。
获取用户
我们从测试服务器获取用户。
get_users.js
const axios = require('axios');
async function makeGetRequest() {
let res = await axios.get('http://localhost:3000/users/');
let data = res.data;
console.log(data);
}
makeGetRequest();
该程序从我们的测试服务器检索所有用户。
$ node get_users.js
[ { id: 1,
first_name: 'Robert',
last_name: 'Schwartz',
email: 'rob23@gmail.com' },
{ id: 2,
first_name: 'Lucy',
last_name: 'Ballmer',
email: 'lucyb56@gmail.com' },
{ id: 3,
first_name: 'Anna',
last_name: 'Smith',
email: 'annasmith23@gmail.com' },
{ id: 4,
first_name: 'Robert',
last_name: 'Brown',
email: 'bobbrown432@yahoo.com' },
{ id: 5,
first_name: 'Roger',
last_name: 'Bacon',
email: 'rogerbacon12@yahoo.com' },
{ id: 6,
first_name: 'Fred',
last_name: 'Blair',
email: 'freddyb34@gmail.com' } ]
这是输出。
删除用户
使用delete()
删除资源。
delete_user.js
const axios = require('axios');
async function makePostRequest() {
let res = await axios.delete('http://localhost:3000/users/2/');
console.log(res.status);
}
makePostRequest();
该示例删除具有 ID 2 的用户。
在本教程中,我们使用了 JavaScript Axios 模块。
您可能也对以下相关教程感兴趣: JSON 服务器教程,笑话教程, Moment.js 教程,从 JavaScript 中的 URL 读取 JSON , JavaScript 贪食蛇教程, JQuery 教程, Node Sass 教程, Lodash 教程。
Jest 教程
标题: http://zetcode.com/javascript/jest/
Jest 教程展示了如何使用 Jest 框架在 JavaScript 应用中执行单元测试。
Jest
Jest JavaScript REST 框架,其重点是简单性。 Jest 是由 Facebook 工程师为其 React 项目创建的。
单元测试是一种软件测试,其中测试软件的各个单元(组件)。 单元测试的目的是验证软件的每个单元是否按设计执行。 单元是所有软件中最小的可测试部分。
模拟是一种技术,其中代码部分被模拟真实代码的虚拟实现所替代。 模拟有助于实现测试隔离。 模拟主要用于单元测试。
在我们的测试中,我们检查值是否满足某些条件。 expect()
函数为我们提供了许多匹配器,这些匹配器使我们可以验证不同的事物,例如toBe()
,toBeFalsy()
或toEqual()
。
在本教程中,我们在 Node 应用中使用 Jest。
安装 Jest
首先,我们安装 Jest。
$ node -v
v11.5.0
我们使用 Node 版本 11.5.0。
$ npm init -y
我们启动一个新的 Node 应用。
$ npm i --dev jest
我们用nmp i --dev jest
安装 Jest 模块。
$ npm i -g jsonserver
$ npm i axios
我们也将使用jsonserver
和axios
。
package.json
测试脚本运行jest
。
package.json
{
"name": "jest-test",
"version": "1.0.0",
"description": "",
"main": "main.js",
"scripts": {
"test": "jest --verbose"
},
"keywords": [],
"author": "Jan Bodnar",
"license": "ISC",
"devDependencies": {
"jest": "^24.0.0"
},
"dependencies": {
"axios": "^0.18.0"
}
}
缺省情况下,笑话仅提供基本输出。 要获得有关测试运行的更多信息,我们使用--verbose
标志。
Jest 运行测试
使用npm test
命令运行测试。 测试文件的名称中必须带有test
术语。
$ npm test
> jest-test@1.0.0 test C:\Users\Jano\Documents\js\jest-test
> jest
PASS ./math-utils.test.js
PASS ./arith.test.js
PASS ./arith-params.test.js
PASS ./arith-skip.test.js
PASS ./string-utils.test.js
PASS ./arith-mock.test.js
PASS ./users.test.js
Test Suites: 7 passed, 7 total
Tests: 2 skipped, 35 passed, 37 total
Snapshots: 0 total
Time: 5.19s
Ran all test suites.
这是使用 Jest 运行测试的示例输出。 这是一个简洁的输出。 有关更多信息,我们可以使用--verbose
选项。
要运行单个测试,我们可以使用npx jest testname
命令。
scripts:{
"test": "jest --verbose ./test-directory"
}
我们可以配置 Jest 在指定的测试目录中运行测试。
用 Jest 测试算术函数
以下是使用 Jest 降级单元测试的经典学术示例。
arith.js
const add = (a, b) => a + b;
const mul = (a, b) => a * b;
const sub = (a, b) => a - b;
const div = (a, b) => a / b;
module.exports = { add, mul, sub, div };
一个模块中有四个基本算术函数。
arith.test.js
const { add, mul, sub, div } = require('./arith');
test('2 + 3 = 5', () => {
expect(add(2, 3)).toBe(5);
});
test('3 * 4 = 12', () => {
expect(mul(3, 4)).toBe(12);
});
test('5 - 6 = -1', () => {
expect(sub(5, 6)).toBe(-1);
});
test('8 / 4 = 2', () => {
expect(div(8, 4)).toBe(2);
});
在arith.test.js
中,我们测试模块。 文件名包含测试词。 然后由玩笑挑出来。
test('2 + 3 = 5', () => {
expect(add(2, 3)).toBe(5);
});
我们使用test()
函数测试add()
方法。 第一个参数是测试的名称,第二个参数是要运行的函数。 我们正在测试add()
函数返回的样本数据正确答案。
$ npx jest arith.test.js
PASS ./arith.test.js
√ 2 + 3 = 5 (3ms)
√ 3 * 4 = 12 (6ms)
√ 5 - 6 = -1
√ 8 / 4 = 2 (1ms)
Test Suites: 1 passed, 1 total
Tests: 4 passed, 4 total
Snapshots: 0 total
Time: 10.981s
Ran all test suites matching /arith.test.js/i.
这是输出。
Jest 跳过测试
测试可能需要花费大量时间才能完成。 如果需要,我们可以跳过一些测试。
arith-skip.test.js
const { add, mul, sub, div } = require('./arith');
xtest('2 + 3 = 5', () => {
expect(add(2, 3)).toBe(5);
});
test.skip('3 * 4 = 12', () => {
expect(mul(3, 4)).toBe(12);
});
test('5 - 6 = -1', () => {
expect(sub(5, 6)).toBe(-1);
});
test('8 / 4 = 2', () => {
expect(div(8, 4)).toBe(2);
});
可以使用skip()
或使用x
前缀跳过测试。 在我们的例子中,前两个测试被跳过。
$ npx jest arith-skip.test.js
PASS ./arith-skip.test.js
√ 5 - 6 = -1 (2ms)
√ 8 / 4 = 2 (1ms)
○ skipped 2 tests
Test Suites: 1 passed, 1 total
Tests: 2 skipped, 2 passed, 4 total
Snapshots: 0 total
Time: 2.323s
Ran all test suites matching /arith-skip.test.js/i.
跳过了两个测试。
Jest 参数化测试
参数化测试允许我们使用不同的值多次运行相同的测试。 这使我们的测试功能更强大。
对于参数化测试,我们使用each()
全局函数。
arith-param.test.js
const { add, mul, sub, div } = require('./arith')
test.each([[1, 1, 2], [-1, 2, 1], [2, 1, 3]])(
'%i + %i equals %i', (a, b, expected) => {
expect(add(a, b)).toBe(expected);
},
);
test.each([[1, 1, 0], [-1, 2, -3], [2, 2, 0]])(
'%i - %i equals %i', (a, b, expected) => {
expect(sub(a, b)).toBe(expected);
},
);
test.each([[1, 1, 1], [-1, 2, -2], [2, 2, 4]])(
'%i * %i equals %i', (a, b, expected) => {
expect(mul(a, b)).toBe(expected);
},
);
test.each([[1, 1, 1], [-1, 2, -0.5], [2, 2, 1]])(
'%i / %i equals %i', (a, b, expected) => {
expect(div(a, b)).toBe(expected);
},
);
在这些测试中,我们使用不同的输入数据多次运行每个算术函数。
test.each([[1, 1, 2], [-1, 2, 1], [2, 1, 3]])(
'%i + %i equals %i', (a, b, expected) => {
expect(add(a, b)).toBe(expected);
},
);
each()
方法接收一个数组数组,该数组的参数将传递给每一行的测试函数。 %i
是需要整数的格式说明符。 这是针对--verbose
选项显示的输出的。
$ npx jest arith-params.test.js
PASS ./arith-params.test.js
√ 1 + 1 equals 2 (3ms)
√ -1 + 2 equals 1 (1ms)
√ 2 + 1 equals 3
√ 1 - 1 equals 0
√ -1 - 2 equals -3
√ 2 - 2 equals 0
√ 1 * 1 equals 1 (1ms)
√ -1 * 2 equals -2
√ 2 * 2 equals 4
√ 1 / 1 equals 1 (1ms)
√ -1 / 2 equals 0
√ 2 / 2 equals 1
Test Suites: 1 passed, 1 total
Tests: 12 passed, 12 total
Snapshots: 0 total
Time: 1.759s
Ran all test suites matching /arith-params.test.js/i.
这是输出。
Jest
beforeAll()
函数是测试设置的一部分。 它会在运行此文件中的任何测试之前运行一个函数。 如果函数返回一个Promise
或是一个生成器,则 Jest 在运行测试之前等待该Promise
解析。
math-utils.js
const sum = (vals) => {
let sum = 0;
vals.forEach((val) => {
sum += val;
});
return sum;
}
const positive = (vals) => {
return vals.filter((x) => { return x > 0; });
}
const negative = (vals) => {
return vals.filter((x) => { return x < 0; });
}
module.exports = { sum, positive, negative };
我们有一个math-utils
模块,其中包含三个函数:sum()
,positive()
和negative()
。
math-utils.test.js
const { sum, positive, negative } = require('./math-utils');
let vals;
let sum_of_vals;
let pos_vals;
let neg_vals;
beforeAll(() => {
pos_vals = [2, 1, 3];
neg_vals = [-2, -1, -1];
vals = pos_vals.concat(neg_vals);
sum_of_vals = vals.reduce((x, y) => x + y, 0);
})
test('the sum of vals should be 2', () => {
expect(sum(vals)).toBe(sum_of_vals);
});
test('should get positive values', () => {
expect(positive(vals)).toEqual(pos_vals);
});
test('should get negative values', () => {
expect(negative(vals)).toEqual(neg_vals);
});
在测试文件中,我们使用beforeAll()
函数的测试运行之前初始化测试数据。
test('should get positive values', () => {
expect(positive(vals)).toEqual(pos_vals);
});
为了测试positive()
函数,我们使用toEqual()
匹配器。 我们测试该函数返回的正值数组等于预定义的测试值数组。
Jest 分组测试
在 Jest 中,测试使用describe()
分组为单位。 它创建一个将几个相关测试组合在一起的模块。
string-utils.js
const isPalindrome = (string) => string == string.split('').reverse().join('');
const isAnagram = (w1, w2) => {
const regularize = (word) => {
return word.toLowerCase().split('').sort().join('').trim();
}
return regularize(w1) === regularize(w2);
}
module.exports = {isPalindrome, isAnagram};
我们的string-utils.js
模块具有两个函数:isPalindrome()
和isAnagram()
。
math-utils.js
const sum = (vals) => {
let sum = 0;
vals.forEach((val) => {
sum += val;
});
return sum;
}
const positive = (vals) => {
return vals.filter((x) => { return x > 0; });
}
const negative = (vals) => {
return vals.filter((x) => { return x < 0; });
}
module.exports = { sum, positive, negative };
我们又有了math-utils.js
模块。
groups.test.js
const { sum, positive, negative } = require('./math-utils');
const { isPalindrome, isAnagram } = require('./string-utils');
describe('testing math utilities', () => {
let vals;
let sum_of_vals;
let pos_vals;
let neg_vals;
beforeAll(() => {
pos_vals = [2, 1, 3];
neg_vals = [-2, -1, -1];
vals = pos_vals.concat(neg_vals);
sum_of_vals = vals.reduce((x, y) => x + y, 0);
})
test('the sum of vals should be 2', () => {
expect(sum(vals)).toBe(sum_of_vals);
});
test('should get positive values', () => {
expect(positive(vals)).toEqual(pos_vals);
});
test('should get negative values', () => {
expect(negative(vals)).toEqual(neg_vals);
});
});
describe('testing string utilities', () => {
test.each(["racecar", "radar", "level", "refer", "deified", "civic"])(
'testing %s for palindrome', (word) => {
expect(isPalindrome(word)).toBeTruthy();
},
);
test.each([["arc", "car"], ["cat", "act"], ["cider", "cried"]])(
'testing if %s and %s are anagrams ', (word1, word2) => {
expect(isAnagram(word1, word2)).toBeTruthy();
},
);
});
使用describe()
,我们为字符串和数学工具创建了两个独立的测试组。 例如,beforeAll()
仅适用于数学工具。
$ npx jest groups.test.js
PASS ./groups.test.js
testing math utilities
√ the sum of vals should be 2 (3ms)
√ should get positive values (1ms)
√ should get negative values
testing string utilities
√ testing racecar for palindrome (1ms)
√ testing radar for palindrome
√ testing level for palindrome
√ testing refer for palindrome
√ testing deified for palindrome (1ms)
√ testing civic for palindrome
√ testing if arc and car are anagrams
√ testing if cat and act are anagrams
√ testing if cider and cried are anagrams (1ms)
Test Suites: 1 passed, 1 total
Tests: 12 passed, 12 total
Snapshots: 0 total
Time: 1.786s
Ran all test suites matching /groups.test.js/i.
我们运行测试。
Jest 测试 Axios
在以下部分中,我们将测试使用 Axios 库的 JavaScript 代码。 首先,我们安装了axios
和json-server
模块。
users.json
{
"users": [
{
"id": 1,
"first_name": "Robert",
"last_name": "Schwartz",
"email": "rob23@gmail.com"
},
{
"id": 2,
"first_name": "Lucy",
"last_name": "Ballmer",
"email": "lucyb56@gmail.com"
},
{
"id": 3,
"first_name": "Anna",
"last_name": "Smith",
"email": "annasmith23@gmail.com"
},
{
"id": 4,
"first_name": "Robert",
"last_name": "Brown",
"email": "bobbrown432@yahoo.com"
},
{
"id": 5,
"first_name": "Roger",
"last_name": "Bacon",
"email": "rogerbacon12@yahoo.com"
}
]
}
这是 JSON 服务器的一些伪造数据。
users.js
const axios = require('axios');
class Users {
static async all() {
let res = await axios.get('http://localhost:3000/users');
return res;
}
}
module.exports = Users;
users.js
模块使用axios
检索数据。 我们将测试该模块。
users-app.js
const Users = require('./users');
async function showData() {
let res = await Users.all();
console.log(res.data);
}
showData();
console.log('finished')
users-app.js
是使用users.js
模块获取和输出数据的应用。
$ json-server --watch users.json
我们开始json-server
。
$ node users-app.js
finished
[ { id: 1,
first_name: 'Robert',
last_name: 'Schwartz',
email: 'rob23@gmail.com' },
{ id: 2,
first_name: 'Lucy',
last_name: 'Ballmer',
email: 'lucyb56@gmail.com' },
{ id: 3,
first_name: 'Anna',
last_name: 'Smith',
email: 'annasmith23@gmail.com' },
{ id: 4,
first_name: 'Robert',
last_name: 'Brown',
email: 'bobbrown432@yahoo.com' },
{ id: 5,
first_name: 'Roger',
last_name: 'Bacon',
email: 'rogerbacon12@yahoo.com' } ]
我们运行该应用。
users.test.js
const axios = require('axios');
const Users = require('./users');
jest.mock('axios');
test('should fetch users', () => {
const users = [{
"id": 1,
"first_name": "Robert",
"last_name": "Schwartz",
"email": "rob23@gmail.com"
}, {
"id": 2,
"first_name": "Lucy",
"last_name": "Ballmer",
"email": "lucyb56@gmail.com"
}];
const resp = { data : users };
axios.get.mockImplementation(() => Promise.resolve(resp));
Users.all().then(resp => expect(resp.data).toEqual(users));
});
该测试文件测试users.js
模块。
jest.mock('axios');
我们模拟模块。
const users = [{
"id": 1,
"first_name": "Robert",
"last_name": "Schwartz",
"email": "rob23@gmail.com"
}, {
"id": 2,
"first_name": "Lucy",
"last_name": "Ballmer",
"email": "lucyb56@gmail.com"
}];
const resp = { data : users };
这是模拟模块将返回的响应。
axios.get.mockImplementation(() => Promise.resolve(resp));
模拟实现返回带有响应的promise
。
Users.all().then(resp => expect(resp.data).toEqual(users));
我们测试了模拟的Users.all()
函数。
$ npx jest users.test.js
PASS ./users.test.js
√ should fetch users (4ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 1.818s
Ran all test suites matching /users.test.js/i.
我们进行测试。
在本教程中,我们使用 Jest 在 JavaScript 应用中进行单元测试。
您可能也对以下相关教程感兴趣: Moment.js 教程, Axios 教程, Faker.js 教程, JSONServer 教程 ,从 JavaScript 中的 URL 读取 JSON , Node Sass 教程, Lodash 教程。
JavaScript 正则表达式
原文: http://zetcode.com/javascript/regularexpressions/
JavaScript 正则表达式教程展示了如何在 JavaScript 中使用正则表达式。
正则表达式用于文本搜索和更高级的文本操作。 正则表达式是内置工具,如grep
,sed
,文本编辑器(如 vi,emacs),编程语言(如 JavaScript,Perl 和 Python)。
JavaScript 正则表达式
在 JavaScript 中,我们使用斜线//
或RegExp
对象构建正则表达式。
模式是一个正则表达式,用于定义我们正在搜索或操纵的文本。 它由文本文字和元字符组成。 元字符是控制正则表达式计算方式的特殊字符。 例如,使用\s
,我们搜索空白。
创建模式后,可以使用其中一个函数将模式应用于文本字符串。 函数包括test()
,match()
,search()
和replace()
。
下表显示了一些正则表达式:
正则表达式 | 含义 |
---|---|
. |
匹配任何单个字符。 |
? |
一次匹配或根本不匹配前面的元素。 |
+ |
与前面的元素匹配一次或多次。 |
* |
与前面的元素匹配零次或多次。 |
^ |
匹配字符串中的起始位置。 |
` | 正则表达式 |
--- | --- |
. |
匹配任何单个字符。 |
? |
一次匹配或根本不匹配前面的元素。 |
+ |
与前面的元素匹配一次或多次。 |
* |
与前面的元素匹配零次或多次。 |
^ |
匹配字符串中的起始位置。 |
匹配字符串中的结束位置。 | |
| |
备用运算符。 |
[abc] |
匹配a 或b 或c 。 |
[a-c] |
范围; 匹配a 或b 或c 。 |
[^abc] |
否定,匹配除a 或b 或c 之外的所有内容。 |
\s |
匹配空白字符。 |
\w |
匹配单词字符; 等同于[a-zA-Z_0-9] |
测试函数
test()
方法执行搜索以查找正则表达式和指定字符串之间的匹配项。 它返回true
或false
。
test_fun.js
let words = ['book', 'bookworm', 'Bible',
'bookish','cookbook', 'bookstore', 'pocketbook'];
let pattern = /book/;
words.forEach(word => {
if (pattern.test(word)) {
console.log(`the ${word} matches`);
}
});
在示例中,我们有一个单词数组。 模式将在每个单词中寻找一个"book"
字符串。
let pattern = /book/;
我们使用斜线创建一个模式。 正则表达式由四个普通字符组成。
words.forEach(word => {
if (pattern.test(word)) {
console.log(`the ${word} matches`);
}
});
我们遍历数组并调用test()
函数。 如果模式与单词匹配,则返回true
。
$ node test_fun.js
the book matches
the bookworm matches
the bookish matches
the cookbook matches
the bookstore matches
the pocketbook matches
这些单词与模式匹配。
search()
函数
search()
函数返回正则表达式与给定字符串之间的第一个匹配项的索引。 如果找不到匹配项,则返回 -1。
search_fun.js
let text = 'I saw a fox in the wood. The fox had red fur.';
let pattern = /fox/;
let idx = text.search(pattern);
console.log(`the term was found at index: ${idx}`);
在该示例中,我们找出"fox"
项的第一个匹配项的索引。
$ node search_fun.js
the term was found at index: 8
这是输出。
exec
函数
exec()
执行搜索以查找指定字符串中的匹配项。 它返回一个带有匹配信息的对象。
exec_fun.js
let words = ['book', 'bookworm', 'Bible',
'bookish', 'cookbook', 'bookstore', 'pocketbook'];
let pattern = /book/;
words.forEach(word => {
let res = pattern.exec(word);
if (res) {
console.log(`${res} matches ${res.input} at index: ${res.index}`);
}
});
在示例中,我们使用exec()
将模式应用于输入字符串。
if (res) {
console.log(`${res} matches ${res.input} at index: ${res.index}`);
}
我们打印有关比赛的信息。 它包括比赛开始的索引。
$ node exec_fun.js
book matches book at index: 0
book matches bookworm at index: 0
book matches bookish at index: 0
book matches cookbook at index: 4
book matches bookstore at index: 0
book matches pocketbook at index: 6
这是输出。
match()
函数
当将模式与输入字符串进行匹配时,match()
函数将检索匹配项。
match_fun.js
let text = 'I saw a fox in the wood. The fox had red fur.';
let pattern = /fox/g;
let found = text.match(pattern);
console.log(`There are ${found.length} matches`);
在该示例中,我们找出"fox"
项的出现次数。
let pattern = /fox/g;
g
字符是一个标志,可查找所有出现的术语。 通常,当找到第一个匹配项时,搜索结束。
$ node match_fun.js
There are 2 matches
我们在字符串中找到了两个"fox"
术语。
replace()
函数
replace()
函数返回一个新字符串,该字符串的部分或全部匹配都由替换字符串替换。
replace_fun.js
let text = 'He has gray hair; gray clouds gathered above us.'
let pattern = /gray/g;
let new_text = text.replace(pattern, 'grey');
console.log(new_text);
在示例中,我们从输入字符串中创建了一个新字符串,在此我们将"gray"
单词替换为'grey'
。
let pattern = /gray/g;
g
字符是一个标志,可查找所有出现的术语。
$ node replacing.js
He has grey hair; grey clouds gathered above us.
这是输出。
不区分大小写的匹配
要启用不区分大小写的搜索,我们使用i
标志。
case_insensitive.js
let words = ['dog', 'Dog', 'DOG', 'Doggy'];
let pattern = /dog/i;
words.forEach(word => {
if (pattern.test(word)) {
console.log(`the ${word} matches`);
}
});
在示例中,无论大小写如何,我们都将模式应用于单词。
let pattern = /dog/i;
附加i
标志,我们进行不区分大小写的搜索。
$ node case_insensitive.js
the dog matches
the Dog matches
the DOG matches
the Doggy matches
执行不区分大小写的搜索时,所有四个单词都与模式匹配。
点元字符
点(。)元字符代表文本中的任何单个字符。
dot_meta.js
let words = ['seven', 'even', 'prevent', 'revenge', 'maven',
'eleven', 'amen', 'event'];
let pattern = /..even/;
words.forEach(word => {
if (pattern.test(word)) {
console.log(`the ${word} matches`);
}
});
在示例中,我们在一个数组中有八个单词。 我们在每个单词上应用一个包含两个点元字符的模式。
$ node dot_meta.js
the prevent matches
the eleven matches
有两个与模式匹配的单词。
问号元字符
问号(?)元字符是与上一个元素零或一次匹配的量词。
question_mark_meta.js
let words = ['seven', 'even', 'prevent', 'revenge', 'maven',
'eleven', 'amen', 'event'];
let pattern = /.?even/;
words.forEach(word => {
if (pattern.test(word)) {
console.log(`the ${word} matches`);
}
});
在示例中,我们在点字符后添加问号。 这意味着在模式中我们可以有一个任意字符,也可以在那里没有任何字符。
$ node question_mark_meta.js
the seven matches
the even matches
the prevent matches
the revenge matches
the eleven matches
the event matches
这次,没有前一个字符的偶数和事件字也匹配。
锚点
锚点匹配给定文本内字符的位置。 当使用^锚时,匹配必须发生在字符串的开头,而当使用$锚时,匹配必须发生在字符串的结尾。
anchors.js
let sentences = ['I am looking for Jane.',
'Jane was walking along the river.',
'Kate and Jane are close friends.'];
let pattern = /^Jane/;
sentences.forEach(sentence => {
if (pattern.test(sentence)) {
console.log(`${sentence}`);
}
});
在示例中,我们有三个句子。 搜索模式为^Jane
。 该模式检查"Jane"
字符串是否位于文本的开头。 Jane\.
将在句子结尾处查找"Jane"
。
精确匹配
可以通过在锚点^和$之间放置术语来进行精确匹配。
exact_match.js
let words = ['seven', 'even', 'prevent', 'revenge', 'maven',
'eleven', 'amen', 'event']
let pattern = /^even$/;
words.forEach(word => {
if (pattern.test(word)) {
console.log(`the ${word} matches`);
}
});
在示例中,我们寻找'even'
项的精确匹配。
$ node exact_match.js
the even matches
这是输出。
字符类
字符类定义了一组字符,任何字符都可以出现在输入字符串中以使匹配成功。
character_class.js
let words = ['a gray bird', 'grey hair', 'great look'];
let pattern = /gr[ea]y/;
words.forEach(word => {
if (pattern.test(word)) {
console.log(`${word}`);
}
});
在该示例中,我们使用字符类同时包含灰色和灰色单词。
let pattern = /gr[ea]y/;
[ea]
类允许在模式中使用'e'或'a'字符。
命名字符类
有一些预定义的字符类。 \s
与空白字符[\t\n\t\f\v]
匹配,\d
与数字[0-9]
匹配,\w
与单词字符[a-zA-Z0-9_]
匹配。
named_character_class.js
let text = 'We met in 2013\. She must be now about 27 years old.';
let pattern = /\d+/g;
while ((found = pattern.exec(text)) !== null) {
console.log(`found ${found} at index ${found.index}`);
}
在示例中,我们在文本中搜索数字。
let pattern = /\d+/g;
\d+
模式在文本中查找任意数量的数字集。 g
标志使搜索在第一次出现时不会停止。
while ((found = pattern.exec(text)) !== null) {
console.log(`found ${found} at index ${found.index}`);
}
要查找所有匹配项,我们在while
循环中使用exec()
函数。
$ node named_character_class.js
found 2013 at index 10
found 27 at index 38
这是输出。
在下面的示例中,我们有使用match()
函数的替代解决方案。
count_numbers.js
let text = 'I met her in 2012\. She must be now about 27 years old.'
let pattern = /\d+/g;
var found = text.match(pattern);
console.log(`There are ${found.length} numbers`);
found.forEach((num, i) => {
console.log(`match ${++i}: ${num}`);
});
要计算数字,我们使用\d
命名类。
$ node count_numbers.js
There are 2 numbers
match 1: 2012
match 2: 27
这是输出。
数词
在下一个示例中,我们计算文本中的单词数。
count_words.js
let text = 'The Sun was shining; I went for a walk.';
let pattern = /\w+/g;
let found = text.match(pattern);
console.log(`There are ${found.length} words`);
\w
名称集代表一个字字符。
let pattern = /\w+/g;
该模式使用量词(+)搜索一个或多个单词字符。 全局标志使搜索查找字符串中的所有单词。
console.log(`There are ${found.length} words`);
我们将单词数打印到控制台。
$ node count_words.js
There are 9 words
这是输出。
交替
交替运算符| 创建具有多种选择的正则表达式。
alternations.js
let words = ["Jane", "Thomas", "Robert",
"Lucy", "Beky", "John", "Peter", "Andy"];
let pattern = /Jane|Beky|Robert/;
words.forEach(word => {
if (pattern.test(word)) {
console.log(`the ${word} matches`);
}
});
列表中有八个名称。
let pattern = /Jane|Beky|Robert/;
此正则表达式查找Jane
,"Beky"
或"Robert"
字符串。
捕获组
捕获组是一种将多个字符视为一个单元的方法。 通过将字符放置在一组圆括号内来创建它们。 例如,(book)
是包含'b', 'o', 'o', 'k'
字符的单个组。
捕获组技术使我们能够找出字符串中与正则表达式模式匹配的那些部分。
capturing_groups.js
content = `<p>The <code>Pattern</code> is a compiled
representation of a regular expression.</p>`;
let pattern = /(<\/?[a-z]*>)/g;
let found = content.match(pattern);
found.forEach(tag => {
console.log(tag);
});
该代码示例通过捕获一组字符来打印提供的字符串中的所有 HTML 标签。
let found = content.match(pattern);
为了找到所有标签,我们使用match()
方法。
$ ./capturing_groups.js
<p>
<code>
</code>
</p>
我们找到了四个 HTML 标签。
JavaScript 正则表达式电子邮件示例
在以下示例中,我们创建一个用于检查电子邮件地址的正则表达式模式。
emails.js
let emails = ["luke@gmail.com", "andy@yahoocom",
"34234sdfa#2345", "f344@gmail.com"];
let pattern = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9-]+\.[a-zA-Z.]{2,18}$/;
emails.forEach(email => {
if (pattern.test(email)) {
console.log(`${email} matches`);
} else {
console.log(`${email} does not match`);
}
})
本示例提供了一种可能的解决方案。
let pattern = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9-]+\.[a-zA-Z.]{2,18}$/;
前^
和后$
个字符提供精确的模式匹配。 模式前后不允许有字符。 电子邮件分为五个部分。 第一部分是本地部分。 这通常是公司,个人或昵称的名称。 [a-zA-Z0-9._-]+
列出了我们可以在本地部分使用的所有可能字符。 它们可以使用一次或多次。
第二部分由文字@
字符组成。 第三部分是领域部分。 通常是电子邮件提供商的域名,例如 yahoo 或 gmail。 [a-zA-Z0-9-]+
是一个字符类,提供可在域名中使用的所有字符。 +
量词允许使用这些字符中的一个或多个。
第四部分是点字符。 它前面带有转义字符(\
),以获取文字点。
最后一部分是顶级域名:[a-zA-Z.]{2,18}
。 顶级域可以包含 2 到 18 个字符,例如sk, net, info, travel, cleaning, travelinsurance
。 最大长度可以为 63 个字符,但是今天大多数域都少于 18 个字符。 还有一个点字符。 这是因为某些顶级域包含两个部分: 例如co.uk
。
$ node emails.js
luke@gmail.com matches
andy@yahoocom does not match
34234sdfa#2345 does not match
f344@gmail.com matches
这是输出。
在本章中,我们介绍了 JavaScript 中的正则表达式。
您可能也对以下相关教程感兴趣: JavaScript 数组教程和 Big.js 教程。
用 JavaScript 创建对象
原文: http://zetcode.com/javascript/createobject/
JavaScript 创建对象教程展示了如何在 JavaScript 中创建对象。 可以使用对象字面值,函数构造器或类定义来创建对象。 通常使用创建性生成器和工厂设计模式来创建对象。
在本教程中,我们使用 Node.js 执行示例。
对象字面值
在对象字面值表示法中,我们将用逗号分隔的对象属性放在大括号{}
中。
属性名称和值用冒号分隔。
object_literal.js
const person = {
firstName: 'John',
lastName: 'Doe',
email: 'jdoe@example.com',
info: function() {
return `${this.firstName} ${this.lastName}, ${this.email}`
}
};
console.log(person.info());
该示例使用字面值表示法创建一个对象。
$ node object_literal.js
John Doe, jdoe@example.com
这是输出。
对象构造器
可以使用new Object()
构造器创建对象。 然后使用点运算符动态添加属性。
object_constructor.js
let person = new Object();
person.firstName = "John";
person.lastName = "Doe";
person.email = 'jdoe@example.com';
person.info = function(){
return `${this.firstName} ${this.lastName}, ${this.email}`;
};
console.log(person.info());
该示例使用Object
构造器创建一个对象。
函数构造器
使用function
关键字创建函数构造器。 它以值作为参数。 使用this
关键字设置属性。 使用this
和function
关键字创建方法。 使用new
关键字创建新对象。
function_constructor.js
function Person(firstName, lastName, email) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.info = function() {
return `${this.firstName} ${this.lastName}, ${this.email}`;
}
}
let person = new Person('John', 'Doe', 'jdoe@example.com');
console.log(person.info());
该示例使用函数构造器创建一个对象。
类定义
对象用class
关键字定义,并用new
关键字生成。 这是创建从诸如 C# 或 Java 之类的语言已知的对象的经典方法。 JavaScript 使用constructor
关键字定义对象构造器。 使用this
关键字设置属性。
class_definition.js
class Person {
constructor(firstName, lastName, email) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
info() {
return `${this.firstName} ${this.lastName}, ${this.email}`;
}
}
let person = new Person('John', 'Doe', 'jdoe@example.com');
console.log(person.info());
该示例使用类定义创建对象。
构建器模式
构建器模式是一种用于创建对象的创新性设计模式。 它通过提供逐步的方法,使用简单的对象来构建复杂的对象。 构建器模式使用流利的 API 创建对象。
builder_pattern.js
let Person = function (firstName, lastName, email) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
let PersonBuilder = function () {
let firstName;
let lastName;
let email;
return {
setFirstName: function (firstName) {
this.firstName = firstName;
return this;
},
setLastName: function (lastName) {
this.lastName = lastName;
return this;
},
setEmail: function (email) {
this.email = email;
return this;
},
info: function () {
return `${this.firstName} ${this.lastName}, ${this.email}`;
},
build: function () {
return new Person(firstName, lastName, email);
}
};
};
var person = new PersonBuilder().setFirstName('John').setLastName('Doe')
.setEmail('jdoe@example.com');
console.log(person.info());
该示例使用构建器设计模式创建一个对象。
工厂模式
使用工厂模式,我们可以在不将创建逻辑暴露给客户端的情况下创建对象。
factory_pattern.js
const personFactory = (firstName, lastName, email) => {
return {
firstName: firstName,
lastName: lastName,
email: email,
info() {
return `${this.firstName} ${this.lastName}, ${this.email}`;
}
};
};
let person = personFactory('John', 'Doe', 'jdoe@example.com');
console.log(person.info());
该示例使用工厂模式创建一个对象。
在本教程中,我们使用不同的语法创建了 JavaScript 对象。 我们还介绍了两种创新的设计模式,即构建器模式和工厂模式。
您可能也对以下相关教程感兴趣: JavaScript 构建器模式教程,或列出所有 JavaScript 教程。
Big.js 教程
原文: http://zetcode.com/javascript/bigjs/
Big.js 教程展示了如何使用 Big.js 模块在 JavaScript 中使用任意精度的大十进制算术运算。
Big.js
Big.js 是一个小型,快速的 JavaScript 库,用于任意精度的十进制算术。
在本教程中,我们在 Node 应用中使用 Big.js。
安装 Big.js
首先,我们安装 Big.js。
$ nodejs -v
v9.11.2
我们使用 Node 版本 9.11.2。
$ npm init
我们启动一个新的 Node 应用。
$ npm i big.js
我们使用npm i big.js
命令安装 Big.js。
JavaScript 数字精度错误
在第一个示例中,我们显示 JavaScript 数字对于执行任意精度算术不是精确的。
count_currency.js
var sum = 0;
// two euros fifty-five cents
var amount = 2.55;
for (let i = 0; i < 100000; i++) {
sum += amount;
}
console.log(sum);
在此示例中,我们将两欧元五十五美分十万倍。
$ nodejs numbers.js
254999.9999995398
我们的计算有误。
Big.js 示例
在下一个示例中,我们使用 Big.js 更正错误。
big_decimal.js
const Big = require('big.js');
var val = new Big(0.0);
var amount = new Big(2.55);
var sum = val.plus(amount).times(100000);
console.log(sum.toFixed(2));
使用 Big.js 库,计算非常精确。
const Big = require('big.js');
我们加载big.js
模块。
var val = new Big(0.0);
var amount = new Big(2.55);
我们创建两个大十进制值。
var sum = val.plus(amount).times(100000);
我们将值相加 100000 次。 请注意,大十进制值是不可变的,因此我们生成一个新变量。
$ nodejs big_decimal.js
255000.00
这是输出。
在本教程中,我们使用Big.js
库对任意精度算法进行了处理。
您可能也对以下相关教程感兴趣: Moment.js 教程,从 JavaScript 中的 URL 读取 JSON , JavaScript 贪食蛇教程, JQuery 教程 , Node Sass 教程, Lodash 教程。
Moment.js 教程
原文: http://zetcode.com/javascript/momentjs/
Moment.js 教程展示了如何通过 Moment.js 模块在 JavaScript 中使用日期和时间。
Moment.js
Moment.js 是一个轻量级的 JavaScript 日期库,用于解析,验证,操作和格式化日期。
在本教程中,我们在 Node 应用中使用 Moment.js。 Day.js 教程中介绍了类似的 Day.js 库。
安装 Moment.js
首先,我们安装 Moment.js。
$ nodejs -v
v9.11.2
我们使用 Node 版本 9.11.2。
$ npm init
我们启动一个新的 Node 应用。
$ npm i moment
我们使用npm i moment
命令安装 Moment.js。
Moment.js 今天的日期
在第一个示例中,我们使用 Moment.js 获取今天的日期。
today.js
const moment = require('moment');
let now = moment();
console.log(now.format());
该示例打印今天的日期和时间。
const moment = require('moment');
我们加载 Moment.js 库。
let now = moment();
我们使用moment()
获得当前本地日期时间对象。
console.log(now.format());
我们使用format()
格式化输出。 默认情况下,我们使用长日期时间格式。
$ node today.js
2018-07-01T16:32:53+02:00
这是 ISO 标准格式。 日期和时间部分用 T 字符分隔。 该字符串以时区结尾。
创建 Moment.js 对象
我们可以使用几种方法来创建日期和时间 Moment.js 对象。 这些对象必须稍后再格式化为人类可读的格式。
create_objects.js
const moment = require('moment');
let d1 = moment("2018-06-03");
console.log(d1.format('ll'));
let d2 = moment([2017, 11, 23]);
console.log(d2.format('ll'));
let d3 = moment({ year :2010, month :3, day :5,
hour :15, minute :10, second :3, millisecond :123});
console.log(d3.format('ll'));
let d4 = moment(1530471537000);
console.log(d4.format('ll'));
let d5 = moment(new Date(2011, 11, 22));
console.log(d5.format('ll'));
该示例以五种不同方式创建日期和时间对象。
let d1 = moment("2018-06-03");
我们从字符串创建一个矩对象。
let d2 = moment([2017, 11, 23]);
console.log(d2.format('ll'));
在这里,从数组创建一个矩对象。
let d3 = moment({ year :2010, month :3, day :5,
hour :15, minute :10, second :3, millisecond :123});
console.log(d3.format('ll'));
我们可以使用 JSON 对象创建力矩对象。
let d4 = moment(1530471537000);
console.log(d4.format('ll'));
我们使用 unix 时间戳(以毫秒为单位)定义矩对象。
let d5 = moment(new Date(2011, 11, 22));
console.log(d5.format('ll'));
最后,我们使用 JavaScript 内置的 Date 对象定义一个矩对象。
$ node create_moment_objects.js
Jun 3, 2018
Dec 23, 2017
Apr 5, 2010
Jul 1, 2018
Dec 22, 2011
这是输出。
Moment.js 格式化日期时间
Moment.js 对象使用format()
函数格式化。 也有本地化格式的选项。
format.js
const moment = require('moment');
let now = moment();
console.log("ISO")
console.log(now.format());
console.log("\nTime")
console.log(now.format("HH:mm:ss"));
console.log(now.format("h:mm:ss a"));
console.log("\nDate")
console.log(now.format("dddd, MMMM Do YYYY"));
console.log(now.format("YYYY-MM-DD"));
console.log("\nLocalized")
console.log(now.format("LT"));
console.log(now.format("LTS"));
console.log(now.format("LTS"));
console.log(now.format("L"));
console.log(now.format("l"));
该示例使用 Moment 的format()
函数格式化日期和时间。
$ node format.js
ISO
2018-07-03T10:09:47+02:00
Time
10:09:47
10:09:47 am
Date
Tuesday, July 3rd 2018
2018-07-03
Localized
10:09 AM
10:09:47 AM
10:09:47 AM
07/03/2018
7/3/2018
这是一个示例输出。
Moment.js 计算日期时间差
使用diff()
函数,我们可以计算两个日期时间对象之间的差。
difference.js
const moment = require('moment');
let d1 = moment('2018-06-12');
let d2 = moment('2018-06-28');
let days = d2.diff(d1, 'days');
console.log(`Difference in days: ${days}`);
let hours = d2.diff(d1, 'hours');
console.log(`Difference in hours: ${hours}`);
该示例以天和小时为单位计算两个矩对象之间的差异。
let days = d2.diff(d1, 'days');
第二个参数表明输出将以天为单位。
$ node difference.js
Difference in days: 16
Difference in hours: 384
这是输出。
Borodino 战役是 1812 年 9 月 7 日在法国入侵俄罗斯期间的拿破仑战争中进行的战斗。
borodino.js
const moment = require('moment');
let borodinoBattle = moment('1812-09-07');
let now = moment();
let days = now.diff(borodinoBattle, 'days');
console.log(`On ${now.format('ll')}, ${days} days have passed since the Borodino battle.`);
在此示例中,我们计算了从那时起经过的天数。
$ node borodino.js
On Jul 3, 2018, 75174 days have passed since the Borodino battle.
这是一个示例输出。
Moment.js 日期时间算法
add()
函数用于将日期和时间添加到矩对象,而subtract()
函数用于从矩对象减去日期和时间。
add_sub.js
const moment = require('moment');
let now = moment();
console.log(`Now: ${now.format('ll')}`);
now.add('3', 'days');
console.log(`Adding three days: ${now.format('ll')}`);
now.subtract('2', 'years');
console.log(`Subtracting 2 years: ${now.format('ll')}`);
在示例中,我们将三天相加减去两年。
now.add('3', 'days');
...
now.subtract('2', 'years');
add()
和subtract()
方法的第二个参数是单位类型。
$ node add_sub.js
Now: Jul 1, 2018
Adding three days: Jul 4, 2018
Subtracting 2 years: Jul 4, 2016
这是输出。
Moment.js 日期时间部分
在下面的示例中,我们获取了当前日期时间的部分。
parts.js
const moment = require('moment');
let now = moment();
let year = now.get('year');
let month = now.get('month'); // 0 to 11
let date = now.get('date');
let hour = now.get('hour');
let minute = now.get('minute');
let second = now.get('second');
let millisecond = now.get('millisecond');
console.log("Year: " + year);
console.log("Month: " + month);
console.log("Date: " + date);
console.log("Hour: " + hour);
console.log("Minute: " + minute);
console.log("Second: " + second);
console.log("Millisecond: " + millisecond);
该示例计算当前日期时间。 我们获得日期时间的年,月,日,时,分,秒和毫秒部分。
$ node parts.js
Year: 2018
Month: 6
Date: 2
Hour: 18
Minute: 10
Second: 3
Millisecond: 329
这是一个示例输出。
Moment.js 星期,月,年
下面的示例计算星期几,月份和年份。
dayof.js
const moment = require('moment');
let now = moment();
console.log("Day of week: " + now.weekday());
console.log("Day of month: " + now.date());
console.log("Day of year: " + now.dayOfYear());
weekday()
返回星期几,date()
返回星期几,dayOfYear()
返回一年中的日子。
$ node main.js
Day of week: 1
Day of month: 2
Day of year: 183
这是一个示例输出。
Moment.js 一年中的第几周,季度中的第几周
在下面的示例中,我们获得一年中的星期,一年中的季度以及一年中的星期数。
weeks_quarter.js
const moment = require('moment');
let now = moment();
console.log("Week of year: " + now.week());
console.log("Quarter of year: " + now.quarter());
console.log("Weeks in year: " + now.weeksInYear());
week()
方法返回一年中的星期,quarter()
方法返回一年中的季度,weeksInYear()
方法返回一年中的星期数。
$ node weeks_quarter.js
Week of year: 27
Quarter of year: 3
Weeks in year: 52
这是一个示例输出。
Moment.js 相对日期时间
我们可以使用fromNow()
,startOf()
和endOf()
函数计算相对日期时间。
relative_time.js
const moment = require('moment');
let day = moment().startOf('year');
let now = moment();
let days = now.diff(day, 'days');
console.log(`${days} have passed since the start of the year.`);
let val = moment().endOf('day');
let mins = val.diff(now, 'minutes');
console.log(`The day will end in ${mins} minutes.`);
let day2 = moment("2028-12-20")
let diff = day2.fromNow();
console.log(`The day will come ${diff}.`);
该示例使用上述功能。
let day = moment().startOf('year');
let now = moment();
let days = now.diff(day, 'days');
在这里,我们计算自年初以来经过的天数。
let val = moment().endOf('day');
let mins = val.diff(now, 'minutes');
这些行计算到午夜的分钟数。
let day2 = moment("2028-12-20")
let diff = day2.fromNow();
在这里,我们获得到指定日期为止的年数。
$ node relative_time.js
182 have passed since the start of the year.
The day will end in 360 minutes.
The day will come in 10 years.
这是输出。
Moment.js 检查有效性
我们可以使用isValid()
方法检查日期和时间对象是否有效。
validity.js
const moment = require('moment');
let day1 = moment('2018-12-12');
let day2 = moment('2018-13-12');
if (day1.isValid()) {
console.log("Day is valid");
} else {
console.log("Day is not valid");
}
if (day2.isValid()) {
console.log("Day is valid");
} else {
console.log("Day is not valid");
}
该示例检查两天的有效性。
Moment.js 日期查询
isBefore()
和isAfter()
函数可用于确定某个日期是在另一个日期之前还是之后。
date_queries.js
const moment = require('moment');
let d1 = moment("2018-05-19");
let d2 = moment("2018-05-20");
let d3 = moment("2018-05-22");
if (d1.isAfter(d2)) {
console.log(`${d1.format('ll')} is after ${d2.format('ll')}`);
} else {
console.log(`${d1.format('ll')} is before ${d2.format('ll')}`);
}
if (d2.isBefore(d3)) {
console.log(`${d2.format('ll')} is before ${d3.format('ll')}`);
} else {
console.log(`${d2.format('ll')} is after ${d3.format('ll')}`);
}
在示例中,我们使用isBefore()
和isAfter()
函数比较三个日期。
$ node date_queries.js
May 19, 2018 is before May 20, 2018
May 20, 2018 is before May 22, 2018
这是输出。
isBetween()
函数检查日期是否在给定的日期范围内。
between.js
const moment = require('moment');
let d1 = moment("2018-05-19");
if (d1.isBetween('2018-05-10', '2018-05-25')) {
console.log("The day is within the date range");
}
该示例使用isBetween()
函数来确定日期是否在指定的日期范围内。
Moment.js Unix 时间
Unix 时间是自 Unix 时代以来的秒数。 unix()
函数返回自世界标准时间 1970 年 1 月 1 日 0 小时 0 分 0 秒以来的秒数。
unixtime.js
const moment = require('moment');
let unixTime = moment().unix();
console.log(unixTime);
let unixTime2 = moment(1000);
console.log(unixTime2.format('MM-DD-YYYY'));
在该示例中,我们获得了当前的 unix 时间并将 unix 时间 1s 转换为人类可读的格式。
let unixTime = moment().unix();
我们通过unix()
函数获得 Unix 时间。 返回的值是从 Unix 纪元开始起经过的秒数。
let unixTime2 = moment(1000);
console.log(unixTime2.format('MM-DD-YYYY'));
我们得到 1 秒的 unix 时间,并以给定的格式输出。
$ node unixtime.js
1530606134
01-01-1970
这是输出。
Moment.js 解析日期和时间
通过将日期和时间格式传递给moment()
函数,我们可以解析日期和时间的字符串表示形式。
parse.js
const moment = require('moment');
let day = "03/04/2008";
let parsed = moment(day, "DD/MM/YYYY");
console.log(parsed.format('ll'));
在该示例中,我们解析了一个非标准的日期和时间字符串。 我们将期望的格式作为moment()
函数的第二个参数传递。
Moment.js 本地化的日期和时间
使用locale()
函数,我们可以设置获取输出的语言环境。
localized.js
const moment = require('moment');
moment.locale('sk');
let now = moment();
console.log(now.format('LLLL'));
moment.locale('de');
now = moment();
console.log(now.format('LLLL'));
moment.locale('hu');
now = moment();
console.log(now.format('LLLL'));
在示例中,我们在三个不同的语言环境中打印当前时刻。
$ node localized.js
nedeľa 1\. júl 2018 22:21
Sonntag, 1\. Juli 2018 22:21
2018\. július 1., vasárnap 22:21
我们提供了当前时刻的斯洛伐克,德国和匈牙利日期和时间输出。
世界时间
我们的星球是一个球体; 它绕其轴旋转。 地球向东旋转,因此太阳在不同位置的不同时间升起。 地球大约每 24 小时旋转一次。 因此,世界被划分为 24 个时区。 在每个时区,都有一个不同的本地时间。 夏令时通常会进一步修改此本地时间。
实际需要一个全球时间。 全球时间可以避免时区和夏令时的混淆。 UTC(世界标准时间)被选为主要时间标准。 UTC 用于航空,天气预报,飞行计划,空中交通管制通关和地图。 与当地时间不同,UTC 不会随季节变化而变化。
utc.js
const moment = require('moment');
let localTime = moment();
console.log(localTime.format());
let utcTime = moment().utc();
console.log(utcTime.format('lll'));
该示例打印当前的 UTC 时间和本地时间。
let utcTime = moment().utc();
通用时间通过utc()
检索。
$ node utc.js
2018-07-01T21:15:17+02:00
Jul 1, 2018 7:15 PM
在我们的案例中,本地时间与世界时间之间的时差为两个小时。 时区一个小时,夏时制另一个小时。
Moment.js 闰年
闰年是包含另一天的一年。 日历中额外一天的原因是天文日历年与日历年之间的差异。
leap_year.js
const moment = require('moment');
// Assume year >= 1582 in the Gregorian calendar.
let years = [ 2000, 2002, 2004, 2008, 2012, 2016, 2020,
1900, 1800, 1600 ];
for (year of years) {
let ym = moment([year]);
if (ym.isLeapYear()) {
console.log(`${year} is a leap year`);
} else {
console.log(`${year} is not a leap year`);
}
}
在示例中,我们有很多年。 我们确定哪些年份是闰年。
if (ym.isLeapYear()) {
我们使用isLeapYear()
函数确定年份是否为闰年。
$ node leap_year.js
2000 is a leap year
2002 is not a leap year
2004 is a leap year
2008 is a leap year
2012 is a leap year
2016 is a leap year
2020 is a leap year
1900 is not a leap year
1800 is not a leap year
1600 is a leap year
这是输出。
在本教程中,我们使用Moment.js
库在 JavaScript 中使用日期和时间。
您可能也对以下相关教程感兴趣: Day.js 教程,或列出所有 JavaScript 教程。
Day.js 教程
原文: http://zetcode.com/javascript/dayjs/
Day.js 教程展示了如何通过 Day.js 模块在 JavaScript 中使用日期和时间。
Day.js
Day.js 是用于解析,验证,操作和格式化日期的极简 JavaScript 日期库。 它是 Moment.js 的替代库,并且具有兼容的 API。 Moment.js 在 Moment.js 教程中进行了介绍。
在本教程中,我们在 Node 应用中使用 Day.js。
安装 Day.js
首先,我们安装 Day.js。
$ node -v
v11.5.0
我们使用 Node 版本 11.5.0。
$ npm init -y
我们启动一个新的 Node 应用。
$ npm i dayjs
我们使用npm i dayjs
命令安装 Day.js。
Day.js 今天的日期
在第一个示例中,我们使用 Day.js 获取今天的日期。
now.js
const dayjs = require('dayjs');
let now = dayjs();
console.log(now.format());
该示例显示当前日期时间。
const dayjs = require('dayjs');
我们加载 Day.js 库。
let now = dayjs();
我们使用dayjs()
获得当前本地日期时间对象。
console.log(now.format());
我们使用format()
格式化输出。 默认情况下,我们使用长日期时间格式。
$ node now.js
2019-05-14T10:12:54+02:00
输出为 ISO 标准格式。 日期时间部分用 T 字符分隔。 该字符串以时区结尾。
创建 Day.js 对象
我们可以使用几种方法来创建日期时间 Day.js 对象。 这些对象被格式化为人类可读的输出。
create_objects.js
const dayjs = require('dayjs');
let d1 = dayjs("2018-06-03");
console.log(d1.format());
let d2 = dayjs.unix(1530471537);
console.log(d2.format());
let d3 = dayjs(new Date(2011, 11, 22));
console.log(d3.format());
该示例以三种不同方式创建日期和时间对象。
let d1 = dayjs("2018-06-03");
我们通过解析字符串创建一个 dayjs 对象。
let d2 = dayjs.unix(1530471537);
console.log(d2.format());
我们使用 unix 时间戳(以秒为单位)定义日期时间对象。
let d3 = dayjs(new Date(2011, 11, 22));
console.log(d3.format());
最后,我们使用 JavaScript 内置的Date
对象来定义dayjs
对象。
$ node create_objects.js
2018-06-03T00:00:00+02:00
2018-07-01T20:58:57+02:00
2011-12-22T00:00:00+01:00
这是输出。
Day.js 格式化日期时间
Day.js 对象使用format()
函数格式化。
formatting.js
const dayjs = require('dayjs');
let now = dayjs();
console.log("ISO")
console.log(now.format());
console.log("\nTime")
console.log(now.format("HH:mm:ss"));
console.log(now.format("h:mm:ss a"));
console.log("\nDate")
console.log(now.format("dddd, MMMM D YYYY"));
console.log(now.format("YYYY-MM-DD"));
使用日的format()
函数的示例格式的日期和时间。
$ node formatting.js
ISO
2019-05-14T10:19:18+02:00
Time
10:19:18
10:19:18 am
Date
Tuesday, May 14 2019
2019-05-14
这是一个示例输出。
Day.js 计算日期时间差
使用diff()
函数,我们可以计算两个日期时间对象之间的差。
difference.js
const dayjs = require('dayjs');
const date1 = dayjs("2019-14-05");
const date2 = dayjs("2018-06-25");
let df1 = date1.diff(date2);
console.log(df1);
let df2 = date1.diff(date2, "month");
console.log(df2);
let df3 = date1.diff(date2, "month", true);
console.log(df3);
let df4 = date1.diff(date2, "day");
console.log(df4);
let df5 = date1.diff(date2, "week");
console.log(df5);
该示例以月,日和周为单位计算两个dayjs
对象之间的差异。
let df2 = date1.diff(date2, "month");
console.log(df2);
第二个参数表明输出将以月为单位。
let df3 = date1.diff(date2, "month", true);
console.log(df3);
将第三个参数设置为true
会返回浮点值,例如 7.3 个月
$ node difference.js
19357200000
7
7.3
224
32
这是输出。
Borodino 战役是 1812 年 9 月 7 日在法国入侵俄罗斯期间的拿破仑战争中进行的战斗。
borodino.js
const dayjs = require('dayjs');
let borodinoBattle = dayjs('1812-09-07');
let now = dayjs();
let days = now.diff(borodinoBattle, 'days');
console.log(`On ${now.format('YYYY-MM-DD')}, ${days} days have passed since the Borodino battle.`);
在示例中,我们计算了自著名战斗以来经过的天数。
$ node borodino.js
On 2019-05-14, 75489 days have passed since the Borodino battle.
这是一个示例输出。
Day.js 日期时间算法
add()
函数用于将日期和时间添加到dayjs
对象,subtract()
函数用于从dayjs
对象中减去日期和时间。
arithm.js
const dayjs = require('dayjs');
let now = dayjs();
console.log(now.format('YYYY-MM-DD'));
let d1 = now.add('14', 'day');
console.log(d1.format('YYYY-MM-DD'));
let d2 = now.subtract('3', 'year');
console.log(d2.format('YYYY-MM-DD'));
在示例中,我们将十四天加上当前日期时间,再减去两年。
let d1 = now.add('14', 'day');
...
let d2 = now.subtract('3', 'year'););
add()
和subtract()
函数的第二个参数是单位类型。
$ node arithm.js
2019-05-14
2019-05-28
2016-05-14
这是输出。
Day.js 日期时间部分
在下面的示例中,我们获取了当前日期时间的部分。
parts.js
const dayjs = require('dayjs');
let now = dayjs();
console.log(now.toObject());
let year = now.year();
console.log(`Year: ${year}`);
let month = now.month();
console.log(`Month: ${month}`);
let date = now.date();
console.log(`Date: ${date}`);
let hour = now.hour();
console.log(`Hour: ${hour}`);
let minute = now.minute();
console.log(`Minute: ${minute}`);
let second = now.second();
console.log(`Second: ${second}`);
let milli = now.millisecond();
console.log(`Millisecond: ${milli}`);
该示例计算当前日期时间。 我们获得日期时间的年,月,日,时,分,秒和毫秒部分。 toObject()
函数返回带有日期时间部分的 JavaScript 对象。
$ node parts.js
{ years: 2019,
months: 4,
date: 14,
hours: 10,
minutes: 41,
seconds: 34,
milliseconds: 963 }
Year: 2019
Month: 4
Date: 14
Hour: 10
Minute: 41
Second: 34
Millisecond: 963
这是一个示例输出。
Day.js 转换函数
除了format()
函数外,我们还可以使用一些内置的转换函数。
converting.js
const dayjs = require('dayjs');
let now = dayjs();
console.log(now.toString());
console.log(now.toJSON());
console.log(now.toISOString());
console.log(now.toObject());
我们有四个函数。 toJSON()
是toISOString()
的别名。
$ node converting.js
Tue, 14 May 2019 09:00:51 GMT
2019-05-14T09:00:51.157Z
2019-05-14T09:00:51.157Z
{ years: 2019,
months: 4,
date: 14,
hours: 11,
minutes: 0,
seconds: 51,
milliseconds: 157 }
这是输出。
Day.js 相对日期时间
我们可以使用startOf()
和endOf()
函数计算相对日期时间。
relative_time.js
const dayjs = require('dayjs');
// let now = dayjs();
let startWeek = dayjs().startOf('week');
console.log(startWeek.format());
let endWeek = dayjs().endOf('week');
console.log(endWeek.format());
let startMonth = dayjs().startOf('month');
console.log(startMonth.format());
let endMonth = dayjs().endOf('month');
console.log(endMonth.format());
let startYear = dayjs().startOf('year');
console.log(startYear.format());
let endYear = dayjs().endOf('year');
console.log(endYear.format());
该示例使用上述函数。
let startWeek = dayjs().startOf('week');
console.log(startWeek.format());
在这里,我们计算当前星期开始的日期时间。
let endYear = dayjs().endOf('year');
console.log(endYear.format());
在这里,我们获取一年中的最后一个日期时间。
$ node relative_time.js
2019-05-12T00:00:00+02:00
2019-05-18T23:59:59+02:00
2019-05-01T00:00:00+02:00
2019-05-31T23:59:59+02:00
2019-01-01T00:00:00+01:00
2019-12-31T23:59:59+01:00
这是输出。
Day.js 检查有效性
我们可以使用isValid()
函数检查日期和时间对象是否有效。
validating.js
const dayjs = require('dayjs');
let day1 = dayjs('2018-12-12');
let day2 = dayjs('2018-11-ks');
if (day1.isValid()) {
console.log("Day is valid");
console.log(day1.format());
} else {
console.log("Day is not valid");
}
if (day2.isValid()) {
console.log("Day is valid");
console.log(day2.format());
} else {
console.log("Day is not valid");
}
该示例检查两天的有效性。
Day.js 日期查询
isSame()
,isBefore()
和isAfter()
函数可用于确定某个日期是在另一个日期之前还是之后。
queries.js
const dayjs = require('dayjs');
let d1 = dayjs("2018-05-19");
let d2 = dayjs("2018-05-20");
let d3 = dayjs("2018-05-22");
let d4 = dayjs("2018-05-19");
if (d1.isSame(d4)) {
console.log('these are same dates');
} else {
console.log('these are not the same dates');
}
if (d1.isAfter(d2)) {
console.log(`${d1.format('YYYY-MM-DD')} is after ${d2.format('YYYY-MM-DD')}`);
} else {
console.log(`${d1.format('YYYY-MM-DD')} is before ${d2.format('YYYY-MM-DD')}`);
}
if (d2.isBefore(d3)) {
console.log(`${d2.format('YYYY-MM-DD')} is before ${d3.format('YYYY-MM-DD')}`);
} else {
console.log(`${d2.format('YYYY-MM-DD')} is after ${d3.format('YYYY-MM-DD')}`);
}
在示例中,我们比较了三个日期。
$ node queries.js
these are same dates
2018-05-19 is before 2018-05-20
2018-05-20 is before 2018-05-22
这是输出。
isBetween()
函数检查日期是否在给定的日期范围内。
between.js
const dayjs = require('dayjs');
const isBetween = require('dayjs/plugin/isBetween');
dayjs.extend(isBetween);
let d1 = dayjs("2018-05-19");
if (d1.isBetween('2018-05-10', '2018-05-25')) {
console.log("The day is within the date range");
} else {
console.log("The day is not within the date range");
}
该示例使用isBetween()
函数来确定日期是否在指定的日期范围内。 对于此示例,我们需要isBetween
插件。
Day.js Unix 时间
Unix 时间是自 Unix 时代以来的秒数。 unix()
函数返回自世界标准时间 1970 年 1 月 1 日 0 小时 0 分 0 秒以来的秒数。
unixtime.js
const dayjs = require('dayjs');
let unixTime_s = dayjs().unix();
console.log(unixTime_s);
let unixTime_ms = dayjs().valueOf();
console.log(unixTime_ms);
let unixTime2 = dayjs(1);
console.log(unixTime2.format('YYYY-DD-MM'));
在该示例中,我们获得了当前的 unix 时间并将 unix 时间 1 s 转换为人类可读的格式。
let unixTime_s = dayjs().unix();
我们通过unix()
函数获得 Unix 时间。 返回的值是从 Unix 纪元开始起经过的秒数。
let unixTime_ms = dayjs().valueOf();
使用valueOf()
函数,我们可以得到以毫秒为单位的 Unix 时间。
let unixTime2 = dayjs(1);
console.log(unixTime2.format('YYYY-DD-MM'));
我们得到 1 秒的 unix 时间,并以给定的格式输出。
$ node unix_time.js
1557825803
1557825803834
1970-01-01
这是一个示例输出。
Day.js 闰年
闰年是包含另一天的一年。 日历中额外一天的原因是天文日历年与日历年之间的差异。 我们需要添加isLeapYear
插件。
leap_year.js
const dayjs = require('dayjs');
const isLeapYear = require('dayjs/plugin/isLeapYear');
dayjs.extend(isLeapYear)
// Assume year >= 1582 in the Gregorian calendar.
let years = [ 2000, 2002, 2004, 2008, 2012, 2016, 2020,
1900, 1800, 1600 ];
for (year of years) {
let ym = dayjs([year]);
if (ym.isLeapYear()) {
console.log(`${year} is a leap year`);
} else {
console.log(`${year} is not a leap year`);
}
}
在示例中,我们有很多年。 我们确定哪些年份是闰年。
if (ym.isLeapYear()) {
我们使用isLeapYear()
函数确定年份是否为闰年。
$ node leap_year.js
2000 is a leap year
2002 is not a leap year
2004 is a leap year
2008 is a leap year
2012 is a leap year
2016 is a leap year
2020 is a leap year
1900 is not a leap year
1800 is not a leap year
1600 is a leap year
这是输出。
在本教程中,我们使用Day.js
库在 JavaScript 中使用日期和时间。
您可能也对以下相关教程感兴趣: Moment.js 教程,或列出所有 JavaScript 教程。
{% raw %}
JavaScript Mustache 教程
原文: http://zetcode.com/javascript/mustache/
在 JavaScript Mustache 教程中,我们展示了如何使用 Mustache 模板引擎。
Mustache
Mustache 是一个简单的 Web 模板系统。 它可用于许多编程语言,包括 JavaScript 和 Java。 Mustache 被描述为一种无逻辑的模板引擎,因为它没有任何明确的控制流语句,例如if
和else
条件语句或for
循环。 可以使用节标记处理列表和 lambda 来实现循环和条件评估。
JSON(JavaScript 对象表示法)是一种轻量级的数据交换格式。 人类很容易读写,机器也很容易解析和生成。 application/json
是 JSON 的官方 Internet 媒体类型。 JSON 文件扩展名是.json
。
jQuery 是一个 JavaScript 库,用于处理 DOM。 使用 jQuery,我们可以查找,选择,遍历和操作 HTML 文档的各个部分。
<script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/2.3.0/mustache.min.js"></script>
Mustache 是一个 JavaScript 库,可以从 CDN(内容交付网络)引用。
Mustache 基本模板示例
在第一个示例中,我们有一个基本的模板示例。
basic.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>JavaScript Mustache template</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/2.3.0/mustache.min.js"></script>
</head>
<body>
<div id="mypanel"></div>
<button id="btn">Load</button>
<script>
$("#btn").on('click', function() {
var data = { name: "Jonathan" };
var template = "Hello {{ name }}";
var text = Mustache.render(template, data);
$("#mypanel").html(text);
});
</script>
</body>
</html>
单击该按钮,我们会在页面上写一条消息。
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/2.3.0/mustache.min.js"></script>
在示例中,我们使用 JQuery 和 Mustache JavaScript 库。
$("#btn").on('click', function() {
...
}
我们创建一个对按钮单击事件做出反应的处理器。
var data = { name: "Jonathan" };
这是数据。
var template = "Hello {{ name }}";
这是 Moustache 模板。 {{ name }}
是一个 Moustache 标签,已被数据值替换。
var text = Mustache.render(template, data);
最终输出使用Mustache.render()
函数渲染。 模板引擎将模板与数据连接起来以生成输出。
$("#mypanel").html(text);
呈现的文本将被写入面板元素。
Mustache 使用模板标签
在第二个示例中,我们使用模板标记。 当前使用的是<script type="text/template">
,但是在不久的将来它将被<template>
标签取代。 标记包含客户端内容,该内容不会在加载页面时呈现,而是在运行时使用 JavaScript 实例化。
json_url.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>JavaScript Mustache template</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/2.3.0/mustache.min.js"></script>
</head>
<body>
<script id="mp_template" type="text/template">
Date: {{ time }}
<br>
Time: {{ date }}
<br>
Unix time: {{ milliseconds_since_epoch }}
</script>
<div id="mypanel"></div>
<button id="btn">Load</button>
<script>
$(function() {
$("#btn").on('click', function() {
$.getJSON('http://time.jsontest.com', function(data) {
var template = $("#mp_template").html();
var text = Mustache.render(template, data);
$("#mypanel").html(text);
});
});
});
</script>
在此示例中,我们向time.jsontest.com
发送请求,该请求返回具有三个属性的 JSON 响应:time
,date
和milliseconds_since_epoch
(Unix 时间)。
<script id="mp_template" type="text/template">
Date: {{ time }}
<br>
Time: {{ date }}
<br>
Unix time: {{ milliseconds_since_epoch }}
</script>
我们在<script id="mp_template" type="text/template">
标签内定义模板。
$.getJSON('http://time.jsontest.com', function(data) {
使用$.getJSON()
,我们使用 GET HTTP 请求从服务器加载 JSON 编码的数据。
var template = $("#mp_template").html();
使用 JQuery 的html()
方法,我们可以获得模板数据。
var text = Mustache.render(template, data);
输出使用Mustache.render()
呈现。
$("#mypanel").html(text);
最终文本将写入面板元素。
带有 Java Servlet 的 Mustache
在第三个示例中,我们使用 servlet 创建一个 Java Web 应用。
$ tree
.
├── pom.xml
└── src
├── main
│ ├── java
│ │ └── com
│ │ └── zetcode
│ │ ├── bean
│ │ │ └── City.java
│ │ └── web
│ │ └── GetCities.java
│ └── webapp
│ ├── index.html
│ ├── META-INF
│ │ └── context.xml
│ └── WEB-INF
└── test
└── java
这是项目结构。
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zetcode</groupId>
<artifactId>ServletJsonMustache</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>ServletJsonMustache</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
</project>
这是 Maven POM 文件。 我们有两个工件:用于 Java servlet 的javax.servlet-api
和用于 Java JSON 处理的gson
。
context.xml
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/ServletJsonMustache"/>
在 Tomcat context.xml
文件中,我们定义了上下文路径。 它是 Web 应用的名称。
City.java
package com.zetcode.bean;
public class City {
private Long id;
private String name;
private int population;
public City() {
}
public City(Long id, String name, int population) {
this.id = id;
this.name = name;
this.population = population;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPopulation() {
return population;
}
public void setPopulation(int population) {
this.population = population;
}
@Override
public String toString() {
return "City{" + "id=" + id + ", name=" + name +
", population=" + population + '}';
}
}
这是City
bean。 它具有三个属性:id,名称和人口。
GetCities.java
package com.zetcode.web;
import com.google.gson.Gson;
import com.zetcode.bean.City;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(name = "GetCities", urlPatterns = {"/GetCities"})
public class GetCities extends HttpServlet {
private static final List<City> cities;
static {
cities = new ArrayList<>();
cities.add(new City(1L, "Bratislava", 432000));
cities.add(new City(2L, "Budapest", 1759000));
cities.add(new City(3L, "Prague", 1280000));
cities.add(new City(4L, "Warsaw", 1748000));
cities.add(new City(5L, "Los Angeles", 3971000));
cities.add(new City(6L, "New York", 8550000));
cities.add(new City(7L, "Edinburgh", 464000));
cities.add(new City(8L, "Berlin", 3671000));
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("application/json;charset=UTF-8");
try (ServletOutputStream os = response.getOutputStream()) {
os.print(new Gson().toJson(cities));
}
}
}
这是GetCities
servlet。
response.setContentType("application/json;charset=UTF-8");
响应对象的内容类型设置为application/json
。
try (ServletOutputStream os = response.getOutputStream()) {
os.print(new Gson().toJson(cities));
}
我们使用Gson
库将 Java 列表转换为 JSON 数组。 将该数组写入响应输出流。 数组未命名。
index.html
<!DOCTYPE html>
<html>
<head>
<title>Cities</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/2.3.0/mustache.min.js"></script>
</head>
<body>
<script id="mp_template" type="text/template">
<table>
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Price</th>
</tr>
</thead>
<tbody>
{{#.}}
<tr>
<td>{{id}}</td>
<td>{{name}}</td>
<td>{{population}}</td>
</tr>
{{/.}}
</tbody>
</table>
</script>
<div id="mypanel"></div>
<button id="btn">Load</button>
<script>
$(function () {
$("#btn").on('click', function () {
$.getJSON('http://localhost:8084/ServletJsonMustache/GetCities', function (cities) {
var template = $("#mp_template").html();
var text = Mustache.render(template, cities);
$("#mypanel").html(text);
});
});
});
</script>
</body>
</html>
这是主页。
<script id="mp_template" type="text/template">
...
</script>
胡子模板放置在<script id="mp_template" type="text/template">
标签中。
<tbody>
{{#.}}
<tr>
<td>{{id}}</td>
<td>{{name}}</td>
<td>{{population}}</td>
</tr>
{{/.}}
</tbody>
使用{{#.}} {{/.}}
语法,我们遍历了 servlet 返回的未命名 JSON 数组,并用值替换了 Mustache 标签。
$.getJSON('http://localhost:8084/ServletJsonMustache/GetCities', function (cities) {
使用$.getJSON()
,我们称为GetCities
Servlet。 该 Servlet 返回 JSON 数据,并使用 Mustache 处理。
命名 JSON 数组
如果我们想命名返回的 JSON 数组,可以使用以下代码:
Gson gson = new GsonBuilder().create();
JsonArray jarray = gson.toJsonTree(cities).getAsJsonArray();
JsonObject jsonObject = new JsonObject();
jsonObject.add("cities", jarray);
os.print(jsonObject.toString());
在 Servlet 中,我们将 JSON 数组放入另一个 JSON 对象中,并将属性命名为cities
。
<tbody>
{{#cities}}
<tr>
<td>{{id}}</td>
<td>{{name}}</td>
<td>{{population}}</td>
</tr>
{{/cities}}
</tbody>
在 Mustache 模板中,我们使用以下语法:{{#cities}} {{/cities}}
。
图:使用 Mustache 从 Servlet 渲染JSON数据
在本教程中,我们使用了 Mustache 模板引擎。
您可能也对以下相关教程感兴趣: JSON 服务器教程,从 JavaScript 中的 URL 读取 JSON , JQuery 教程, Node.js 教程 或 jQuery 自动完成教程或使用 jQuery DatePicker
。
{% endraw %}
Knex.js 教程
原文: http://zetcode.com/javascript/knex/
Knex.js 教程展示了如何使用 Knex.js 在 JavaScript 中对数据库进行编程。
Knex.js
Knex.js 是用于关系数据库(包括 PostgreSQL,MySQL,SQLite3 和 Oracle)的 JavaScript 查询生成器。 它可以与回调和Promise
一起使用。 它支持事务和连接池。
在本教程中,我们使用 MySQL。
安装 Knex.js
首先,我们需要安装 Knex.js。
$ nodejs -v
v9.11.2
我们使用 Node 版本 9.11.2。
$ npm init
我们启动一个新的 Node 应用。
$ npm i knex mysql2
我们安装 Knex.js 和 MySQL 驱动程序。 有两个驱动程序可用:mysql
和mysql2
; 我们选择了后者。
Knex.js 的数据库版本
在第一个示例中,我们找出 MySQL 的版本。
version.js
const options = {
client: 'mysql2',
connection: {
host: '127.0.0.1',
user: 'user12',
password: 's$cret',
database: 'mydb'
}
}
const knex = require('knex')(options);
knex.raw("SELECT VERSION()").then(
(version) => console.log((version[0][0]))
).catch((err) => { console.log( err); throw err })
.finally(() => {
knex.destroy();
});
该示例返回 MySQL 的版本。
const options = {
client: 'mysql2',
connection: {
host: '127.0.0.1',
user: 'user12',
password: 's$cret',
database: 'mydb'
}
}
这些是 MySQL 的连接选项。
const knex = require('knex')(options);
我们加载 Knex.js 并提供连接选项。
knex.raw("SELECT VERSION()").then(
(version) => console.log((version[0][0]))
).catch((err) => { console.log( err); throw err })
.finally(() => {
knex.destroy();
});
使用raw()
函数,我们执行 SQL 语句。 如果语句运行正常,我们将输出输出。 否则,我们记录错误。 最后,我们使用destroy()
关闭数据库连接。
$ node version.js
TextRow { 'VERSION()': '5.7.22-0ubuntu0.16.04.1' }
这是输出。
Knex.js 创建表
在第二个示例中,我们创建一个新的数据库表。
create_table.js
const options = {
client: 'mysql2',
connection: {
host: '127.0.0.1',
user: 'user12',
password: 's$cret',
database: 'mydb'
}
}
const knex = require('knex')(options);
knex.schema.createTable('cars', (table) => {
table.increments('id')
table.string('name')
table.integer('price')
}).then(() => console.log("table created"))
.catch((err) => { console.log(err); throw err })
.finally(() => {
knex.destroy();
});
使用 Knex.js 模式createTable()
函数创建一个新表。 我们定义模式以包含三列:id,名称和价格。
Knex.js 插入数据
接下来,我们将向创建的表中插入一些数据。
insert_cars.js
const options = {
client: 'mysql2',
connection: {
host: '127.0.0.1',
user: 'user12',
password: 's$cret',
database: 'mydb'
}
}
const knex = require('knex')(options);
const cars = [
{ name: 'Audi', price: 52642 },
{ name: 'Mercedes', price: 57127 },
{ name: 'Skoda', price: 9000 },
{ name: 'Volvo', price: 29000 },
{ name: 'Bentley', price: 350000 },
{ name: 'Citroen', price: 21000 },
{ name: 'Hummer', price: 41400 },
{ name: 'Volkswagen', price: 21600 },
]
knex('cars').insert(cars).then(() => console.log("data inserted"))
.catch((err) => { console.log(err); throw err })
.finally(() => {
knex.destroy();
});
我们用knex('cars)
选择cars
表,并用insert()
方法插入八行。
Knex.js 选择所有行
在下面的示例中,我们从cars
表中选择所有行。
select_cars.js
const options = {
client: 'mysql2',
connection: {
host: '127.0.0.1',
user: 'user12',
password: 's$cret',
database: 'mydb'
}
}
const knex = require('knex')(options);
knex.from('cars').select("*")
.then((rows) => {
for (row of rows) {
console.log(`${row['id']} ${row['name']} ${row['price']}`);
}
}).catch((err) => { console.log( err); throw err })
.finally(() => {
knex.destroy();
});
我们使用select()
函数选择所有行。 这次我们选择了具有from()
函数的表格。 然后,我们遍历返回的行数组并打印三个字段。
$ node select_cars.js
1 Audi 52642
2 Mercedes 57127
3 Skoda 9000
4 Volvo 29000
5 Bentley 350000
6 Citroen 21000
7 Hummer 41400
8 Volkswagen 21600
这是输出。
Knex.js 使用WHERE
限制输出
SQL WHERE
子句用于定义要返回的行要满足的条件。
select_where.js
const options = {
client: 'mysql2',
connection: "mysql://root:andrea@localhost:3306/mydb"
}
const knex = require('knex')(options);
knex.from('cars').select("name", "price").where('price', '>', '50000')
.then((rows) => {
for (row of rows) {
console.log(`${row['name']} ${row['price']}`);
}
})
.catch((err) => { console.log( err); throw err })
.finally(() => {
knex.destroy();
});
该示例返回价格高于 50000 的汽车。
const options = {
client: 'mysql2',
connection: "mysql://user12:s$cret@localhost:3306/mydb"
}
这次,我们提供了一个连接 URL。
knex.from('cars').select("name", "price").where('price', '>', '50000')
我们用select()
选择了两列,并在where()
函数中添加了WHERE
子句。
$ node select_where.js
Audi 52642
Mercedes 57127
Bentley 350000
三辆汽车比 5 万辆贵。
Knex.js 排序行
我们可以使用orderBy()
函数订购数据。
order_cars.js
const options = {
client: 'mysql2',
connection: {
host: '127.0.0.1',
user: 'user12',
password: 's$cret',
database: 'mydb'
}
}
const knex = require('knex')(options);
knex.from('cars').select('name', 'price').orderBy('price', 'desc')
.then((rows) => {
for (row of rows) {
console.log(`${row['name']} ${row['price']}`);
}
}).catch((err) => { console.log( err); throw err })
.finally(() => {
knex.destroy();
});
该示例选择所有汽车,然后按价格降序对其进行排序。
$ node order_cars.js
Bentley 350000
Mercedes 57127
Audi 52642
Hummer 41400
Volvo 29000
Volkswagen 21600
Citroen 21000
Skoda 9000
这是输出。
在本教程中,我们使用了Knex.js
库。 我们创建了一些与 MySQL 交互的命令行程序。
您可能也对以下相关教程感兴趣: Sequelize 教程, Node Postgres 教程, Moment.js 教程, JSON 服务器教程 ,从 URL 中读取 JavaScript 中的 JSON , JavaScript 贪食蛇教程, Node Sass 教程, Lodash 教程。
MongoDB JavaScript 教程
原文: http://zetcode.com/javascript/mongodb/
MongoDB JavaScript 教程展示了如何在 JavaScript 中创建与 MongoDB 一起使用的程序。 本教程使用本地 mongodb 驱动程序。 (还有其他解决方案,例如 Mongoose 或 Monk。)
MongoDB
MongoDB 是 NoSQL 跨平台的面向文档的数据库。 它是可用的最受欢迎的数据库之一。 MongoDB 由 MongoDB Inc. 开发,并作为免费和开源软件发布。
MongoDB 中的记录是一个文档,它是由字段和值对组成的数据结构。 MongoDB 文档与 JSON 对象相似。 字段的值可以包括其他文档,数组和文档数组。 MongoDB 将文档存储在集合中。 集合类似于关系数据库中的表以及行中的文档。
安装 MongoDB 服务器
以下命令可用于在基于 Debian 的 Linux 上安装 MongoDB。
$ sudo apt-get install mongodb
该命令将安装 MongoDB 随附的必要包。
$ sudo service mongodb status
mongodb start/running, process 975
使用sudo service mongodb status
命令,我们检查mongodb
服务器的状态。
$ sudo service mongodb start
mongodb start/running, process 6448
mongodb
服务器由sudo service mongodb start
命令启动。
MongoDB 驱动程序安装
我们设置了项目。
$ node -v
v11.5.0
我们使用 Node.js 版本 11.5.0。
$ npm i mongodb
我们安装mongodb
本机 JavaScript 驱动程序。 npm
是 Node.js 包管理器。 MongoDB Node.js 驱动程序提供基于回调和基于Promise
的交互。
MongoDB 创建数据库
mongo
工具是 MongoDB 的交互式 JavaScript Shell 界面,它为系统管理员提供了一个界面,并为开发者提供了一种直接测试数据库查询和操作的方法。
$ mongo testdb
MongoDB shell version v4.0.7
...
> db
testdb
> db.cars.insert({name: "Audi", price: 52642})
> db.cars.insert({name: "Mercedes", price: 57127})
> db.cars.insert({name: "Skoda", price: 9000})
> db.cars.insert({name: "Volvo", price: 29000})
> db.cars.insert({name: "Bentley", price: 350000})
> db.cars.insert({name: "Citroen", price: 21000})
> db.cars.insert({name: "Hummer", price: 41400})
> db.cars.insert({name: "Volkswagen", price: 21600})
我们创建一个testdb
数据库,并在cars
集合中插入八个文档。
MongoDB Promise
Promise
是用于延迟和异步计算的对象。 它表示尚未完成的操作,但有望在将来进行。
asyncFunc()
.then(value => { /* success */ })
.catch(error => { /* failure */ })
.finally( => { /* cleanup */};
then()
方法始终返回Promise
,这使我们能够链接方法调用。
注意:如果没有传递回调,
MongoClient
的connect
将返回一个Promise
。
我们也可以使用async/await
语法来处理Promise
。
MongoDB JS 驱动程序
在第一个示例中,我们打印 Node.js 驱动程序的版本。
driver_version.js
const mongo = require('mongodb');
const MongoClient = mongo.MongoClient;
const url = 'mongodb://localhost:27017';
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
if (err) throw err;
console.log(client.topology.clientInfo);
client.close();
});
在该示例中,我们连接到服务器并找到客户端信息。
const mongo = require('mongodb');
我们使用mongodb
模块。
const client = mongo.MongoClient;
MongoClient
用于连接到 MongoDB 服务器。
const url = 'mongodb://localhost:27017';
这是数据库的 URL。 27017 是 MongoDB 服务器监听的默认端口。
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
使用connect()
创建到数据库的连接。
$ node driver_version.js
{ driver: { name: 'nodejs', version: '3.2.2' },
os:
{ type: 'Windows_NT',
name: 'win32',
architecture: 'x64',
version: '10.0.17134' },
platform: 'Node.js v11.5.0, LE' }
驱动程序版本为 3.2.2。
MongoDB 列出数据库集合
listCollections()
方法列出了数据库中的可用集合。
list_collections.js
const mongo = require('mongodb');
const MongoClient = mongo.MongoClient;
const url = 'mongodb://localhost:27017';
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
if (err) throw err;
const db = client.db("testdb");
db.listCollections().toArray().then((docs) => {
console.log('Available collections:');
docs.forEach((doc, idx, array) => { console.log(doc.name) });
}).catch((err) => {
console.log(err);
}).finally(() => {
client.close();
});
});
该示例连接到testdb
数据库并检索其所有集合。
db.listCollections().toArray().then((docs) => {
console.log('Available collections:');
docs.forEach((doc, idx, array) => { console.log(doc.name) });
...
listCollection()
方法在testdb
数据库中找到所有集合; 它们被打印到控制台。
注意:我们应该谨慎使用
toArray()
方法,因为它会导致大量的内存使用。
}).catch((err) => {
console.log(err);
}).finally(() => {
client.close();
});
在catch
块中,我们捕获了任何潜在的异常,并在finally
块中关闭了与数据库的连接。
注意:我们的应用是控制台程序; 因此,我们在程序结束时关闭连接。 在 Web 应用中,应重新使用连接。
$ node list_collections.js
Available collections:
continents
cars
cities
在我们的数据库中,我们有这三个集合。
MongoDB 数据库统计
dbstats()
方法获取数据库的统计信息。
dbstats.js
const mongo = require('mongodb');
const MongoClient = mongo.MongoClient;
const url = 'mongodb://localhost:27017';
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
if (err) throw err;
const db = client.db("testdb");
db.stats((err, stats) => {
if (err) throw err;
console.log(stats);
client.close();
})
});
该示例连接到testdb
数据库并显示其统计信息。
$ node dbstats.js
{ db: 'testdb',
collections: 3,
views: 0,
objects: 18,
avgObjSize: 57.888888888888886,
dataSize: 1042,
storageSize: 69632,
numExtents: 0,
indexes: 3,
indexSize: 69632,
fsUsedSize: 136856346624,
fsTotalSize: 254721126400,
ok: 1 }
这是一个示例输出。
MongoDB 查找
find()
函数为查询创建一个游标,该游标可用于遍历 MongoDB 的结果。
find_all.js
const mongo = require('mongodb');
const MongoClient = mongo.MongoClient;
const url = 'mongodb://localhost:27017';
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
if (err) throw err;
const db = client.db("testdb");
db.collection('cars').find({}).toArray().then((docs) => {
console.log(docs);
}).catch((err) => {
console.log(err);
}).finally(() => {
client.close();
});
});
在示例中,我们从cars
集合中检索所有文档。
db.collection('cars').find({}).toArray().then((docs) => {
传递空查询将返回所有文档。
$ node find_all.js
[ { _id: 5cfcfc3438f62aaa09b52175, name: 'Audi', price: 52642 },
{ _id: 5cfcfc3a38f62aaa09b52176, name: 'Mercedes', price: 57127 },
{ _id: 5cfcfc3f38f62aaa09b52177, name: 'Skoda', price: 9000 },
{ _id: 5cfcfc4338f62aaa09b52178, name: 'Volvo', price: 29000 },
{ _id: 5cfcfc4838f62aaa09b52179, name: 'Bentley', price: 350000 },
{ _id: 5cfcfc4b38f62aaa09b5217a, name: 'Citroen', price: 21000 },
{ _id: 5cfcfc4f38f62aaa09b5217b, name: 'Hummer', price: 41400 },
{ _id: 5cfcfc5438f62aaa09b5217c,
name: 'Volkswagen',
price: 21600 } ]
这是输出。
MongoDB 计数文件
count()
函数返回集合中匹配文档的数量。
count_documents.js
const mongo = require('mongodb');
const MongoClient = mongo.MongoClient;
const url = 'mongodb://localhost:27017';
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
if (err) throw err;
const db = client.db("testdb");
db.collection('cars').find({}).count().then((n) => {
console.log(`There are ${n} documents`);
}).catch((err) => {
console.log(err);
}).finally(() => {
client.close();
});
});
该示例计算cars
集合中的文档数。
$ node count_documents.js
There are 8 documents
现在,汽车集合中有八个文件。
MongoDB findOne
findOne()
方法返回一个满足指定查询条件的文档。 如果多个文档满足查询条件,则此方法将根据反映磁盘上文档顺序的自然顺序返回第一个文档。
find_one.js
const MongoClient = require('mongodb').MongoClient;
const url = 'mongodb://localhost:27017';
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
if (err) throw err;
const db = client.db("testdb");
let collection = db.collection('cars');
let query = { name: 'Volkswagen' }
collection.findOne(query).then(doc => {
console.log(doc);
}).catch((err) => {
console.log(err);
}).finally(() => {
client.close();
});
});
该示例从cars
集合中读取一个文档。
let query = { name: 'Volkswagen' }
该查询包含汽车的名称-大众汽车。
collection.findOne(query).then(doc => {
该查询将传递给findOne()
方法。
$ node find_one.js
{ _id: 8, name: 'Volkswagen', price: 21600 }
这是示例的输出。
MongoDB 异步/等待示例
使用async/await
,我们可以轻松地以同步方式处理Promise
。
async_await.js
const MongoClient = require('mongodb').MongoClient;
const url = 'mongodb://localhost:27017';
async function findCar() {
const client = await MongoClient.connect(url, { useNewUrlParser: true })
.catch(err => { console.log(err); });
if (!client) {
return;
}
try {
const db = client.db("testdb");
let collection = db.collection('cars');
let query = { name: 'Volkswagen' }
let res = await collection.findOne(query);
console.log(res);
} catch (err) {
console.log(err);
} finally {
client.close();
}
}
findCar();
该示例使用async/await
读取一个文档。
async function findCar() {
该函数具有async
关键字。
let res = await collection.findOne(query);
使用await
,我们等待findOne()
函数的结果。
MongoDB 查询运算符
可以使用 MongoDB 查询运算符(例如$gt
,$lt
或$ne
)过滤数据。
read_gt.js
const mongo = require('mongodb');
const MongoClient = mongo.MongoClient;
const url = 'mongodb://localhost:27017';
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
if (err) throw err;
const db = client.db("testdb");
let query = { price: { $gt: 30000 } };
db.collection('cars').find(query).toArray().then((docs) => {
console.log(docs);
}).catch((err) => {
console.log(err);
}).finally(() => {
client.close();
});
});
该示例打印汽车价格大于 30,000 的所有文档。
let query = { price: { $gts: 30000 } };
$gt
运算符用于获取价格大于 30,000 的汽车。
$ node read_gt.js
[ { _id: 5d03e40536943362cffc84a7, name: 'Audi', price: 52642 },
{ _id: 5d03e40a36943362cffc84a8, name: 'Mercedes', price: 57127 },
{ _id: 5d03e41936943362cffc84ab, name: 'Bentley', price: 350000 },
{ _id: 5d03e42236943362cffc84ad, name: 'Hummer', price: 41400 } ]
这是示例的输出。 仅包括价格超过 30,000 的汽车。
$and
逻辑运算符可用于组合多个表达式。
read_gt_lt.js
const mongo = require('mongodb');
const MongoClient = mongo.MongoClient;
const url = 'mongodb://localhost:27017';
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
if (err) throw err;
const db = client.db("testdb");
let query = { $and: [{ price: { $gt: 20000 } }, { price: { $lt: 50000 } }] };
db.collection('cars').find(query).toArray().then((docs) => {
console.log(docs);
}).catch((err) => {
console.log(err);
}).finally(() => {
client.close();
});
});
在示例中,我们检索价格在 20,000 到 50,000 之间的汽车。
let query = { $and: [{ price: { $gt: 20000 } }, { price: { $lt: 50000 } }] };
$and
运算符将$gt
和$lt
组合在一起以获得结果。
$ node read_gt_lt.js
[ { _id: 5d03e41336943362cffc84aa, name: 'Volvo', price: 29000 },
{ _id: 5d03e41e36943362cffc84ac, name: 'Citroen', price: 21000 },
{ _id: 5d03e42236943362cffc84ad, name: 'Hummer', price: 41400 },
{ _id: 5d03e42636943362cffc84ae,
name: 'Volkswagen',
price: 21600 } ]
这是示例的输出。
MongoDB 预测
投影确定从数据库传递哪些字段。
projections.js
const mongo = require('mongodb');
const MongoClient = mongo.MongoClient;
const url = 'mongodb://localhost:27017';
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
if (err) throw err;
const db = client.db("testdb");
db.collection('cars').find({}).project({_id: 0}).toArray().then((docs) => {
console.log(docs);
}).catch((err) => {
console.log(err);
}).finally(() => {
client.close();
});
});
该示例从输出中排除_id
字段。
db.collection('cars').find({}).project({_id: 0}).toArray().then((docs) => {
project()
方法设置查询的投影; 它不包括_id
字段。
$ node projections.js
[ { name: 'Audi', price: 52642 },
{ name: 'Mercedes', price: 57127 },
{ name: 'Skoda', price: 9000 },
{ name: 'Volvo', price: 29000 },
{ name: 'Bentley', price: 350000 },
{ name: 'Citroen', price: 21000 },
{ name: 'Hummer', price: 41400 },
{ name: 'Volkswagen', price: 21600 } ]
这是示例的输出。
MongoDB 限制数据输出
limit()
方法指定要返回的文档数,skip()
方法指定要跳过的文档数。
skip_limit.js
const mongo = require('mongodb');
const MongoClient = mongo.MongoClient;
const url = 'mongodb://localhost:27017';
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
if (err) throw err;
const db = client.db("testdb");
db.collection('cars').find({}).skip(2).limit(5).toArray().then((docs) => {
console.log(docs);
}).catch((err) => {
console.log(err);
}).finally(() => {
client.close();
});
});
该示例从cars
集合中读取,跳过前两个文档,并将输出限制为五个文档。
db.collection('cars').find({}).skip(2).limit(5).toArray().then((docs) => {
skip()
方法跳过前两个文档,limit()
方法将输出限制为五个文档。
$ node skip_limit.js
[ { _id: 5d03e40f36943362cffc84a9, name: 'Skoda', price: 9000 },
{ _id: 5d03e41336943362cffc84aa, name: 'Volvo', price: 29000 },
{ _id: 5d03e41936943362cffc84ab, name: 'Bentley', price: 350000 },
{ _id: 5d03e41e36943362cffc84ac, name: 'Citroen', price: 21000 },
{ _id: 5d03e42236943362cffc84ad, name: 'Hummer', price: 41400 } ]
这是示例的输出。
MongoDB 聚合
聚合计算集合中数据的聚合值。
sum_all_cars.js
const mongo = require('mongodb');
const MongoClient = mongo.MongoClient;
const url = 'mongodb://localhost:27017';
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
if (err) throw err;
const db = client.db("testdb");
let myagr = [{$group: {_id: 1, all: { $sum: "$price" } }}];
db.collection('cars').aggregate(myagr).toArray().then((sum) => {
console.log(sum);
}).catch((err) => {
console.log(err);
}).finally(() => {
client.close();
});
});
该示例计算集合中所有汽车的价格。
let myagr = [{$group: {_id: 1, all: { $sum: "$price" } }}];
$sum
运算符计算并返回数值的总和。 $group
运算符通过指定的标识符表达式对输入文档进行分组,并将累加器表达式(如果指定)应用于每个组。
db.collection('cars').aggregate(myagr).toArray().then((sum) => {
aggregate()
函数将聚合操作应用于cars
集合。
$ node sum_all_cars.js
[ { _id: 1, all: 581769 } ]
所有价格的总和是 581,769。
我们可以使用$match
运算符来选择要汇总的特定汽车。
sum_two_cars.js
const mongo = require('mongodb');
const MongoClient = mongo.MongoClient;
const url = 'mongodb://localhost:27017';
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
if (err) throw err;
const db = client.db("testdb");
let myagr = [
{ $match: { $or: [{ name: "Audi" }, { name: "Volvo" }] } },
{ $group: { _id: 1, sum2cars: { $sum: "$price" } } }
];
db.collection('cars').aggregate(myagr).toArray().then((sum) => {
console.log(sum);
}).catch((err) => {
console.log(err);
}).finally(() => {
client.close();
});
});
该示例计算奥迪和沃尔沃汽车的价格总和。
let myagr = [
{ $match: { $or: [{ name: "Audi" }, { name: "Volvo" }] } },
{ $group: { _id: 1, sum2cars: { $sum: "$price" } } }
];
该表达式使用$match
,$or
,$group
和$sum
运算符执行任务。
$ node sum_two_cars.js
[ { _id: 1, sum2cars: 81642 } ]
两辆车的价格之和为 81,642。
MongoDB insertOne
insertOne()
方法将单个文档插入到集合中。
insert_one.js
const mongo = require('mongodb');
const MongoClient = mongo.MongoClient;
const ObjectID = mongo.ObjectID;
const url = 'mongodb://localhost:27017';
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
if (err) throw err;
const db = client.db("testdb");
let doc = {_id: new ObjectID(), name: "Toyota", price: 37600 };
db.collection('cars').insertOne(doc).then((doc) => {
console.log('Car inserted')
console.log(doc);
}).catch((err) => {
console.log(err);
}).finally(() => {
client.close();
});
});
该示例将一辆汽车插入cars
集合。
let doc = {_id: new ObjectID(), name: "Toyota", price: 37600 };
这是要插入的文档。 使用ObjectID
生成一个新的 ID。
db.collection('cars').insertOne(doc).then((doc) => {
insertOne()
函数将文档插入到集合中。
> db.cars.find({name:'Toyota'})
{ "_id" : ObjectId("5d03d4321f9c262a50e671ee"), "name" : "Toyota", "price" : 37600 }
我们用mongo
工具确认插入。
MongoDB insertMany()
insertMany()
函数可将多个文档插入一个集合中。
insert_many.js
const mongo = require('mongodb');
const MongoClient = mongo.MongoClient;
const ObjectID = mongo.ObjectID;
const url = 'mongodb://localhost:27017';
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
if (err) throw err;
const db = client.db("testdb");
let collection = db.collection('continents');
let continents = [
{ _id: new ObjectID(), name: "Africa" }, { _id: new ObjectID(), name: "America" },
{ _id: new ObjectID(), name: "Europe" }, { _id: new ObjectID(), name: "Asia" },
{ _id: new ObjectID(), name: "Australia" }, { _id: new ObjectID(), name: "Antarctica" }
];
collection.insertMany(continents).then(result => {
console.log("documents inserted into the collection");
}).catch((err) => {
console.log(err);
}).finally(() => {
client.close();
});
});
该示例创建一个continents
集合并将六个文档插入其中。
let collection = db.collection('continents');
collection()
方法检索集合; 如果集合不存在,则会创建它。
let continents = [
{ _id: new ObjectID(), name: "Africa" }, { _id: new ObjectID(), name: "America" },
{ _id: new ObjectID(), name: "Europe" }, { _id: new ObjectID(), name: "Asia" },
{ _id: new ObjectID(), name: "Australia" }, { _id: new ObjectID(), name: "Antarctica" }
];
这是要插入新集合的六个记录的数组。 ObjectID()
创建一个新的 ObjectID,这是用于标识文档的唯一值,而不是整数。
collection.insertMany(continents).then(result => {
console.log("documents inserted into the collection");
}).catch((err) => {
console.log(err);
}).finally(() => {
client.close();
});
insertMany()
方法将文档数组插入continents
集合。
> db.continents.find()
{ "_id" : ObjectId("5cfcf97732fc4913748c9669"), "name" : "Africa" }
{ "_id" : ObjectId("5cfcf97732fc4913748c966a"), "name" : "America" }
{ "_id" : ObjectId("5cfcf97732fc4913748c966b"), "name" : "Europe" }
{ "_id" : ObjectId("5cfcf97732fc4913748c966c"), "name" : "Asia" }
{ "_id" : ObjectId("5cfcf97732fc4913748c966d"), "name" : "Australia" }
{ "_id" : ObjectId("5cfcf97732fc4913748c966e"), "name" : "Antarctica" }
continents
集合已成功创建。
MongoDB deleteOne
deleteOne()
方法用于删除文档。
delete_one.js
const mongo = require('mongodb');
const MongoClient = mongo.MongoClient;
const url = 'mongodb://localhost:27017';
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
if (err) throw err;
const db = client.db("testdb");
let query = { name: "Volkswagen" };
db.collection('cars').deleteOne(query).then((result) => {
console.log('Car deleted');
console.log(result);
}).catch((err) => {
console.log(err);
}).finally(() => {
client.close();
});
});
该示例删除文档。
let query = { name: "Volkswagen" };
db.collection('cars').deleteOne(query).then((result) => {
...
deleteOne()
删除Volkswagen
的文档。
MongoDB updateOne()
updateOne()
函数用于更新文档。
update_one.js
const mongo = require('mongodb');
const MongoClient = mongo.MongoClient;
const url = 'mongodb://localhost:27017';
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
if (err) throw err;
const db = client.db("testdb");
let filQuery = { name: "Audi" };
let updateQuery = { $set: { "price": 52000 }};
db.collection('cars').updateOne(filQuery, updateQuery).then(result => {
console.log('Car updated');
console.log(result);
}).catch((err) => {
console.log(err);
}).finally(() => {
client.close();
});
});
该示例更新了汽车的价格。
let filQuery = { name: "Audi" };
let updateQuery = { $set: { "price": 52000 }};
db.collection('cars').updateOne(filQuery, updateQuery).then(result => {
通过updateOne()
方法将 Audi 的价格更改为 52,000。 $set
运算符用于更改价格。
> db.cars.find({name:'Audi'})
{ "_id" : ObjectId("5cfcfc3438f62aaa09b52175"), "name" : "Audi", "price" : 52000 }
我们使用mongo
工具确认更改。
在本教程中,我们使用了 MongoDB 和 JavaScript。 列出所有 JavaScript 教程。
Sequelize 教程
原文: http://zetcode.com/javascript/sequelize/
Sequelize 教程展示了如何使用 Sequelize ORM 在 JavaScript 中对数据库进行编程。
Sequelize
Sequelize 是 Node.js 的基于 Promise 的 ORM。 它可与 PostgreSQL,MySQL,SQLite 和 MSSQL 方言配合使用,并具有可靠的事务支持,关系,读取复制等功能。
对象关系映射(ORM)是一种从面向对象的语言访问关系数据库的技术。
在本教程中,我们使用 MySQL。
设置续集
我们初始化一个 Node 应用并安装 Sequelize 和 MySQL 适配器。
$ nodejs -v
v10.12.0
我们使用 Node 版本 10.12.0。
$ npm init
我们启动一个新的 Node 应用。
$ npm i sequelize
$ nmp i mysql2
我们安装 Seqelize 和 MySQL 驱动程序。 有两个驱动程序可用:mysql
和mysql2
; 我们选择了后者。
Sequelize 认证
在第一个示例中,我们创建与 MySQL 数据库的连接。
authenticate.js
const Sequelize = require('sequelize');
const path = 'mysql://user12:12user@localhost:3306/testdb';
const sequelize = new Sequelize(path, { operatorsAliases: false });
sequelize.authenticate().then(() => {
console.log('Connection established successfully.');
}).catch(err => {
console.error('Unable to connect to the database:', err);
}).finally(() => {
sequelize.close();
});
该示例在连接到 MySQL 数据库时显示一条消息。
const Sequelize = require('sequelize');
我们加载 Sequelize 模块。
const path = 'mysql://user12:12user@localhost:3306/testdb';
这是 MySQL 连接路径。 它包含用户名,密码,主机名,数据库端口和数据库名称。
const sequelize = new Sequelize(path, { operatorsAliases: false });
我们实例化 Sequelize。
sequelize.authenticate().then(() => {
console.log('Connection established successfully.');
...
authenticate()
方法通过尝试向数据库进行认证来测试连接。 建立连接后,我们将打印一条消息。
}).catch(err => {
console.error('Unable to connect to the database:', err);
...
如果发生错误,我们将打印一条错误消息。
}).finally(() => {
sequelize.close();
});
最后,我们关闭数据库连接。
$ node authenticate.js
Executing (default): SELECT 1+1 AS result
Connection established successfully
这是输出。 输出也包括调试输出。
Sequelize 模型定义
Model
代表数据库中的表。 此类的实例代表数据库行。 Sequelize 的define()
方法定义了一个新模型。
define_model.js
const Sequelize = require('sequelize');
const path = 'mysql://user12:12user@localhost:3306/mydb';
const sequelize = new Sequelize(path, {
operatorsAliases: false
});
let Dummy = sequelize.define('dummy', {
description: Sequelize.STRING
});
Dummy.sync().then(() => {
console.log('New table created');
}).finally(() => {
sequelize.close();
})
该示例创建一个简单的模型。 它将模型保存到数据库表中。
let Dummy = sequelize.define('dummy', {
description: Sequelize.STRING
});
创建了一个新模型Dummy
。 第一个参数是型号名称。 第二个参数由属性组成,这些属性是表列。 在我们的例子中,我们有一个列名description
,它是String
类型。
Dummy.sync().then(() => {
console.log('New table created');
}).finally(() => {
sequelize.close();
})
sync()
方法将模型同步到数据库。 实际上,它将创建一个新的dummies
表。 (表名是复数的。)
$ node model_define.js
Executing (default): CREATE TABLE IF NOT EXISTS `dummies` (`id` INTEGER
NOT NULL auto_increment , `description` VARCHAR(255),
`createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL,
PRIMARY KEY (`id`)) ENGINE=InnoDB;
Executing (default): SHOW INDEX FROM `dummies`
New table created
这是输出。 默认情况下,Sequelize 提供日志记录。 可以使用logging
选项将其关闭。
mysql> describe dummies;
+-------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| description | varchar(255) | YES | | NULL | |
| createdAt | datetime | NO | | NULL | |
| updatedAt | datetime | NO | | NULL | |
+-------------+--------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)
我们检查在 MySQL 中创建的表。 Sequelize 还创建了另外两个列:createdAt
和updatedAt
。 可以使用timestamps
选项将其关闭。
Sequelize 删除表
用drop()
方法删除一个表。
drop_table.js
const Sequelize = require('sequelize');
const path = 'mysql://user12:12user@localhost:3306/mydb';
const sequelize = new Sequelize(path, {
operatorsAliases: false,
logging: false
});
let Dummy = sequelize.define('dummy', {
description: Sequelize.STRING
});
Dummy.drop().then(() => {
console.log('table deleted');
}).finally(() => {
sequelize.close();
});
该示例删除dummies
表。
Sequelize 时间戳
Sequelize 自动为模型添加时间戳。 我们可以使用timestamps
控制此行为。
timestamps.js
const Sequelize = require('sequelize');
const path = 'mysql://user12:12user@localhost:3306/mydb';
const sequelize = new Sequelize(path, {
operatorsAliases: false,
logging: false,
define: {
timestamps: false
}
});
let Dummy = sequelize.define('dummy', {
description: Sequelize.STRING
});
sequelize.sync({force: true}).then(() => {
Dummy.create({ description: 'test 1' }).then(() => {
console.log('table created');
}).finally(() => {
sequelize.close();
});
});
该示例创建一个没有时间戳的表。
const sequelize = new Sequelize(path, {
operatorsAliases: false,
logging: false,
define: {
timestamps: false
}
});
在这里,我们关闭时间戳记。
mysql> describe dummies;
+-------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| description | varchar(255) | YES | | NULL | |
+-------------+--------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)
我们确认表中没有时间戳。
Sequelize 批量创建
bulkCreate()
方法创建并批量插入多个实例。 该方法采用对象数组。
bulk_create_notes.js
const Sequelize = require('sequelize');
const path = 'mysql://user12:12user@localhost:3306/mydb';
const sequelize = new Sequelize(path, {
operatorsAliases: false,
logging: false
});
let Note = sequelize.define('notes', {
description: Sequelize.STRING
});
let notes = [
{ description: 'Tai chi in the morning' },
{ description: 'Visited friend' },
{ description: 'Went to cinema' },
{ description: 'Listened to music' },
{ description: 'Watched TV all day' },
{ description: 'Walked for a hour' },
];
sequelize.sync({ force: true }).then(() => {
Note.bulkCreate(notes, { validate: true }).then(() => {
console.log('notes created');
}).catch((err) => {
console.log('failed to create notes');
console.log(err);
}).finally(() => {
sequelize.close();
});
});
表格示例记录了几行。
const sequelize = new Sequelize(path, {
operatorsAliases: false,
logging: false
});
我们禁用日志记录。
sequelize.sync({ force: true }).then(() => {
sqeuelize.syn()
同步所有型号。 在force
选项丢弃的表,如果它的创建之前就存在。
Note.bulkCreate(notes, { validate: true }).then(() => {
console.log('notes created');
...
bulkCreate()
创建具有六行的表格。
mysql> select * from notes;
+----+------------------------+---------------------+---------------------+
| id | description | createdAt | updatedAt |
+----+------------------------+---------------------+---------------------+
| 1 | Tai chi in the morning | 2018-10-21 14:34:28 | 2018-10-21 14:34:28 |
| 2 | Visited friend | 2018-10-21 14:34:28 | 2018-10-21 14:34:28 |
| 3 | Went to cinema | 2018-10-21 14:34:28 | 2018-10-21 14:34:28 |
| 4 | Listened to music | 2018-10-21 14:34:28 | 2018-10-21 14:34:28 |
| 5 | Watched TV all day | 2018-10-21 14:34:28 | 2018-10-21 14:34:28 |
| 6 | Walked for a hour | 2018-10-21 14:34:28 | 2018-10-21 14:34:28 |
+----+------------------------+---------------------+---------------------+
6 rows in set (0.00 sec)
这是在数据库中创建的表。
Sequelize build()
和save()
使用build()
和save()
分两步或使用create()
一步创建新行。
build_save.js
const Sequelize = require('sequelize');
const path = 'mysql://user12:12user@localhost:3306/mydb';
const sequelize = new Sequelize(path, {
operatorsAliases: false,
logging: false
});
let Note = sequelize.define('notes', {
description: Sequelize.STRING
});
const note = Note.build({ description: 'Took a cold bath' });
note.save().then(() => {
console.log('new task saved');
}).finally(() => {
sequelize.close();
});
本示例使用build()
和save()
创建一个新的笔记。
Sequelize findById
使用findById()
,我们通过其 ID 查找特定行。
find_by_id.js
const Sequelize = require('sequelize');
const path = 'mysql://user12:12user@localhost:3306/mydb';
const sequelize = new Sequelize(path, {
operatorsAliases: false,
logging: false
});
let Note = sequelize.define('notes', {
description: Sequelize.STRING
});
Note.findById(2).then((note) => {
console.log(note.get({ plain: true }));
console.log('********************')
console.log(`id: ${note.id}, description: ${note.description}`);
}).finally(() => {
sequelize.close();
});
该示例查找带有 ID 2 的笔记。
console.log(note.get({ plain: true }));
默认情况下,Sequelize 返回大量元数据。 要关闭数据,我们使用plain: true
选项。
$ node find_by_id.js
{ id: 2,
description: 'Visited friend',
createdAt: 2018-10-21T14:34:28.000Z,
updatedAt: 2018-10-21T14:34:28.000Z }
********************
id: 2, description: Visited friend
我们将行打印两次。 在第一种情况下,我们返回所有数据。 在第二种情况下,我们仅选择两个字段。
Sequelize findOne
findOne()
方法搜索单个行。
find_one.js
const Sequelize = require('sequelize');
const path = 'mysql://user12:12user@localhost:3306/mydb';
const sequelize = new Sequelize(path, {
operatorsAliases: false,
logging: false
});
let Note = sequelize.define('notes', {
description: Sequelize.STRING
});
Note.findOne({ where: { id: 1 } }).then(note => {
console.log(note.get({ plain: true }));
}).finally(() => {
sequelize.close();
});
该示例使用find_one()
返回表的第一行。 where
选项指定要查找的 ID。
$ node find_one.js
{ id: 1,
description: 'Tai chi in the morning',
createdAt: 2018-10-21T14:34:28.000Z,
updatedAt: 2018-10-21T14:34:28.000Z }
这是输出。
Sequelize async
和await
在下一个示例中,我们使用async
和await
关键字。
find_one2.js
const Sequelize = require('sequelize');
const path = 'mysql://user12:12user@localhost:3306/mydb';
const sequelize = new Sequelize(path, {
operatorsAliases: false,
logging: false
});
let Note = sequelize.define('notes', {
description: Sequelize.STRING
});
async function getOneNote() {
let user = await Note.findOne();
console.log(user.get('description'));
sequelize.close();
}
getOneNote();
我们使用async
和await
关键字返回带有findOne()
的第一行。
Sequelize 计数
count()
方法计算表中的行数。
count_rows.js
const Sequelize = require('sequelize');
const path = 'mysql://user12:12user@localhost:3306/mydb';
const sequelize = new Sequelize(path, {
operatorsAliases: false,
logging: false
});
let Note = sequelize.define('notes', {
description: Sequelize.STRING
});
async function countRows() {
let n = await Note.count();
console.log(`There are ${n} rows`);
sequelize.close();
}
countRows();
该示例计算notes
表中的行数。
$ node count_rows.js
There are 7 rows
目前,表格中有 7 行。
Sequelize 删除行
使用destroy()
方法删除一行。 它返回已删除的行数。
delete_row.js
const Sequelize = require('sequelize');
const path = 'mysql://user12:12user@localhost:3306/mydb';
const sequelize = new Sequelize(path, {
operatorsAliases: false,
logging: false
});
let Note = sequelize.define('notes', {
description: Sequelize.STRING
});
async function deleteRow() {
let n = await Note.destroy({ where: { id: 2 } });
console.log(`number of deleted rows: ${n}`);
sequelize.close();
}
deleteRow();
该示例删除 ID 为 2 的行。
Sequelize 更新行
用update()
方法更新一行。
update_row.js
const Sequelize = require('sequelize');
const path = 'mysql://user12:12user@localhost:3306/mydb';
const sequelize = new Sequelize(path, {
operatorsAliases: false,
logging: false
});
let Note = sequelize.define('notes', {
description: Sequelize.STRING
});
async function updateRow() {
let id = await Note.update(
{ description: 'Finished reading history book' },
{ where: { id: 1 } });
sequelize.close();
}
updateRow();
该示例更新了第一行的描述。
Sequelize findAll
findAll()
方法搜索多个实例。
find_all.js
const Sequelize = require('sequelize');
const path = 'mysql://user12:12user@localhost:3306/mydb';
const sequelize = new Sequelize(path, {
operatorsAliases: false,
logging: false
});
let Note = sequelize.define('notes', {
description: Sequelize.STRING
});
async function findAllRows() {
let notes = await Note.findAll({ raw: true });
console.log(notes);
sequelize.close();
}
findAllRows();
该示例使用findAll()
从数据库表中检索所有行。
let notes = await Note.findAll({ raw: true });
raw: true
选项关闭元数据。
$ node find_all.js
[ { id: 1,
description: 'Finished reading history book',
createdAt: 2018-10-21T14:34:28.000Z,
updatedAt: 2018-10-21T16:00:22.000Z },
{ id: 2,
description: 'Visited friend',
createdAt: 2018-10-21T14:34:28.000Z,
updatedAt: 2018-10-21T14:34:28.000Z },
{ id: 3,
description: 'Went to cinema',
createdAt: 2018-10-21T14:34:28.000Z,
updatedAt: 2018-10-21T14:34:28.000Z },
{ id: 4,
description: 'Listened to music',
createdAt: 2018-10-21T14:34:28.000Z,
updatedAt: 2018-10-21T14:34:28.000Z },
{ id: 5,
description: 'Watched TV all day',
createdAt: 2018-10-21T14:34:28.000Z,
updatedAt: 2018-10-21T14:34:28.000Z },
{ id: 6,
description: 'Walked for a hour',
createdAt: 2018-10-21T14:34:28.000Z,
updatedAt: 2018-10-21T14:34:28.000Z },
{ id: 7,
description: 'Took a cold bath',
createdAt: 2018-10-21T14:49:51.000Z,
updatedAt: 2018-10-21T14:49:51.000Z } ]
该示例返回了七行。
Seqelize 选择列
使用attributes
选项,我们可以选择要包括在查询中的列。
columns.js
const Sequelize = require('sequelize');
const path = 'mysql://user12:12user@localhost:3306/mydb';
const sequelize = new Sequelize(path, {
operatorsAliases: false,
});
let Note = sequelize.define('notes', {
description: Sequelize.STRING
});
async function getTwoColumns() {
let notes = await Note.findAll({ attributes: ['id', 'description'], raw: true });
console.log(notes);
sequelize.close();
}
getTwoColumns();
在示例中,我们选择id
和description
列。
$ node columns.js
Executing (default): SELECT `id`, `description` FROM `notes` AS `notes`;
[ { id: 1, description: 'Finished reading history book' },
{ id: 3, description: 'Went to cinema' },
{ id: 4, description: 'Listened to music' },
{ id: 5, description: 'Watched TV all day' },
{ id: 6, description: 'Walked for a hour' } ]
这是输出。
Seqelize offset
和limit
使用offset
和limit
属性,我们可以定义findAll()
方法中要包括的行的初始跳过和行数。
offset_limit.js
const Sequelize = require('sequelize');
const path = 'mysql://user12:12user@localhost:3306/mydb';
const sequelize = new Sequelize(path, {
operatorsAliases: false,
logging: false
});
let Note = sequelize.define('notes', {
description: Sequelize.STRING
});
async function getRows() {
let notes = await Note.findAll({ offset: 2, limit: 3,
attributes: ['id', 'description'], raw: true
});
console.log(notes);
sequelize.close();
}
getRows();
该示例从第二行开始还原三行。
$ node offset_limit.js
[ { id: 3, description: 'Went to cinema' },
{ id: 4, description: 'Listened to music' },
{ id: 5, description: 'Watched TV all day' } ]
这是输出。
Seqelize 顺序排序
为了在查询中包含ORDER BY
子句,我们使用order
选项。
order_by.js
const Sequelize = require('sequelize');
const path = 'mysql://user12:12user@localhost:3306/mydb';
const sequelize = new Sequelize(path, {
operatorsAliases: false
});
let Note = sequelize.define('notes', {
description: Sequelize.STRING
});
async function getRows() {
let notes = await Note.findAll({
order: [['description', 'DESC']],
attributes: ['id', 'description'], raw: true
})
console.log(notes);
sequelize.close();
}
getRows();
在示例中,我们从表中选择所有行,并按描述以降序对其进行排序。
$ node order_by.js
Executing (default): SELECT `id`, `description` FROM `notes` AS `notes`
ORDER BY `notes`.`description` DESC;
[ { id: 3, description: 'Went to cinema'}, { id: 5, description: 'Watched TV all day' },
{ id: 6, description: 'Walked for a hour'}, { id: 2, description: 'Visited friend' },
{ id: 1, description: 'Tai chi in the morning' },
{ id: 4, description: 'Listened to music' } ]
从输出中我们可以看到ORDER BY
子句已添加到查询中。
Seqelize Op.IN
运算符
使用Op.IN
运算符,我们可以确定指定的值是否与子查询或列表中的任何值匹配。
operator_in.js
const Sequelize = require('sequelize');
const Op = Sequelize.Op;
const path = 'mysql://user12:12user@localhost:3306/mydb';
const sequelize = new Sequelize(path, {
operatorsAliases: false,
logging: false
});
let Note = sequelize.define('notes', {
description: Sequelize.STRING
});
async function getRows() {
let notes = await Note.findAll({ where: { id: { [Op.in]: [3, 6] } } });
notes.forEach(note => {
console.log(`${note.id}: ${note.description}`);
});
sequelize.close();
}
getRows();
在示例中,我们选择与 ID 列表匹配的所有行。
$ node operator_in.js
3: Went to cinema
6: Walked for a hour
输出显示两行:ID 为 3 和 6。
Seqelize Op.between
运算符
使用Op.between
运算符,我们可以确定指定值是否与给定范围内的任何值匹配。
operator_between.js
const Sequelize = require('sequelize');
const Op = Sequelize.Op;
const path = 'mysql://user12:12user@localhost:3306/mydb';
const sequelize = new Sequelize(path, {
operatorsAliases: false,
logging: false
});
let Note = sequelize.define('notes', {
description: Sequelize.STRING
});
async function getRows() {
let notes = await Note.findAll({ where: { id: { [Op.between]: [3, 6] } }});
notes.forEach(note => {
console.log(`${note.id}: ${note.description}`);
});
sequelize.close();
}
getRows();
该示例使用Op.between
运算符显示行3..6
。
Sequelize belongsTo
Sequelize belongsTo
在源模型和提供的目标模型之间创建一对一的关联。 外键添加在源上。
belongs_to.js
const Sequelize = require('sequelize');
const path = 'mysql://user12:12user@localhost:3306/mydb';
const sequelize = new Sequelize(path, {
operatorsAliases: false,
logging: false
});
let Employee = sequelize.define('employees', {
name: Sequelize.STRING
});
let Project = sequelize.define('projects', {
name: Sequelize.STRING
});
Employee.belongsTo(Project);
let employees = [
{ name: 'Jane Brown' }, { name: 'Lucia Benner' }, { name: 'Peter Novak' }
];
sequelize.sync({ force: true }).then(() => {
return Employee.bulkCreate(employees);
}).then((employees) => {
let works = [];
let i = 0;
employees.forEach(employee => {
let pname = 'Project ' + String.fromCharCode('A'.charCodeAt() + i);
i++;
let work = Project.create({ name: pname }).then(project => {
employee.setProject(project);
});
works.push(work);
});
Promise.all(works).then(() => sequelize.close());
console.log('finish');
});
在示例中,我们有两个模型:Employee
和Project
。 我们使用belongsTo
在两个模型之间创建一对一关联。 我们将数据添加到模型中。
let Employee = sequelize.define('employees', {
name: Sequelize.STRING
});
let Project = sequelize.define('projects', {
name: Sequelize.STRING
});
我们定义了两个模型。
Employee.belongsTo(Project);
我们在Employee
和Project
模型之间创建一对一关联。 外键在Employee
中生成。
let employees = [
{ name: 'Jane Brown' }, { name: 'Lucia Benner' }, { name: 'Peter Novak' }
];
我们将创建三名员工。
let works = [];
works
数组用于存储生成的Promise
。
employees.forEach(employee => {
let pname = 'Project ' + String.fromCharCode('A'.charCodeAt() + i);
i++;
let work = Project.create({ name: pname }).then(project => {
employee.setProject(project);
});
works.push(work);
});
我们遍历所有员工,并为每个员工生成一个新项目。 setProject()
添加了一个新项目。 Project.create()
生成一个新的Promise
,将其添加到works
数组中。
Promise.all(works).then(() => sequelize.close());
Promise.all()
解析数组中的所有promise
。
接下来,我们检索联接的数据。 当我们生成还从其他表中获取关联数据的查询时,我们会渴望加载。 通过include
选项启用了预先加载。
belongs_to2.js
const Sequelize = require('sequelize');
const path = 'mysql://user12:12user@localhost:3306/mydb';
const sequelize = new Sequelize(path, {
operatorsAliases: false,
logging: false
});
let Employee = sequelize.define('employees', {
name: Sequelize.STRING
});
let Project = sequelize.define('projects', {
name: Sequelize.STRING
});
Employee.belongsTo(Project);
Employee.findAll({include: [Project]}).then(employees => {
employees.forEach(employee => {
console.log(`${employee.name} is in project ${employee.project.name}`);
});
}).finally(() => {
sequelize.close();
});
该示例列出了员工及其项目。
Employee.findAll({include: [Project]}).then(employees => {
在查询中,我们添加include
选项,其中包括关联的模型。
$ node belongs_to2.js
Jane Brown is in project Project A
Lucia Benner is in project Project B
Peter Novak is in project Project C
这是输出。
双向化一对一关系
双向关系在两个方向上均有效。 我们可以从源模型引用目标模型,反之亦然。 为了在模型之间创建双向一对一关系,我们将其与belongsTo()
和hasOne()
映射。
bidi_one2one.js
const Sequelize = require('sequelize');
const path = 'mysql://user12:12user@localhost:3306/mydb';
const sequelize = new Sequelize(path, {
operatorsAliases: false,
logging: false
});
let Employee = sequelize.define('employees', {
name: Sequelize.STRING
});
let Project = sequelize.define('projects', {
name: Sequelize.STRING
});
Employee.belongsTo(Project);
Project.hasOne(Employee);
Project.findAll({include: [Employee]}).then(projects => {
projects.forEach(project => {
console.log(`${project.name} belongs to user ${project.employee.name}`);
});
}).finally(() => {
sequelize.close();
});
在此示例中,我们从每个项目中检索一名员工。
Employee.belongsTo(Project);
Project.hasOne(Employee);
为了实现双向关联,我们还使用hasOne()
映射了模型。
$ node bidi_one2one.js
Project A belongs to user Jane Brown
Project B belongs to user Lucia Benner
Project C belongs to user Peter Novak
这是输出。
Sequelize hasMany
Sequelize hasMany
在源和提供的目标之间创建多对一关联。 外键添加到目标上。
one_to_many.js
const Sequelize = require('sequelize');
const path = 'mysql://user12:12user@localhost:3306/mydb';
const sequelize = new Sequelize(path, {
operatorsAliases: false,
logging: false
});
let User = sequelize.define('user', {
name: Sequelize.STRING,
});
let Task = sequelize.define('task', {
description: Sequelize.STRING,
});
User.hasMany(Task);
async function createTables() {
await User.sync();
await Task.sync();
console.log('done');
sequelize.close();
}
createTables();
首先,我们创建两个表:users
和tasks
。
在第二步中,我们用数据填充表。
one_to_many2.js
const Sequelize = require('sequelize');
const path = 'mysql://user12:12user@localhost:3306/mydb';
const sequelize = new Sequelize(path, {
operatorsAliases: false,
logging: false
});
let User = sequelize.define('user', {
name: Sequelize.STRING
});
let Task = sequelize.define('task', {
description: Sequelize.STRING,
});
User.hasMany(Task);
let mytasks1 = [
{ description: 'write memo' }, { description: 'check accounts' }
];
let mytasks2 = [
{ description: 'make two phone calls' },
{ description: 'read new emails' },
{ description: 'arrange meeting' }
];
async function addUsersTasks() {
let user1 = await User.create({ name: 'John Doe' });
let tasks1 = await Task.bulkCreate(mytasks1);
await user1.setTasks(tasks1);
let user2 = await User.create({ name: 'Debbie Griffin' });
let tasks2 = await Task.bulkCreate(mytasks2);
await user2.setTasks(tasks2);
console.log('done');
sequelize.close();
}
addUsersTasks();
我们有两个执行某些任务的用户。
let user1 = await User.create({ name: 'John Doe' });
使用User.create()
创建一个新用户。
let tasks1 = await Task.bulkCreate(mytasks1);
使用Task.bulkCreate()
生成新任务。
await user1.setTasks(tasks1);
使用setTasks()
将任务添加到用户。
最后,我们检索数据。
one_to_many3.js
const Sequelize = require('sequelize');
const path = 'mysql://user12:12user@localhost:3306/mydb';
const sequelize = new Sequelize(path, {
operatorsAliases: false,
logging: false
});
let User = sequelize.define('user', {
name: Sequelize.STRING
});
let Task = sequelize.define('task', {
description: Sequelize.STRING,
});
User.hasMany(Task);
async function showUsersTasks() {
let users = await User.findAll({ include: [Task] });
users.forEach(user => {
console.log(`${user.name} has tasks: `);
let tasks = user.tasks;
tasks.forEach(task => {
console.log(` * ${task.description}`);
})
});
console.log('done');
sequelize.close();
}
showUsersTasks();
在示例中,我们显示了所有用户及其关联的任务。
let users = await User.findAll({ include: [Task] });
要启用紧急加载,我们使用include
选项。 急切的加载是在查询中也检索关联的数据时。
$ node one_to_many3.js
John Doe has tasks:
* write memo * check accountsDebbie Griffin has tasks:
* make two phone calls * read new emails
* arrange meeting
done
这是输出。
双向一对多关系
双向一对多关系在两个方向上均有效。 为了在模型之间建立双向的一对多关系,我们使用hasMany()
和belongsTo()
映射它们。
bidi_one2many.js
const Sequelize = require('sequelize');
const path = 'mysql://user12:12user@localhost:3306/mydb';
const sequelize = new Sequelize(path, {
operatorsAliases: false,
logging: false
});
let User = sequelize.define('user', {
name: Sequelize.STRING
});
let Task = sequelize.define('task', {
description: Sequelize.STRING
});
User.hasMany(Task);
Task.belongsTo(User);
async function showTaskUser() {
let task = await Task.findOne({ include: [User] });
console.log(`${task.description} belongs to ${task.user.name}`);
sequelize.close();
}
showTaskUser();
该示例从检索的任务中获取用户。
User.hasMany(Task);
Task.belongsTo(User);
为了实现双向一对一关系,我们使用hasMany()
和belongsTo()
映射模型。
$ node bidi_one2many.js
write memo belongs to John Doe
这是输出。
在本教程中,我们使用了Seqeulize
库。 我们创建了一些与 MySQL 交互的命令行程序。
您可能也对以下相关教程感兴趣: Knex.js 教程, Node Postgres 教程, Lodash 教程,书架教程, 或列出所有 JavaScript 教程。
Bookshelf.js 教程
原文: http://zetcode.com/javascript/bookshelf/
Bookshelf.js 教程展示了如何使用 Bookshelf.js ORM 在 JavaScript 中对数据库进行编程。 Bookshelf.js 构建在 Knex 之上。
Bookshelf.js
Bookshelf.js 是基于 Knex SQL 查询生成器构建的 Node.js 的 JavaScript ORM。 它支持基于promise
和传统的回调接口。 书架提供事务支持,渴望/嵌套渴望的关系加载,多态关联以及对一对一,一对多和多对多关系的支持。
Bookshelf.js 可与 PostgreSQL,MySQL 和 SQLite3 一起使用。
对象关系映射(ORM)是一种从面向对象的语言访问关系数据库的技术。 它是 Python 数据库 API 的抽象。 在本教程中,我们使用 PostgreSQL。
城市表
我们使用城市表。
cities_postgresql.sql
DROP TABLE IF EXISTS cities;
CREATE TABLE cities(id serial PRIMARY KEY, name VARCHAR(255), population INT);
INSERT INTO cities(name, population) VALUES('Bratislava', 432000);
INSERT INTO cities(name, population) VALUES('Budapest', 1759000);
INSERT INTO cities(name, population) VALUES('Prague', 1280000);
INSERT INTO cities(name, population) VALUES('Warsaw', 1748000);
INSERT INTO cities(name, population) VALUES('Los Angeles', 3971000);
INSERT INTO cities(name, population) VALUES('New York', 8550000);
INSERT INTO cities(name, population) VALUES('Edinburgh', 464000);
INSERT INTO cities(name, population) VALUES('Berlin', 3671000);
安装 Bookshelf.js
我们安装书架。
$ node -v
v11.5.0
我们使用 Node 版本 11.5.0。
$ npm init -y
我们启动一个新的 Node 应用。
$ npm i pg
$ npm i knex bookshelf
我们安装了 PostgreSQL 驱动程序 Knex.js 和 Bookshelf.js。
Bookshelf.js计数行
在第一个示例中,我们计算cities
表中的行数。
config/db.js
const knex = require('knex')({
client: 'pg',
connection: {
host: '127.0.0.1',
user: 'postgres',
password: '',
database: 'testdb',
charset: 'utf8'
}
});
module.exports.knex = knex;
在db.js
文件中,我们定义一个 Knex 客户端对象。
model/city.js
const knex = require('../config/db').knex;
const bookshelf = require('bookshelf')(knex);
const City = bookshelf.Model.extend({
tableName: 'cities'
});
module.exports = City;
我们有模型对象。 模型对象映射到数据库表中的一行。
count_cities.js
const knex = require('./config/db').knex;
const City = require('./model/city');
City.count().then((count) => {
console.log(`There are ${count} cities`);
}).catch((err) => {
console.log(err);
}).finally(() => {
knex.destroy();
});
该示例计算cities
表中的行数。 它使用回调。
$ node count_cities.js
There are 8 cities
这是输出。
count_cities2.js
const knex = require('./config/db').knex;
const City = require('./model/city');
async function countCities() {
try {
let count = await City.count();
console.log(`There are ${count} cities`);
} catch (e) {
logger.info(`No data found ${e}`);
} finally {
knex.destroy();
}
}
countCities();
在第二个示例中,我们将promise
与async/await
一起使用。
Bookshelf.js fetch()
fetch()
使用当前在模型上设置的任何属性来从数据库获取模型,以形成选择查询。 设置require
选项后,如果结果为空,则返回的响应将被NotFoundError
拒绝。
$ npm i winston
在此示例中,我们还使用 Winston 日志记录模块。
fetch_city.js
const knex = require('./config/db').knex;
const City = require('./model/city');
const winston = require('winston');
const consoleTransport = new winston.transports.Console()
const options = {
transports: [consoleTransport]
}
const logger = new winston.createLogger(options)
async function fetch_city() {
try {
let val = await City.where({ 'name': 'Bratislava' }).fetch({require:true});
// console.log(val.toJSON());
logger.info(val);
} catch (e) {
logger.info(`No data found ${e}`);
} finally {
knex.destroy();
}
}
fetch_city();
该示例检索指定的城市。
let val = await City.where({ 'name': 'Bratislava' }).fetch({require:true});
我们获取一个名为'Bratislava'
的模型。
logger.info(val);
我们记录返回的数据。
$ node fetch_city.js
{"message":{"id":1,"name":"Bratislava","population":432000},"level":"info"}
这是输出。
Bookshelf.js fetch_all
fetch_all()
使用当前在模型上设置的任何查询参数从数据库中获取模型的集合,以形成选择查询。
fetch_all.js
const knex = require('./config/db').knex;
const City = require('./model/city');
async function fetch_all() {
try {
let vals = await City.fetchAll();
console.log(vals.toJSON());
} catch (e) {
console.log(`Failed to fetch data: ${e}`);
} finally {
knex.destroy();
}
}
fetch_all();
该示例检索所有城市。
let vals = await City.fetchAll();
我们称为fetchAll()
函数。
console.log(vals.toJSON());
数据以 JSON 格式写入控制台。
$ node fetch_all.js
[ { id: 1, name: 'Bratislava', population: 432000 },
{ id: 2, name: 'Budapest', population: 1759000 },
{ id: 3, name: 'Prague', population: 1280000 },
{ id: 4, name: 'Warsaw', population: 1748000 },
{ id: 5, name: 'Los Angeles', population: 3971000 },
{ id: 6, name: 'New York', population: 8550000 },
{ id: 7, name: 'Edinburgh', population: 464000 },
{ id: 8, name: 'Berlin', population: 3671000 } ]
这是输出。
Bookshelf.js forge()
辅助函数
Bookshelf 的forge()
是一个简单的辅助函数,可在不需要new
关键字的情况下实例化新模型。
forge_helper.js
const knex = require('./config/db').knex;
const City = require('./model/city');
async function fetch_city() {
try {
let val = await City.forge({ 'id': '4' }).fetch();
console.log(val.toJSON());
} catch (e) {
console.info(`No data found ${e}`);
} finally {
knex.destroy();
}
}
fetch_city();
在示例中,我们使用forge()
帮助器选择一个城市。
Bookshelf.js save()
用save()
保存新模型。
save_city.js
const knex = require('./config/db').knex;
const City = require('./model/city');
async function save_city() {
try {
let val = await City.forge({ 'name': 'Kyiv', 'population': 2884000}).save();
console.log(val.toJSON());
} catch (e) {
console.log(`Failed to save data: ${e}`);
} finally {
knex.destroy();
}
}
save_city();
该示例将保存一个新城市。
$ node save_city.js
{ name: 'Kyiv', population: 2884000, id: 9 }
$ node fetch_all.js
[ { id: 1, name: 'Bratislava', population: 432000 },
{ id: 2, name: 'Budapest', population: 1759000 },
{ id: 3, name: 'Prague', population: 1280000 },
{ id: 4, name: 'Warsaw', population: 1748000 },
{ id: 5, name: 'Los Angeles', population: 3971000 },
{ id: 6, name: 'New York', population: 8550000 },
{ id: 7, name: 'Edinburgh', population: 464000 },
{ id: 8, name: 'Berlin', population: 3671000 },
{ id: 9, name: 'Kyiv', population: 2884000 } ]
这是输出。
Bookshelf.js orderBy()
orderBy()
函数按指定的列名和排序顺序对检索到的数据进行排序。 order
参数是可选的,默认为'ASC'。
order_by.js
const knex = require('./config/db').knex;
const City = require('./model/city');
async function fetch_city() {
try {
let vals = await City.forge().orderBy('name', 'DESC').fetchAll({require:true});
console.log(vals.toJSON());
} catch (e) {
console.log(`Failed to fetch data: ${e}`);
} finally {
knex.destroy();
}
}
fetch_city();
在示例中,我们获取所有城市,并按名称降序排列它们。
$ node order_by.js
[ { id: 4, name: 'Warsaw', population: 1748000 },
{ id: 3, name: 'Prague', population: 1280000 },
{ id: 6, name: 'New York', population: 8550000 },
{ id: 5, name: 'Los Angeles', population: 3971000 },
{ id: 9, name: 'Kyiv', population: 2884000 },
{ id: 7, name: 'Edinburgh', population: 464000 },
{ id: 2, name: 'Budapest', population: 1759000 },
{ id: 1, name: 'Bratislava', population: 432000 },
{ id: 8, name: 'Berlin', population: 3671000 } ]
这是输出。
Bookshelf.js 一对一关系
一对一的关系由hasOne()
和belongsTo()
函数定义。
employees_projects.sql
DROP TABLE IF EXISTS employees;
DROP TABLE IF EXISTS projects;
CREATE TABLE projects(id serial PRIMARY KEY, name VARCHAR(255));
INSERT INTO projects(name) VALUES('Project A');
INSERT INTO projects(name) VALUES('Project B');
INSERT INTO projects(name) VALUES('Project C');
CREATE TABLE employees(id serial PRIMARY KEY, project_id INT REFERENCES projects (id),
name VARCHAR(255));
INSERT INTO employees(project_id, name) VALUES(2, 'John Doe');
INSERT INTO employees(project_id, name) VALUES(1, 'Lucia Smith');
我们有employees
和projects
。 员工只能分配到一个项目。
Bookshelf.js hasOne()
hasOne()
函数定义模型之间的一对一关系。 hasOne
关系指定表恰好具有另一种对象类型,该对象由另一表中的外键指定。
model/project.js
const knex = require('../config/db').knex;
const bookshelf = require('bookshelf')(knex);
const Employee = require('./employee');
const Project = bookshelf.Model.extend({
tableName: 'projects',
employee: function () {
return this.hasOne(Employee);
}
});
module.exports = Project;
Project
模型包含hasOne()
函数。 通过查询项目,我们可以获取其链接的员工。
model/employee.js
const knex = require('../config/db').knex;
const bookshelf = require('bookshelf')(knex);
const Employee = bookshelf.Model.extend({
tableName: 'employees'
});
module.exports = Employee;
这是Employee
模型。
has_one.js
const knex = require('./config/db').knex;
const Project = require('./model/project');
async function doQuery() {
try {
let val = await Project.where({ id: 2 }).fetch({
withRelated: ['employee']
});
console.log(val.toJSON());
} catch (e) {
console.log(`Failed to fetch data: ${e}`);
} finally {
knex.destroy();
}
}
doQuery();
在示例中,我们获取一个项目及其关联的员工。
let val = await Project.where({ id: 3 }).fetch({
withRelated: ['employee']
});
指定withRelated
选项以获取集合的模型,并希望加载该模型上命名的任何指定关系。 如果没有此选项,我们将仅获得没有关联员工的项目。
$ node has_one.js
{ id: 2,
name: 'Project B',
employee: { id: 1, project_id: 2, name: 'John Doe' } }
这是输出。
Bookshelf.js belongsTo()
一对一
当一个模型是另一个目标模型的成员时,将使用belongsTo()
函数。 外键在当前(源)模型中定义。 belongsTo()
函数用于一对一和one-to-many
关系。
model/project.js
const knex = require('../config/db').knex;
const bookshelf = require('bookshelf')(knex);
const Project = bookshelf.Model.extend({
tableName: 'projects'
});
module.exports = Project;
这是Project
模型。
model/employee.js
const knex = require('../config/db').knex;
const bookshelf = require('bookshelf')(knex);
const Project = require('./project');
const Employee = bookshelf.Model.extend({
tableName: 'employees',
project: function () {
return this.belongsTo(Project);
}
});
module.exports = Employee;
Employee
包含belongsTo()
函数。
belongs_to.js
const knex = require('./config/db').knex;
const Employee = require('./model/employee');
async function doQuery() {
try {
let val = await Employee.where({ id: 1 }).fetch({
withRelated: ['project'], require: true
});
console.log(val.toJSON());
} catch (e) {
console.log(`Failed to fetch data: ${e}`);
} finally {
knex.destroy();
}
}
doQuery();
在该示例中,我们通过其链接项目获取一名雇员。
$ node belongs_to.js
{ id: 1,
project_id: 2,
name: 'John Doe',
project: { id: 2, name: 'Project B' } }
这是输出。
Bookshelf.js 一对多关系
一对多关系通过hasMany()
和belongsTo()
函数定义。
users_tasks.js
DROP TABLE IF EXISTS tasks;
DROP TABLE IF EXISTS users;
CREATE TABLE users(id serial PRIMARY KEY, name VARCHAR(255));
INSERT INTO users(name) VALUES('John Doe');
INSERT INTO users(name) VALUES('Lucia Smith');
CREATE TABLE tasks(id serial PRIMARY KEY, user_id INT REFERENCES users (id),
name VARCHAR(255));
INSERT INTO tasks(user_id, name) VALUES(1, 'Task A');
INSERT INTO tasks(user_id, name) VALUES(1, 'Task B');
INSERT INTO tasks(user_id, name) VALUES(1, 'Task C');
INSERT INTO tasks(user_id, name) VALUES(2, 'Task D');
INSERT INTO tasks(user_id, name) VALUES(2, 'Task E');
我们有users
和tasks
。 用户可以执行一个或多个任务。 一个任务只能由一个用户拥有。
Bookshelf.js hasMany()
hasMany()
定义了模型之间的一对多关系。 该关系指定当前模型在另一张表中具有一个或多个与该模型的主键匹配的行。
model/user.js
const knex = require('../config/db').knex;
const bookshelf = require('bookshelf')(knex);
const Task = require('./task');
const User = bookshelf.Model.extend({
tableName: 'users',
tasks: function() {
return this.hasMany(Task);
}
});
module.exports = User;
User
模型包含hasMany()
函数。
model/task.js
const knex = require('../config/db').knex;
const bookshelf = require('bookshelf')(knex);
const Task = bookshelf.Model.extend({
tableName: 'tasks',
});
module.exports = Task;
这是Task
模型。
has_many.js
const knex = require('./config/db').knex;
const User = require('./model/user');
async function doQuery() {
try {
let val = await User.where({ id: 1 }).fetch({
withRelated: ['tasks'], require: true
});
console.log(val.toJSON());
} catch (e) {
console.log(`Failed to fetch data: ${e}`);
} finally {
knex.destroy();
}
}
doQuery();
在示例中,我们获取用户及其任务。
$ node has_many.js
{ id: 1,
name: 'John Doe',
tasks:
[ { id: 1, user_id: 1, name: 'Task A' },
{ id: 2, user_id: 1, name: 'Task B' },
{ id: 3, user_id: 1, name: 'Task C' } ] }
ID 为 1 的用户具有三个任务。
Bookshelf.js belongsTo()
一对多
在一对多的情况下,belongsTo()
是hasMany()
的倒数,并且是关联的一侧。
model/user.js
const knex = require('../config/db').knex;
const bookshelf = require('bookshelf')(knex);
const User = bookshelf.Model.extend({
tableName: 'users',
});
module.exports = User;
这是User
模型。
model/task.js
const knex = require('../config/db').knex;
const bookshelf = require('bookshelf')(knex);
const User = require('./user');
const Task = bookshelf.Model.extend({
tableName: 'tasks',
user: function() {
return this.belongsTo(User);
}
});
module.exports = Task;
Task
模型包含belongsTo()
函数。
belongs_to2.js
const knex = require('./config/db').knex;
const Task = require('./model/task');
async function doQuery() {
try {
let val = await Task.where({ id: 4 }).fetch({
withRelated: ['user'], require: true
});
console.log(val.toJSON());
} catch (e) {
console.log(`Failed to fetch data: ${e}`);
} finally {
knex.destroy();
}
}
doQuery();
在示例中,我们与任务的关联用户一起获取任务。
在本教程中,我们使用书架库。 我们创建了一些与 PostgreSQL 交互的命令行程序。
您可能也对以下相关教程感兴趣: Sequelize 教程, Node Postgres 教程或 JavaScript 教程。
Node Postgres 教程
原文: http://zetcode.com/javascript/nodepostgres/
Node Postgres 教程展示了如何通过node-postgres
在 JavaScript 中使用 PostgreSQL 数据库。
Node postgres
node-postgres
是 Node.js 模块的集合,用于与 PostgreSQL 数据库接口。 它支持回调,promise,异步/等待,连接池,准备好的语句,游标和流式结果。
在我们的示例中,我们还使用 Ramda 库。 有关更多信息,请参见 Ramda 教程。
安装node-postgres
首先,我们安装node-postgres
。
$ node -v
v11.5.0
我们使用 Node 版本 11.5.0。
$ npm init -y
我们启动一个新的 Node 应用。
$ npm i pg
我们使用nmp i pg
安装 node-postgres。
$ npm i ramda
另外,我们安装 Ramda 来处理数据。
cars.sql
DROP TABLE IF EXISTS cars;
CREATE TABLE cars(id SERIAL PRIMARY KEY, name VARCHAR(255), price INT);
INSERT INTO cars(name, price) VALUES('Audi', 52642);
INSERT INTO cars(name, price) VALUES('Mercedes', 57127);
INSERT INTO cars(name, price) VALUES('Skoda', 9000);
INSERT INTO cars(name, price) VALUES('Volvo', 29000);
INSERT INTO cars(name, price) VALUES('Bentley', 350000);
INSERT INTO cars(name, price) VALUES('Citroen', 21000);
INSERT INTO cars(name, price) VALUES('Hummer', 41400);
INSERT INTO cars(name, price) VALUES('Volkswagen', 21600);
在某些示例中,我们使用此cars
表。
node-postgres
第一个示例
在第一个示例中,我们连接到 PostgreSQL 数据库并返回一个简单的SELECT
查询结果。
first.js
const pg = require('pg');
const R = require('ramda');
const cs = 'postgres://postgres:s$cret@localhost:5432/ydb';
const client = new pg.Client(cs);
client.connect();
client.query('SELECT 1 + 4').then(res => {
const result = R.head(R.values(R.head(res.rows)));
console.log(result);
}).finally(() => client.end());
该示例连接到数据库并发出SELECT
语句。
const pg = require('pg');
const R = require('ramda');
我们包括pg
和ramda
模块。
const cs = 'postgres://postgres:s$cret@localhost:5432/ydb';
这是 PostgreSQL 连接字符串。 它用于建立与数据库的连接。
const client = new pg.Client(cs);
client.connect();
创建一个客户端。 我们使用connect()
连接到数据库。
client.query('SELECT 1 + 4').then(res => {
const result = R.head(R.values(R.head(res.rows)));
console.log(result);
}).finally(() => client.end());
我们发出一个简单的SELECT
查询。 我们得到结果并将其输出到控制台。 res.rows
是一个对象数组; 我们使用 Ramda 来获取返回的标量值。 最后,我们使用end()
关闭连接。
$ node first.js
5
这是输出。
node-postgres
列名称
在下面的示例中,我们获取数据库的列名称。
column_names.js
const pg = require('pg');
const cs = 'postgres://postgres:s$cret@localhost:5432/ydb';
const client = new pg.Client(cs);
client.connect();
client.query('SELECT * FROM cars').then(res => {
const fields = res.fields.map(field => field.name);
console.log(fields);
}).catch(err => {
console.log(err.stack);
}).finally(() => {
client.end()
});
列名使用res.fields
属性检索。 我们还使用catch
子句输出潜在的错误。
$ node column_names.js
[ 'id', 'name', 'price' ]
输出显示cars
表的三个列名称。
选择所有行
在下一个示例中,我们从数据库表中选择所有行。
all_rows.js
const pg = require('pg');
const R = require('ramda');
const cs = 'postgres://postgres:s$cret@localhost:5432/ydb';
const client = new pg.Client(cs);
client.connect();
client.query('SELECT * FROM cars').then(res => {
const data = res.rows;
console.log('all data');
data.forEach(row => {
console.log(`Id: ${row.id} Name: ${row.name} Price: ${row.price}`);
})
console.log('Sorted prices:');
const prices = R.pluck('price', R.sortBy(R.prop('price'), data));
console.log(prices);
}).finally(() => {
client.end()
});
该示例输出cars
表中的所有行以及汽车价格的排序列表。
$ node all_rows.js
all data
Id: 1 Name: Audi Price: 52642
Id: 2 Name: Mercedes Price: 57127
Id: 3 Name: Skoda Price: 9000
Id: 4 Name: Volvo Price: 29000
Id: 5 Name: Bentley Price: 350000
Id: 6 Name: Citroen Price: 21000
Id: 7 Name: Hummer Price: 41400
Id: 8 Name: Volkswagen Price: 21600
Sorted prices:
[ 9000, 21000, 21600, 29000, 41400, 52642, 57127, 350000 ]
这是输出。
node-postgres
参数化查询
参数化查询使用占位符,而不是直接将值写入语句。 参数化查询可提高安全性和性能。
parameterized.js
const pg = require('pg');
const cs = 'postgres://postgres:s$cret@localhost:5432/ydb';
const client = new pg.Client(cs);
client.connect();
const sql = 'SELECT * FROM cars WHERE price > $1';
const values = [50000];
client.query(sql, values).then(res => {
const data = res.rows;
data.forEach(row => console.log(row));
}).finally(() => {
client.end()
});
该示例在简单的SELECT
语句中使用参数化查询。
const sql = 'SELECT * FROM cars WHERE price > $1';
这是SELECT
查询。 $1
是一个占位符,以后会以安全的方式替换为一个值。
const values = [50000];
这些是要插入到参数化查询中的值。
client.query(sql, values).then(res => {
这些值作为第二个参数传递到query()
方法。
$ node parameterized.js
{ id: 1, name: 'Audi', price: 52642 }
{ id: 2, name: 'Mercedes', price: 57127 }
{ id: 5, name: 'Bentley', price: 350000 }
这是输出。
使用async/await
的node-postgres
Node Postgres 支持async/await
语法。
async_await.js
const pg = require('pg');
const R = require('ramda');
const cs = 'postgres://postgres:s$cret@localhost:5432/ydb';
async function fetchNow() {
const client = new pg.Client(cs);
try {
await client.connect();
let result = await client.query('SELECT now()');
return R.prop('now', R.head(result.rows));
} finally {
client.end()
}
}
fetchNow().then(now => console.log(now));
该示例使用async/await
输出SELECT now()
查询的结果。
$ node async_await.js
2019-02-17T11:53:01.447Z
这是输出。
node-postgres
行模式
默认情况下,node-postgres
将数据作为对象数组返回。 我们可以告诉node-postgres
以数组的形式返回数据。
row_mode.js
const pg = require('pg');
const R = require('ramda');
const cs = 'postgres://postgres:s$cret@localhost:5432/ydb';
const client = new pg.Client(cs);
client.connect();
const query = {
text: 'SELECT * FROM cars',
rowMode: 'array'
};
client.query(query).then(res => {
const data = res.rows;
console.log('all data');
data.forEach(row => {
console.log(`Id: ${row[0]} Name: ${row[1]} Price: ${row[2]}`);
})
console.log('Sorted prices:');
const prices = data.map(x => x[2]);
const sorted = R.sort(R.comparator(R.lt), prices);
console.log(sorted);
}).finally(() => {
client.end()
});
该示例显示cars
表中的所有行。 它启用数组行模式。
const query = {
text: 'SELECT * FROM cars',
rowMode: 'array'
};
我们使用将rowMode
设置为array
的配置对象。
console.log('all data');
data.forEach(row => {
console.log(`Id: ${row[0]} Name: ${row[1]} Price: ${row[2]}`);
})
现在我们遍历数组数组。
$ node row_mode.js
all data
Id: 1 Name: Audi Price: 52642
Id: 2 Name: Mercedes Price: 57127
Id: 3 Name: Skoda Price: 9000
Id: 4 Name: Volvo Price: 29000
Id: 5 Name: Bentley Price: 350000
Id: 6 Name: Citroen Price: 21000
Id: 7 Name: Hummer Price: 41400
Id: 8 Name: Volkswagen Price: 21600
Sorted prices:
[ 9000, 21000, 21600, 29000, 41400, 52642, 57127, 350000 ]
这是输出。
node-postgres
池化示例
连接池可提高数据库应用的性能。 它是特别有用的 Web 应用。
pooled.js
const pg = require('pg');
var config = {
user: 'postgres',
password: 's$cret',
database: 'ydb'
}
const pool = new pg.Pool(config);
pool.connect()
.then(client => {
return client.query('SELECT * FROM cars WHERE id = $1', [1])
.then(res => {
client.release();
console.log(res.rows[0]);
})
.catch(e => {
client.release();
console.log(e.stack);
})
}).finally(() => pool.end());
该示例说明如何设置一个使用连接池的示例。 完成查询后,我们将调用client.release()
方法将连接返回到池。
}).finally(() => pool.end());
pool.end()
耗尽所有活动客户端的池,断开它们的连接,并关闭该池中的所有内部计时器。 在此示例的脚本中使用了此方法。 在 Web 应用中,我们可以在 Web 服务器关闭或根本不调用时调用它。
在本教程中,我们使用node-postgres
与 Node.js 中的 PostgreSQL 进行交互。
您可能也对以下相关教程感兴趣: Knex.js 教程, Sequelize 教程,从 JavaScript 中的 URL 读取 JSON , JavaScript 贪食蛇教程 , JQuery 教程, Node Sass 教程, Lodash 教程。
Node Sass 教程
原文: http://zetcode.com/javascript/nodesass/
Node Sass 教程展示了如何使用node-sass
模块。 node-sass
模块用于将 Sass 代码转换为 CSS 代码。
Sass
Sass 是一种预处理器脚本语言,可解释或编译为级联样式表(CSS)。 Sass 包含两种语法。 较早的语法使用缩进来分隔代码块,并使用换行符来分隔规则。 较新的语法 SCSS 使用类似于 CSS 的块格式。 它使用花括号来表示代码块,并使用分号来分隔块内的行。
传统上,缩进语法和 SCSS 文件分别具有扩展名.sass
和.scss
。
Node-sass
Node-sass 是一个库,提供了 Node.js 与 LibSass(流行的样式表预处理器 Sass 的 C 版本)的绑定。 它允许我们将 SCSS 文件本地编译为 CSS。
Node Sass 示例
在下面的示例中,我们创建一个使用node-sass
模块的简单 Web 项目。
$ mkdir sass
$ mkdir public/css
在项目目录中,我们创建三个子目录。 在sass
目录中,我们将有 SCSS 代码。 SCSS 代码将转换为 CSS,然后移至public/css
目录。
$ nodejs -v
v9.11.2
我们使用 Node 版本 9.11.2。
$ npm init
我们启动一个新的 Node 应用。
$ npm i node-sass
我们安装node-sass
模块。 我们使用该模块来监视 SCSS 文件并将其自动转换为 CSS 代码。
$ npm install -g live-server
另外,我们安装live-server
,这是一个具有实时重载功能的小型开发服务器。
package.json
{
"name": "js-nodesass",
"version": "1.0.0",
"description": "node-sass example",
"main": "index.js",
"scripts": {
"sass": "node-sass -w sass -o public/css"
},
"author": "Jan Bodnar",
"license": "BSD",
"dependencies": {
"node-sass": "^4.9.0"
}
}
在package.json
文件中,我们创建一个运行node-sass
模块的脚本。 它将监视sass
目录,并将编译后的代码输出到public/css
目录。
public/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="css/main.css">
<title>Home page</title>
</head>
<body>
<div class="container">
<h1>Bugs</h1>
<table>
<tr>
<th>Bug name</th>
<th>Description</th>
</tr>
<tr>
<td>Assasin bug</td>
<td>The assassin bug uses its short three-segmented beak to pierce
its prey and eat it.</td>
</tr>
<tr>
<td>Bed bug</td>
<td>Bed bugs are parasitic insects in the that feed exclusively
on blood.</td>
</tr>
<tr>
<td>Carpet beetle</td>
<td>Considered a pest of domestic houses and, particularly, natural
history museums where the larvae may damage natural fibers and
can damage carpets, furniture, clothing, and insect collections.</td>
</tr>
<tr>
<td>Earwig</td>
<td>Earwigs are mostly nocturnal and often hide in small, moist
crevices during the day, and are active at night, feeding on
a wide variety of insects and plants.</td>
</tr>
</table>
</div>
</body>
</html>
这是一个包含一些数据的 HTML 文件。 本文档使用 CSS 文件设置样式。
<link rel="stylesheet" href="css/main.css">
CSS 代码是从css/main
目录加载的。
sass/main.scss
$myfont: Georgia 1.1em;
$table_head_col: #ccc;
$table_row_col: #eee;
$table_bor_col: #eee;
$container_width: 700px;
$first_col_width: 150px;
div.container {
margin: auto;
font: $myfont;
width: $container_width;
}
table {
tr:nth-child(odd) {background: $table_row_col}
td:first-child {width: $first_col_width}
th {
background-color: $table_head_col;
}
border: 1px solid $table_bor_col;
}
这是我们的 SCSS 代码。 我们设置容器和表格的样式。 该代码使用两个重要的 SCSS 功能:变量和嵌套。
$ npm run sass
我们运行sass
脚本。
$ live-server --open=public
最后,我们启动开发服务器。
图:示例应用
在本教程中,我们使用了node-sass
模块。 我们在一个简单的 Web 应用中使用了该模块,将其 SCSS 代码编译为 CSS 代码。
您可能也对以下相关教程感兴趣: Liquid.js 教程, JSON 服务器教程, Gulp Sass 教程, jQuery 自动完成教程或使用 jQuery DatePicker
。
Document.querySelector
教程
标题: http://zetcode.com/javascript/queryselector/
Document.querySelector
教程显示了如何使用querySelector
选择 JavaScript 中的 HTML 元素。
Document.querySelector
Document
的querySelector()
方法返回文档中与指定选择器或一组选择器匹配的第一个元素。 如果找不到匹配项,则返回null
。
querySelectorAll()
返回一个静态NodeList
,代表与指定选择器组匹配的文档元素列表。
Document.querySelector
示例
下面的示例演示querySelector()
和querySelectorAll()
方法的用法。
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document.querySelector</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.3.1/components/button.min.css">
<style>
body { margin: 3em }
.selected { background-color: #eee }
.container {
display: grid;
grid-template-columns: 100px 100px 100px 100px 100px;
grid-template-rows: 50px;
grid-column-gap:5px;
margin-bottom: 1em;
}
div>div {
border: 1px solid #ccc;
}
</style>
</head>
<body>
<div class="container">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<button id="first" type="submit" class="ui grey button">First</button>
<button id="all" type="submit" class="ui brown button">All</button>
<button id="clear" type="submit" class="ui brown button">Clear</button>
<script src="main.js"></script>
</body>
</html>
在文档中,我们显示五个带边框的div
元素。 我们有三个按钮。 每个按钮都会更改div
的外观。
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.3.1/components/button.min.css">
我们使用语义 UI 设置文档样式。
.selected { background-color: #eee }
所选的div
具有灰色背景色。
.container {
display: grid;
grid-template-columns: 100px 100px 100px 100px 100px;
grid-template-rows: 50px;
grid-column-gap:5px;
margin-bottom: 1em;
}
使用 CSS 网格布局系统将div
一行显示。
div>div {
border: 1px solid #ccc;
}
容器div
中的div
具有灰色边框。
<div class="container">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
父容器div
中有五个div
。
<button id="first" type="submit" class="ui grey button">First</button>
<button id="all" type="submit" class="ui brown button">All</button>
<button id="clear" type="submit" class="ui brown button">Clear</button>
我们在文档中有三个按钮。 第一个按钮更改第一个内部div
的背景颜色。 全部按钮更改所有内部div
。 并且“清除”按钮清除div
的背景。 这些按钮具有语义 UI 样式。
<script src="main.js"></script>
JavaScript 代码位于main.js
文件中。
main.js
document.getElementById("first").onclick = (e) => {
let tag = document.querySelector(".container div:first-child");
tag.className = "selected";
};
document.getElementById("all").onclick = (e) => {
let tags = document.querySelectorAll(".container div");
tags.forEach( tag => {
tag.className = "selected";
});
};
document.getElementById("clear").onclick = (e) => {
let tags = document.querySelectorAll(".container div");
tags.forEach( tag => {
tag.classList.remove("selected");
});
};
在main.js
文件中,我们实现了按钮的功能。
document.getElementById("first").onclick = (e) => {
单击监听器将添加到具有onclick
属性的按钮。 用getElementById()
选择按钮。
let tag = document.querySelector(".container div:first-child");
使用querySelector()
方法,我们在容器div
中选择了第一个内部div
。
tag.className = "selected";
我们将selected
类添加到所选标签。
let tags = document.querySelectorAll(".container div");
使用querySelectorAll()
,我们选择所有内部div
。
tags.forEach( tag => {
tag.className = "selected";
});
在forEach()
循环中,我们遍历列表并将类附加到每个元素。
图:使用Document.querySelector
选择元素
在屏幕截图中,我们可以看到第一个div
的背景色已更改。
在本教程中,我们使用了querySelector()
和querySelectorAll()
方法。
您可能也对以下相关教程感兴趣: JavaScript Lodash 教程, Document.all
教程, JSON 服务器教程,从 URL 中读取 JSON JavaScript , JavaScript 贪食蛇教程, JQuery 教程, jQuery 自动完成教程或使用 jQuery DatePicker
。
Document.all
教程
原文: http://zetcode.com/javascript/documentall/
Document.all
教程展示了如何使用all
属性选择 JavaScript 中的所有 HTML 元素。
Document.all
Document 的all
属性返回一个以文档节点为根的HTMLAllCollection
-它返回页面的全部内容。 该属性是只读的。
在我们的示例中,我们将使用 Ramda 库遍历返回的HTMLAllCollection
。 有关更多信息,请参见 Ramda 教程。
Document.all
示例
下面的示例演示文档all
属性的用法。
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
</head>
<body>
<p>
This is simple web document.
</p>
<script>
let allTags = document.all;
let nOfTags = R.length(R.keys(allTags));
console.log(`There are ${nOfTags} tags in the document`);
console.log('List of tags:');
R.forEachObjIndexed((value, key) => {
console.log(`${key}: ${value.localName}`);
}, allTags);
</script>
</body>
</html>
在文档中,我们显示元素的数量及其列表。
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
我们包括 Ramda 库。
let allTags = document.all;
使用document.all
获取所有标签。
let nOfTags = R.length(R.keys(allTags));
console.log(`There are ${nOfTags} tags in the document`);
我们计算标签的数量并将消息显示到控制台。
R.forEachObjIndexed((value, key) => {
console.log(`${key}: ${value.localName}`);
}, allTags);
使用 Ramda 的forEachObjIndexed()
,我们遍历集合并输出所有标签名称。
在本教程中,我们使用了文档的all
属性。
您可能也对以下相关教程感兴趣: JavaScript queryselector
教程, Element.innerHtml
教程, JavaScript Lodash 教程, JQuery 教程 , Ramda 教程或使用 jQuery DatePicker
。
JSON 服务器教程
原文: http://zetcode.com/javascript/jsonserver/
JSON 服务器教程介绍了 JavaScript json-server
库,该库可用于创建伪造的 REST API。
JSON 服务器
json 服务器是一个 JavaScript 库,用于创建测试 REST API。
JSON 服务器安装
首先,我们创建一个项目目录并安装json-server
模块。
$ mkdir json-server-lib
$ cd json-server-lib
$ npm init -y
$ npm i -g json-server
JSON 服务器模块与npm
一起全局安装。
$ npm install axios
此外,我们安装了axios
模块,这是一个基于Promise
的 JavaScript HTTP 客户端。
$ cat package.json
{
"name": "json-server-lib",
"version": "1.0.0",
"description": "",
"main": "index.js",
"dependencies": {
"axios": "^0.18.0"
},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
这是我们的package.json
文件。
JSON 测试数据
我们有一些 JSON 测试数据:
users.json
{
"users": [
{
"id": 1,
"first_name": "Robert",
"last_name": "Schwartz",
"email": "rob23@gmail.com"
},
{
"id": 2,
"first_name": "Lucy",
"last_name": "Ballmer",
"email": "lucyb56@gmail.com"
},
{
"id": 3,
"first_name": "Anna",
"last_name": "Smith",
"email": "annasmith23@gmail.com"
},
{
"id": 4,
"first_name": "Robert",
"last_name": "Brown",
"email": "bobbrown432@yahoo.com"
},
{
"id": 5,
"first_name": "Roger",
"last_name": "Bacon",
"email": "rogerbacon12@yahoo.com"
}
]
}
启动 JSON 服务器
JSON 服务器从json-server
启动,该服务器已在全球范围内安装。
$ json-server --watch users.json
--watch
命令用于指定服务器的数据。
$ curl localhost:3000/users/3/
{
"id": 3,
"first_name": "Anna",
"last_name": "Smith",
"email": "annasmith23@gmail.com"
}
使用curl
命令,我们为用户提供 ID 3。
JSON 服务器 GET 请求
在下一个示例中,我们使用 GET 请求检索数据。
get_request.js
const axios = require('axios');
axios.get('http://localhost:3000/users')
.then(resp => {
data = resp.data;
data.forEach(e => {
console.log(`${e.first_name}, ${e.last_name}, ${e.email}`);
});
})
.catch(error => {
console.log(error);
});
使用 axios 模块,我们将所有用户作为 JSON 数组获取,并使用forEach()
遍历它。
$ node get_request.js
Robert, Schwartz, rob23@gmail.com
Lucy, Ballmer, lucyb56@gmail.com
Anna, Smith, annasmith23@gmail.com
Robert, Brown, bobbrown432@yahoo.com
Roger, Bacon, rogerbacon12@yahoo.com
这是示例的输出。 我们得到所有用户并打印其全名和电子邮件。
JSON 服务器 POST 请求
通过 POST 请求,我们创建了一个新用户。
post_request.js
const axios = require('axios');
axios.post('http://localhost:3000/users', {
id: 6,
first_name: 'Fred',
last_name: 'Blair',
email: 'freddyb34@gmail.com'
}).then(resp => {
console.log(resp.data);
}).catch(error => {
console.log(error);
});
使用 axios 创建一个新用户。
$ node post_request.js
{ id: 6,
first_name: 'Fred',
last_name: 'Blair',
email: 'freddyb34@gmail.com' }
服务器以新创建的对象作为响应。
$ curl localhost:3000/users/6/
{
"id": 6,
"first_name": "Fred",
"last_name": "Blair",
"email": "freddyb34@gmail.com"
}
我们使用curl
命令验证新创建的用户。
JSON 服务器使用 PUT 请求修改数据
在以下示例中,我们使用 PUT 请求修改数据。
put_request.js
const axios = require('axios');
axios.put('http://localhost:3000/users/6/', {
first_name: 'Fred',
last_name: 'Blair',
email: 'freddyb34@yahoo.com'
}).then(resp => {
console.log(resp.data);
}).catch(error => {
console.log(error);
});
在示例中,我们修改了用户的电子邮件地址。
$ node put_request.js
{ first_name: 'Fred',
last_name: 'Blair',
email: 'freddyb34@yahoo.com',
id: 6 }
这是输出。
JSON 服务器 DELETE 请求
在下面的示例中,我们显示了如何通过 DELETE 请求删除用户。
delete_request.js
const axios = require('axios');
axios.delete('http://localhost:3000/users/1/')
.then(resp => {
console.log(resp.data)
}).catch(error => {
console.log(error);
});
在示例中,我们删除 ID 为 1 的用户。
$ node delete_request.js
{}
服务器以空 JSON 数据响应。
JSON 服务器排序数据
在下一个示例中,我们对数据进行排序。
sort_data.js
const axios = require('axios');
axios.get('http://localhost:3000/users?_sort=last_name&_order=asc')
.then(resp => {
data = resp.data;
data.forEach(e => {
console.log(`${e.first_name}, ${e.last_name}, ${e.email}`)
});
}).catch(error => {
console.log(error);
});
该代码示例按用户的姓氏升序对数据进行排序。 我们使用_sort
和_order
查询参数。
$ node sort_data.js
Roger, Bacon, rogerbacon12@yahoo.com
Lucy, Ballmer, lucyb56@gmail.com
Fred, Blair, freddyb34@yahoo.com
Robert, Brown, bobbrown432@yahoo.com
Robert, Schwartz, rob23@gmail.com
Anna, Smith, annasmith23@gmail.com
这是输出。
JSON 服务器运算符
我们可以使用_gte
和_lte
获取特定范围的数据。
operators.js
const axios = require('axios');
axios.get('http://localhost:3000/users?id_gte=4')
.then(resp => {
console.log(resp.data)
}).catch(error => {
console.log(error);
});
该代码示例显示 ID 大于或等于 4 的用户。
$ node operators.js
[ { id: 4,
first_name: 'Robert',
last_name: 'Brown',
email: 'bobbrown432@yahoo.com' },
{ id: '5',
first_name: 'Roger',
last_name: 'Bacon',
email: 'rogerbacon12@yahoo.com' },
{ first_name: 'Fred',
last_name: 'Blair',
email: 'freddyb34@yahoo.com',
id: 6 } ]
这是输出。
JSON 服务器全文搜索
可以使用q
参数执行全文搜索。
full_text_search.js
const axios = require('axios');
axios.get('http://localhost:3000/users?q=yahoo')
.then(resp => {
console.log(resp.data)
}).catch(error => {
console.log(error);
});
该代码示例搜索 yahoo 术语。
$ node full_text_search.js
[ { id: 4,
first_name: 'Robert',
last_name: 'Brown',
email: 'bobbrown432@yahoo.com' },
{ id: '5',
first_name: 'Roger',
last_name: 'Bacon',
email: 'rogerbacon12@yahoo.com' },
{ first_name: 'Fred',
last_name: 'Blair',
email: 'freddyb34@yahoo.com',
id: 6 } ]
搜索查询返回了这三个用户。
在本教程中,我们介绍了 JSONServer JavaScript 库。
您可能也对以下相关教程感兴趣:数据表 JSON 服务器教程, Axios 教程,笑话教程, faker.js 教程, Document.querySelector()
教程,从 JavaScript 中的 URL 读取 JSON , JavaScript 贪食蛇教程, JQuery 教程, jQuery 自动完成教程或 Node Sass 教程。
JavaScript 贪食蛇教程
原文: http://zetcode.com/javascript/snake/
JavaScript 贪食蛇教程展示了如何在 JavaScript 中创建贪食蛇游戏。 这些图像和源可从作者的 Github JavaScript-Snake-Game 存储库中获得。
贪食蛇游戏
贪食蛇是一款较老的经典视频游戏,最早于 70 年代后期创建。 后来它被带到 PC 上。 在这个游戏中,玩家控制蛇。 目的是尽可能多地吃苹果。 蛇每次吃一个苹果,它的身体就会长大。 蛇必须避开墙壁和自己的身体。 该游戏有时称为 Nibbles。
HTML5 画布
HTML5 canvas
元素提供了一个与分辨率有关的位图区域,该区域可用于动态绘制图形,游戏图形,艺术作品或其他可视图像。 简单来说,canvas
是 HTML5 中的新元素,它使您可以使用 JavaScript 绘制图形。 Canvas
无需将插件插入 Flash,Silverlight 或 Java,即可将动画带入网页。
JavaScript 贪食蛇代码示例
蛇的每个关节的大小为 10 像素。 蛇由光标键控制。 最初,蛇具有三个关节。 如果游戏结束,则画布中间会显示"Game Over"
消息。
index.html
<!DOCTYPE html>
<html>
<head>
<title>JavaScript Snake game</title>
<style>
canvas {background: black}
</style>
<script src="snake.js"></script>
</head>
<body onload="init();">
<canvas id="myCanvas" width="300" height="300">
</canvas>
</body>
</html>
这是 HTML 来源。 我们将 JavaScript 源代码放置在snake.js
文件中。
<canvas id="myCanvas" width="300" height="300">
</canvas>
我们创建一个画布对象。 这是我们游戏的渲染区域。
snake.js
// JavaScript Snake example
// Author Jan Bodnar
// http://zetcode.com/javascript/snake/
var canvas;
var ctx;
var head;
var apple;
var ball;
var dots;
var apple_x;
var apple_y;
var leftDirection = false;
var rightDirection = true;
var upDirection = false;
var downDirection = false;
var inGame = true;
const DOT_SIZE = 10;
const ALL_DOTS = 900;
const MAX_RAND = 29;
const DELAY = 140;
const C_HEIGHT = 300;
const C_WIDTH = 300;
const LEFT_KEY = 37;
const RIGHT_KEY = 39;
const UP_KEY = 38;
const DOWN_KEY = 40;
var x = new Array(ALL_DOTS);
var y = new Array(ALL_DOTS);
function init() {
canvas = document.getElementById('myCanvas');
ctx = canvas.getContext('2d');
loadImages();
createSnake();
locateApple();
setTimeout("gameCycle()", DELAY);
}
function loadImages() {
head = new Image();
head.src = 'head.png';
ball = new Image();
ball.src = 'dot.png';
apple = new Image();
apple.src = 'apple.png';
}
function createSnake() {
dots = 3;
for (var z = 0; z < dots; z++) {
x[z] = 50 - z * 10;
y[z] = 50;
}
}
function checkApple() {
if ((x[0] == apple_x) && (y[0] == apple_y)) {
dots++;
locateApple();
}
}
function doDrawing() {
ctx.clearRect(0, 0, C_WIDTH, C_HEIGHT);
if (inGame) {
ctx.drawImage(apple, apple_x, apple_y);
for (var z = 0; z < dots; z++) {
if (z == 0) {
ctx.drawImage(head, x[z], y[z]);
} else {
ctx.drawImage(ball, x[z], y[z]);
}
}
} else {
gameOver();
}
}
function gameOver() {
ctx.fillStyle = 'white';
ctx.textBaseline = 'middle';
ctx.textAlign = 'center';
ctx.font = 'normal bold 18px serif';
ctx.fillText('Game over', C_WIDTH/2, C_HEIGHT/2);
}
function checkApple() {
if ((x[0] == apple_x) && (y[0] == apple_y)) {
dots++;
locateApple();
}
}
function move() {
for (var z = dots; z > 0; z--) {
x[z] = x[(z - 1)];
y[z] = y[(z - 1)];
}
if (leftDirection) {
x[0] -= DOT_SIZE;
}
if (rightDirection) {
x[0] += DOT_SIZE;
}
if (upDirection) {
y[0] -= DOT_SIZE;
}
if (downDirection) {
y[0] += DOT_SIZE;
}
}
function checkCollision() {
for (var z = dots; z > 0; z--) {
if ((z > 4) && (x[0] == x[z]) && (y[0] == y[z])) {
inGame = false;
}
}
if (y[0] >= C_HEIGHT) {
inGame = false;
}
if (y[0] < 0) {
inGame = false;
}
if (x[0] >= C_WIDTH) {
inGame = false;
}
if (x[0] < 0) {
inGame = false;
}
}
function locateApple() {
var r = Math.floor(Math.random() * MAX_RAND);
apple_x = r * DOT_SIZE;
r = Math.floor(Math.random() * MAX_RAND);
apple_y = r * DOT_SIZE;
}
function gameCycle() {
if (inGame) {
checkApple();
checkCollision();
move();
doDrawing();
setTimeout("gameCycle()", DELAY);
}
}
onkeydown = function(e) {
var key = e.keyCode;
if ((key == LEFT_KEY) && (!rightDirection)) {
leftDirection = true;
upDirection = false;
downDirection = false;
}
if ((key == RIGHT_KEY) && (!leftDirection)) {
rightDirection = true;
upDirection = false;
downDirection = false;
}
if ((key == UP_KEY) && (!downDirection)) {
upDirection = true;
rightDirection = false;
leftDirection = false;
}
if ((key == DOWN_KEY) && (!upDirection)) {
downDirection = true;
rightDirection = false;
leftDirection = false;
}
};
这是 JavaScript 贪食蛇的源代码。
const DOT_SIZE = 10;
const ALL_DOTS = 900;
const MAX_RAND = 29;
const DELAY = 140;
const C_HEIGHT = 300;
const C_WIDTH = 300;
DOT_SIZE
是苹果的大小和蛇的点。 ALL_DOTS
常数定义画布上可能的最大点数(900 = 300 * 300 / 10 * 10
)。 MAX_RAND
常数用于计算苹果的随机位置。 DELAY
常数确定游戏的速度。 C_HEIGHT
和C_WIDTH
常数存储画布的大小。
const LEFT_KEY = 37;
const RIGHT_KEY = 39;
const UP_KEY = 38;
const DOWN_KEY = 40;
这些常量存储箭头键的值。 它们用于提高可读性。
var x = new Array(ALL_DOTS);
var y = new Array(ALL_DOTS);
这两个数组存储蛇的所有关节的x
和y
坐标。
function init() {
canvas = document.getElementById('myCanvas');
ctx = canvas.getContext('2d');
loadImages();
createSnake();
locateApple();
setTimeout("gameCycle()", DELAY);
}
init()
函数获取对画布对象及其上下文的引用。 调用loadImages()
,createSnake()
和locateApple()
函数来执行特定任务。 setTimeout()
开始动画。
function loadImages() {
head = new Image();
head.src = 'head.png';
ball = new Image();
ball.src = 'dot.png';
apple = new Image();
apple.src = 'apple.png';
}
在loadImages()
函数中,我们为游戏加载了三张图像。
function createSnake() {
dots = 3;
for (var z = 0; z < dots; z++) {
x[z] = 50 - z * 10;
y[z] = 50;
}
}
在createSnake()
函数中,我们创建蛇对象。 首先,它具有三个关节。
function checkApple() {
if ((x[0] == apple_x) && (y[0] == apple_y)) {
dots++;
locateApple();
}
}
如果头部与苹果相撞,我们会增加蛇的关节数。 我们称locateApple()
方法为随机放置一个新的 Apple 对象。
function move() {
...
在move()
方法中,我们有游戏的关键算法。 为了理解它,请看一下蛇是如何运动的。 我们控制蛇的头。 我们可以使用光标键更改其方向。 其余关节在链上向上移动一个位置。 第二关节移动到第一个关节的位置,第三关节移动到第二个关节的位置,依此类推。
for (var z = dots; z > 0; z--) {
x[z] = x[(z - 1)];
y[z] = y[(z - 1)];
}
for
循环将蛇的关节向上移动。
if (leftDirection) {
x[0] -= DOT_SIZE;
}
这条线将头向左移动。
function checkCollision() {
...
在checkCollision()
方法中,我们确定蛇是否击中了自己或边界之一。
for (var z = dots; z > 0; z--) {
if ((z > 4) && (x[0] == x[z]) && (y[0] == y[z])) {
inGame = false;
}
}
如果蛇用头撞到其关节之一,则游戏结束。
if (y[0] >= C_HEIGHT) {
inGame = false;
}
如果蛇撞到画布底部,则游戏结束。
function locateApple() {
var r = Math.floor(Math.random() * MAX_RAND);
apple_x = r * DOT_SIZE;
r = Math.floor(Math.random() * MAX_RAND);
apple_y = r * DOT_SIZE;
}
locateApple()
随机选择苹果对象的x
和y
坐标。 apple_x
和apple_y
是苹果图像左上点的坐标。
function gameCycle() {
if (inGame) {
checkApple();
checkCollision();
move();
doDrawing();
setTimeout("gameCycle()", DELAY);
}
}
gameCycle()
函数形成游戏周期。 如果游戏尚未完成,我们将执行碰撞检测,移动和绘画。 setTimeout()
函数递归调用gameCycle()
函数。
if ((key == LEFT_KEY) && (!rightDirection)) {
leftDirection = true;
upDirection = false;
downDirection = false;
}
如果单击左光标键,则将leftDirection
变量设置为true
。 move()
函数中使用此变量来更改蛇对象的坐标。 还要注意,当蛇向右行驶时,我们不能立即向左转。
图:贪食蛇 gmae
这是 JavaScript 贪食蛇游戏。
JavaScript 构建器模式教程
原文: http://zetcode.com/javascript/builderpattern/
JavaScript 构建器模式教程展示了如何使用构建器模式在 JavaScript 中创建对象。
构建器模式
构建器模式是一种设计模式,可为创建对象提供灵活的解决方案。 构建器模式将复杂对象的构造与其表示形式分开。
生成器模式通过提供逐步的方法,使用简单的对象来构建复杂的对象。 它属于创作模式。
构建器模式示例
以下示例将构建器模式与TaskBuilder
结合使用。
task_creator.js
let Task = function(name, description, finished, dueDate) {
this.name = name;
this.description = description;
this.finished = finished;
this.dueDate = dueDate;
}
let TaskBuilder = function () {
let name;
let description;
let isFinished = false;
let dueDate;
return {
setName: function (name) {
this.name = name;
return this;
},
setDescription: function (description) {
this.description = description;
return this;
},
setFinished: function (finished) {
this.finished = finished;
return this;
},
setDueDate: function (dueDate) {
this.dueDate = dueDate;
return this;
},
build: function () {
return new Task(name, description, isFinished, dueDate);
}
};
};
let task = new TaskBuilder().setName('Task A').setDescription('finish book')
.setDueDate(new Date(2019, 5, 12));
console.log(task);
在此示例中,我们有一个TaskBuilder
生成Task
对象。
let Task = function(name, description, finished, dueDate) {
this.name = name;
this.description = description;
this.finished = finished;
this.dueDate = dueDate;
}
这是一个Task
对象。 它具有四个属性:name
,description
,finished
和dueDate
。
return {
setName: function (name) {
this.name = name;
return this;
},
...
TaskBuilder
返回设置四个属性的函数。 请注意,每个函数都返回this
,即对当前对象的引用。 这样,我们可以链接函数调用。 函数调用链称为流畅 API 。
let task = new TaskBuilder().setName('Task A').setDescription('finish book')
.setDueDate(new Date(2019, 5, 12));
console.log(task);
我们使用TaskBuilder
创建任务。
在本教程中,我们介绍了 JavaScript 中的构建器模式。
列出所有 JavaScript 教程。
JavaScript 数组
原文: http://zetcode.com/javascript/arrays/
JavaScript 数组教程展示了如何在 JavaScript 中使用数组。
数组是许多值的集合。 数组项称为数组的元素。 每个元素都可以由索引引用。 数组从零开始。
JavaScript 数组初始化
在第一个示例中,我们展示了如何在 JavaScript 中初始化数组。
array_init.js
"use strict";
const nums = [1, 2, 3, 4, 5];
console.log(nums);
该示例使用 JavaScript 创建一个简单的数组。
const nums = [1, 2, 3, 4, 5];
使用方括号创建一个数组。 元素之间用逗号分隔。
$ nodejs array_init.js
[ 1, 2, 3, 4, 5 ]
这是输出。
JavaScript 数组索引
下一个示例显示了 JavaScript 中的数组索引操作。
array_index.js
"use strict";
const nums = [1, 2, 3, 4, 5, 1];
const e1 = nums[0];
console.log(e1);
nums[2] = 22;
console.log(nums[2]);
console.log(nums.indexOf(1));
console.log(nums.lastIndexOf(1));
我们使用索引操作来获取和修改数组值以及获取元素的索引。
const e1 = nums[0];
我们得到数组的第一个元素。 索引从零开始。
nums[2] = 22;
我们修改数组的第三个值。
console.log(nums.indexOf(1));
使用indexOf()
,我们第一次出现元素 1。
console.log(nums.lastIndexOf(1));
使用lastIndexOf()
,我们得到元素 1 的最后一次出现。
$ nodejs array_index.js
1
22
0
5
这是输出。
JavaScript 数组基本操作
以下示例介绍了 JavaScript 数组的一些基本操作。
basic_oper.js
"use strict";
const words = [];
words.push("pen");
words.push("pencil", "knife", "chair");
console.log(words);
const el1 = words.shift();
console.log(el1);
console.log(words);
const el2 = words.pop();
console.log(el2);
console.log(words);
在示例中,我们介绍了 JavaScript 数组的push()
,shift()
和pop()
方法。
const words = [];
words.push("pen");
words.push("pencil", "knife", "chair");
创建一个空数组。 使用push()
方法,我们在数组末尾添加一个或多个元素。
const el1 = words.shift();
shift()
方法从数组中删除第一个元素,然后返回删除的元素。 它改变了数组的长度。
const el2 = words.pop();
pop()
方法从数组中删除最后一个元素并返回该元素。 此方法还更改了数组的长度。
$ nodejs basic_oper.js
[ 'pen', 'pencil', 'knife', 'chair' ]
pen
[ 'pencil', 'knife', 'chair' ]
chair
[ 'pencil', 'knife' ]
这是输出。
JavaScript 循环数组
在下一个示例中,我们遍历 JavaScript 数组。
array_loop.js
"use strict";
const words = ["pen", "pencil", "rock", "sky", "earth"];
words.forEach(e => console.log(e));
for (let word of words) {
console.log(word);
}
for (let idx in words) {
console.log(words[idx]);
}
const len = words.length;
for (let i = 0; i < len; i++) {
console.log(words[i]);
}
const i = 0;
while (i < len) {
console.log(words[i]);
i++;
}
该示例显示了遍历 JavaScript 数组的四种方式。
words.forEach(e => console.log(e));
我们使用forEach()
方法遍历数组。 它为每个数组元素执行一次提供的函数。
for (let word of words) {
console.log(word);
}
通过for of
循环,我们遍历数组的值。
for (let idx in words) {
console.log(words[idx]);
}
通过for in
循环,我们遍历数组的索引。
var len = words.length;
for (let i = 0; i < len; i++) {
console.log(words[i]);
}
在这里,我们使用类似于 C 的for
循环遍历数组。
var i = 0;
while (i < len) {
console.log(words[i]);
i++;
}
最后,我们使用while
循环遍历数组。
JavaScript 数组切片
slice()
方法返回数组部分的浅表副本。 该方法采用一个或两个参数,这些参数指定选择的索引。 原始数组未修改。
array_slice.js
"use strict";
const nums = [2, -3, 4, 6, -1, 9, -7];
const res = nums.slice(3);
console.log(res);
const res2 = nums.slice(2, 4);
console.log(res2);
在示例中,我们创建了两个切片。
const res = nums.slice(3);
我们创建一个从索引 3 到数组末尾的切片。
const res2 = nums.slice(2, 4);
我们创建一个从索引 2 到索引 4 的切片; 结束索引不包含在内。
$ nodejs array_slice.js
[ 6, -1, 9, -7 ]
[ 4, 6 ]
这是输出。
JavaScript 排序数组
sort()
方法对数组中的元素进行适当排序,然后返回数组。 默认排序顺序是根据字符串 Unicode 代码点确定的。 sort()
方法采用可选函数,该函数定义了排序顺序。
array_sort.js
"use strict";
const nums = [2, 3, 1, 6, 5, 8, 9, 0];
nums.sort();
console.log(nums);
nums.reverse();
console.log(nums);
const persons = [
{name: 'Peter', age: 21},
{name: 'Robert', age: 37},
{name: 'Martin', age: 45},
{name: 'Jane', age: 31}
];
persons.sort((a, b) => a.age - b.age);
console.log(persons);
persons.sort((a, b) => {
const nameA = a.name.toLowerCase(), nameB = b.name.toLowerCase();
if (nameA < nameB) {
return -1;
} else if (nameA > nameB) {
return 1;
} else {
return 0;
}
});
console.log(persons);
该示例对整数数组和对象数组进行排序。
nums.sort();
sort()
方法按升序对整数数组进行排序。
nums.reverse();
reverse()
方法按降序对整数数组进行排序。
persons.sort((a, b) => a.age - b.age);
我们通过age
属性对一系列人对象进行排序。
persons.sort((a, b) => {
const nameA = a.name.toLowerCase(), nameB = b.name.toLowerCase();
if (nameA < nameB) {
return -1;
} else if (nameA > nameB) {
return 1;
} else {
return 0;
}
});
我们通过名称属性对人员对象数组进行排序。
$ nodejs array_sort.js
[ 0, 1, 2, 3, 5, 6, 8, 9 ]
[ 9, 8, 6, 5, 3, 2, 1, 0 ]
[ { name: 'Peter', age: 21 },
{ name: 'Jane', age: 31 },
{ name: 'Robert', age: 37 },
{ name: 'Martin', age: 45 } ]
[ { name: 'Jane', age: 31 },
{ name: 'Martin', age: 45 },
{ name: 'Peter', age: 21 },
{ name: 'Robert', age: 37 } ]
这是输出。
JavaScript 多维数组
在 JavaScript 中,我们可以创建多维数组。
multi_dim.js
"use strict";
const nums = [2, 3, 2, [33, 44, 55], [7, 8, [77, 88]]];
console.log(nums[2]);
console.log(nums[3]);
console.log(nums[3][0]);
console.log(nums[4][0]);
console.log(nums[4][2][0]);
通过将数组嵌套到其他数组中来创建多维数组。
const nums = [2, 3, 2, [33, 44, 55], [7, 8, [77, 88]]];
我们定义了一个多维数组。
console.log(nums[2]);
为了从第一维获取元素,我们使用一对方括号。
console.log(nums[3]);
这行打印整个内部数组。
console.log(nums[3][0]);
为了从内部数组中获取元素,我们使用了两对方括号。
console.log(nums[4][2][0]);
在这里,我们从三维获得了一个值。
$ nodejs multi_dim.js
2
[ 33, 44, 55 ]
33
7
77
这是输出。
JavaScript 过滤数组
filter()
方法创建一个新数组,其中所有元素均通过给定函数实现的测试。
filter_array.js
"use strict"
const nums = [2, -3, 4, 6, -1, 9, -7];
const res = nums.filter(e => e > 0);
console.log(res);
该示例创建一个仅包含正值的新数组。
const res = nums.filter(e => e > 0);
filter()
方法采用谓词方法作为参数。 谓词返回true
以保留元素,否则返回false
。
$ nodejs filter_array.js
[ 2, 4, 6, 9 ]
这是输出。
JavaScript 数组映射
map()
方法通过在调用数组中的每个元素上应用提供的函数来创建新数组。
array_map.js
"use strict";
const a1 = ['dog', 'tree', 'smart'];
const a2 = a1.map(e => e.toUpperCase());
console.log(a2);
我们有很多单词。 使用map()
方法,我们将toUpperCase()
方法应用于每个单词。
$ nodejs array_map.js
[ 'DOG', 'TREE', 'SMART' ]
这是输出。
JavaScript 数组查找
find()
方法返回满足所提供函数的第一个元素的值; 否则返回undefined
。
array_find.js
"use strict";
const nums = [2, -3, 4, 6, 1, 23, 9, 7];
const e1 = nums.find(e => e > 10);
console.log(e1);
在示例中,我们打印出大于 10 的第一个值。
$ nodejs array_find.js
23
这是输出。
JavaScript 数组归约
精简是将数组值聚合为单个值的终端操作。 reduce()
方法对累加器和数组中的每个元素(从左到右)应用一个函数,以将其减小为单个值。
array_reduce.js
"use strict";
const nums = [2, 3, 4, 5, 6, 7];
const res = nums.reduce((product, next) => product * next);
console.log(res);
我们使用reduce()
方法从数组元素计算乘积。
const res = nums.reduce((product, next) => product * next);
product
是累加器,next
是数组中的下一个值。
$ nodejs array_reduce.js
5040
这是输出。
在本教程中,我们介绍了 JavaScript 数组。 您可能也对这些相关教程感兴趣: Lodash 教程, JavaScript 正则表达式, Node.js 教程, JavaScript 贪食蛇教程。
XMLHttpRequest
教程
原文: http://zetcode.com/javascript/xmlhttprequest/
XMLHttpRequest
教程展示了如何使用XMLHttpRequest
在 JavaScript 中发出 HTTP 请求。
XMLHttpRequest
XMLHttpRequest
是内置的浏览器对象,它允许使用 JavaScript 发出 HTTP 请求。 XMLHttpRequest
API 提供了用于在客户端和服务器之间传输数据的客户端功能。 它提供了一种从 URL 检索数据的简便方法,而无需刷新整个页面。
结果,网页必须仅更新页面的一部分而不破坏用户正在做的事情。 XMLHttpRequest
在 AJAX 编程中大量使用。 XMLHttpRequest
以两种操作模式工作:同步和异步。 尽管它的名字,XMLHttpRequest
可以对任何数据进行操作,而不仅限于 XML。
XMLHttpRequest
示例
下面的示例向测试站点创建一个请求,并返回当前日期时间。
fetch_time.js
let getJSON = (url, callback) => {
let xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'json';
xhr.onload = () => {
let status = xhr.status;
if (status == 200) {
callback(null, xhr.response);
} else {
callback(status);
}
};
xhr.send();
};
getJSON('http://time.jsontest.com', (err, data) => {
if (err != null) {
console.error(err);
} else {
let text = `Date: ${data.date}
Time: ${data.time}
Unix time: ${data.milliseconds_since_epoch}`
console.log(text);
}
});
This example reads JSON data with XMLHttpRequest
.
let xhr = new XMLHttpRequest();
创建了XMLHttpRequest
的新实例。
xhr.open('GET', url, true);
open()
方法将 GET 请求初始化为指定的 URL。 第三个参数true
使其成为异步请求。
xhr.responseType = 'json';
responseType
值定义响应类型。
xhr.onload = function() {
var status = xhr.status;
if (status == 200) {
callback(null, xhr.response);
} else {
callback(status);
}
};
在onload()
方法内部,我们等待服务器的响应。
xhr.send();
send()
方法发送请求; 默认情况下,该请求是异步的。
let text = `Date: ${data.date}
Time: ${data.time}
Unix time: ${data.milliseconds_since_epoch}`
console.log(text);
我们将日期,时间和 Unix 时间记录到控制台。
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Consume XML request</title>
<script src="fetch_time.js"></script>
</head>
<body>
</body>
</html>
该代码已加载到 HTML 页面。 在浏览器中加载页面之后,我们转到浏览器控制台,该控制台在开发者工具中可用。
在本教程中,我们使用XMLHttpRequest
在 JavaScript 中创建了 HTTP 请求。
您可能也对以下相关教程感兴趣: JavaScript queryselector
教程, JavaScript Lodash 教程, Ramda 教程或列出所有 JavaScript 教程。
在 JavaScript 中从 URL 读取 JSON
原文: http://zetcode.com/articles/javascriptjsonurl/
在 JavaScript 教程的“从 URL 读取 JSON”中,我们从提供的 URL 中读取 JSON 格式的数据。 我们使用 JQuery,Fetch API 和XMLHttpRequest
。
统一资源定位符(URL)是对 Web 资源的引用,该资源指定了它在计算机网络上的位置以及用于检索它的机制。 网络资源是可以通过网络获取的任何数据,例如 HTML 文档,PDF 文件,PNG 图像,JSON 数据或纯文本。
JSON(JavaScript 对象表示法)是一种轻量级的数据交换格式。 人类很容易读写,机器也很容易解析和生成。 JSON 的官方 Internet 媒体类型为application/json
。 JSON 文件扩展名是.json
。
在我们的示例中,我们使用http://time.jsontest.com
中的 JSON 数据。
{
"time": "11:27:26 AM",
"milliseconds_since_epoch": 1494934046126,
"date": "05-16-2017"
}
GET 请求返回此 JSON 字符串。
使用 JQuery 读取 JSON
jQuery 是一个 JavaScript 库,用于处理 DOM。 使用 jQuery,我们可以查找,选择,遍历和操作 HTML 文档的各个部分。
JQuery $.getJSON()
方法使用 GET HTTP 请求从服务器加载 JSON 编码的数据。
jQuery.getJSON( url [, data ] [, success ] )
这是方法签名。 url
参数是一个字符串,其中包含将请求发送到的 URL。 data
是随请求发送到服务器的普通对象或字符串。 success
是一个回调函数,如果请求成功,则执行该函数。
$.ajax({
dataType: "json",
url: url,
data: data,
success: success
});
$.getJSON()
是上述调用的简写。
js_read_json_url.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>JavaScript - read JSON from URL</title>
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
</head>
<body>
<div class="mypanel"></div>
<script>
$.getJSON('http://time.jsontest.com', function(data) {
var text = `Date: ${data.date}<br>
Time: ${data.time}<br>
Unix time: ${data.milliseconds_since_epoch}`
$(".mypanel").html(text);
});
</script>
</body>
</html>
在示例中,我们从http://time.jsontest.com
读取 JSON 数据。 返回的对象具有三个属性:日期,时间和 unix 纪元。
var text = `Date: ${data.date}<br>
Time: ${data.time}<br>
Unix time: ${data.milliseconds_since_epoch}`
我们使用 JavaScript 模板字符串构建消息。
$(".mypanel").html(text);
使用 JQuery 的html()
方法,我们将文本附加到div
标签。
图:使用 JQuery 从 URL 读取 JSON
在图中,我们可以看到当前日期,时间和 Unix 时间。
使用 Fetch API 读取 JSON
Fetch API 是用于提取资源的接口。 它类似于XMLHttpRequest
,但其 API 提供了更强大和灵活的功能集。
<script>
fetch('http://time.jsontest.com')
.then(res => res.json())
.then((out) => {
console.log('Output: ', out);
}).catch(err => console.error(err));
</script>
该示例使用 Fetch API 读取 JSON 数据,并将返回的数据打印到控制台。 要查看输出,我们需要激活浏览器的开发者控制台。
fetch()
方法采用一个强制性参数,即我们要获取的资源的路径。 它返回一个解析为请求响应的promise
。
使用XMLHttpRequest
读取 JSON
XMLHttpRequest
API 提供了用于在客户端和服务器之间传输数据的客户端功能。 它提供了一种从 URL 检索数据的简便方法,而无需刷新整个页面。 结果,网页必须仅更新页面的一部分而不破坏用户正在做的事情。 XMLHttpRequest
在 AJAX 编程中大量使用。
<script>
var getJSON = function(url, callback) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'json';
xhr.onload = function() {
var status = xhr.status;
if (status == 200) {
callback(null, xhr.response);
} else {
callback(status);
}
};
xhr.send();
};
getJSON('http://time.jsontest.com', function(err, data) {
if (err != null) {
console.error(err);
} else {
var text = `Date: ${data.date}
Time: ${data.time}
Unix time: ${data.milliseconds_since_epoch}`
console.log(text);
}
});
</script>
本示例使用XMLHttpRequest
读取 JSON 数据。
var xhr = new XMLHttpRequest();
创建了XMLHttpRequest
的新实例。
xhr.open('GET', url, true);
open()
方法初始化一个请求。
xhr.responseType = 'json';
responseType
值定义响应类型。
xhr.onload = function() {
var status = xhr.status;
if (status == 200) {
callback(null, xhr.response);
} else {
callback(status);
}
};
在onload()
方法中,我们等待服务器的响应。
xhr.send();
send()
方法发送请求; 默认情况下,该请求是异步的。
在本教程中,我们已经使用 JQuery,Fetch API 和XMLHttpRequest
在 JavaScript 中读取了 JSON 数据。
您可能也对以下相关教程感兴趣: JQuery 教程, JavaScript Mustache 教程, JavaScript 中的 JSON 数组循环, jQuery 自动完成教程或使用 jQuery DatePicker
。
在 JavaScript 中循环遍历 JSON 数组
原文: http://zetcode.com/javascript/jsonforeach/
JSON forEach
教程展示了如何在 JavaScript 中循环遍历 JSON 数组。 在本教程中,我们使用 JSON 服务器来处理测试数据。
json 服务器是一个 JavaScript 库,用于创建测试 REST API。
首先,我们创建一个项目目录并安装json-server
模块。
$ mkdir jsonforeach
$ cd jsonforeach
$ npm init -y
$ npm i -g json-server
JSON 服务器模块与npm
一起全局安装。
JSON 测试数据
我们有一些 JSON 测试数据:
users.json
{
"users": [
{
"id": 1,
"first_name": "Robert",
"last_name": "Schwartz",
"email": "rob23@gmail.com"
},
{
"id": 2,
"first_name": "Lucy",
"last_name": "Ballmer",
"email": "lucyb56@gmail.com"
},
{
"id": 3,
"first_name": "Anna",
"last_name": "Smith",
"email": "annasmith23@gmail.com"
},
{
"id": 4,
"first_name": "Robert",
"last_name": "Brown",
"email": "bobbrown432@yahoo.com"
},
{
"id": 5,
"first_name": "Roger",
"last_name": "Bacon",
"email": "rogerbacon12@yahoo.com"
}
]
}
$ json-server --watch users.json
--watch
命令用于指定服务器的数据。
$ curl localhost:3000/users/3/
{
"id": 3,
"first_name": "Anna",
"last_name": "Smith",
"email": "annasmith23@gmail.com"
}
使用curl
命令,我们为用户提供 ID 3。
JSON forEach
示例
在下一个示例中,我们使用提取 API 通过 GET 请求检索数据。 我们使用forEach
循环返回的数据。
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Home page</title>
</head>
<body>
<button id="log">Log</button>
<script src="main.js"></script>
</body>
</html>
这是index.html
页面。 通过单击Log
按钮,我们从 JSON 服务器测试数据中获取数据并将其记录到浏览器控制台中。
main.js
const logBtn = document.getElementById('log');
logBtn.addEventListener('click', fetchData);
async function fetchData() {
const response = await fetch('http://localhost:3000/users/');
const data = await response.json();
data.forEach(obj => {
Object.entries(obj).forEach(([key, value]) => {
console.log(`${key} ${value}`);
});
console.log('-------------------');
});
}
fetch()
函数从提供的 URL 中以 JSON 数组的形式检索数据。 使用forEach()
,我们遍历了数组。
Object.entries(obj).forEach(([key, value]) => {
console.log(`${key} ${value}`);
});
我们遍历每个对象的条目,并将键和值打印到控制台。
id 1 main.js:12:13
first_name Robert main.js:12:13
last_name Schwartz main.js:12:13
email rob23@gmail.com main.js:12:13
------------------- main.js:14:9
id 2 main.js:12:13
first_name Lucy main.js:12:13
last_name Ballmer main.js:12:13
email lucyb56@gmail.com main.js:12:13
------------------- main.js:14:9
...
这是浏览器控制台中的输出。
在本教程中,我们展示了如何使用forEach
遍历 JSON 数组。
您可能也对以下相关教程感兴趣:数据表 JSON 服务器教程, Axios 教程, faker.js 教程或在 JavaScript 中从 URL 读取 JSON。
jQuery 教程
原文: https://zetcode.com/web/jquery/
在本教程中,我们将学习 jQuery 的基础知识。 我们将展示 jQuery 库,展示如何下载和包含 jQuery,解释各种 jQuery 选择器,展示如何绑定事件,展示各种 jQuery 效果,以及处理异步事件。
当我们要创建一个网站时,我们需要使用特定的技术。 HTML 创建网页的结构。 CSS 负责网页的外观。 JavaScript 为网页带来了活力。
超文本标记语言(HTML),级联样式表(CSS)和 JavaScript 构成了万维网的三项基石技术。 jQuery 是 JavaScript 的抽象; 它使使用 JavaScript 的工作更加轻松。
HTML 文件
一个网站由多个网页组成。 每个网页都是一个 HTML 文档。 HTML 文档是一种文本文档,其结构由超文本标记语言定义。 要创建文档结构,我们使用 HTML 标签,例如<div>
,<h2>
或<body>
。 HTML 文档具有.html
或.htm
扩展名。
图:一个简单的 HTML 文档的来源
Web 浏览器使我们能够查看每个 HTML 文档的 HTML 源。 HTML 文档由两部分组成:头和正文。 HTML 元素以层次结构进行组织-HTML 标记具有其父代,子代和同级兄弟。
文档对象模型(DOM)
文档对象模型(DOM)是 HTML 文档的编程接口。 它定义了用于操纵文档结构,样式和内容的功能。 DOM 将 HTML 文档表示为节点的树形结构,其中每个节点都是代表文档一部分的对象。 节点是具有属性和方法的对象。 这些实体可以通过 JavaScript 及其 jQuery 库进行访问。
jQuery
jQuery 是一个 JavaScript 库,用于处理 DOM。 使用 jQuery,我们可以查找,选择,遍历和操作 HTML 文档的各个部分。 这些部分也称为 DOM 元素。 jQuery 是当今使用最广泛的 JavaScript 库。 据估计,在前 1000 万个网站中,有三分之二使用了该网站。 jQuery 最初是由 John Resig 创建的。 jQuery 是根据 MIT 许可获得许可的免费开源软件。
使用 jQuery 进行开发的原则是:
- JavaScript 和 HTML 的分离。
- 简洁明了。
- 消除跨浏览器的不兼容性。
- 可扩展性。
选择 jQuery 库
jQuery 库本质上是一个小文件。 为了在我们的项目中使用 jQuery,我们可以从项目的网站上下载文件,或者使用内容分发网络(CDN)。
有几种选择。 首先,有多个可用的 jQuery 版本。 文件名中提到了库的版本。 当前有三个版本分支:1.x,2.x 和 3.x。 出于教育目的,最好选择最新版本的 jQuery 库。 然后,我们需要在库的生产和开发版本之间进行选择。 生产版本已压缩,并且在库名称中带有min
字。 压缩或缩小的版本的大小已减小,但提供相同的功能。 开发版本易于阅读并带有注释。
jquery-3.1.1.js
jquery-3.1.1.min.js
第一个文件是 jQuery 库 3.1.1 的开发版本。 第二个文件是 jQuery 库 3.1.1 版的生产版本。
此外,还有所谓的库的瘦版本。 精简版的库名称中带有slim
字。 它们不包括 AJAX 功能,效果和当前不建议使用的代码。
jquery-3.1.1.slim.js
jquery-3.1.1.slim.min.js
第一个文件是 jQuery 库 3.1.1 的苗条开发版本。 第二个文件是 jQuery 库 3.1.1 的精简生产版本。
在本教程中,将使用 jQuery 3.1.1 的缩小版。
在 HTML 文档中包含 jQuery
通过链接到本地副本或公共服务器上可用的版本之一,可以将 jQuery 库包含在文档中。 为了包括 jQuery 库,我们使用<script>
标签。 该文件通常位于</body>
标签之前,位于文档的开头或底部。
<script src="jquery-3.1.1.min.js"></script>
在这种情况下,我们包括 jQuery 库的本地副本。
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
在这里,我们包含来自code.jquery.com
上公共可用存储库的库。
有几个著名的 jQuery 公共存储库。 这些存储库也称为内容交付网络(CDN)。 使用 CDN 可以带来一些性能优势。
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.1.1.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
在这里,我们有 jQuery,Google 和 Microsoft CDN。
选择文本编辑器
一个好的文本编辑器将帮助我们有效地编写代码。 文本编辑器提供语法高亮显示,代码完成,自动缩进等功能。 支持 jQuery 的文本编辑器包括括号,Sublime Text,Kwrite,Gedit,Notepad ++,PSPad 或 TextMate。
图:括号文本编辑器
上图显示了一个在 Brackets 文本编辑器中使用 jQuery 的小型 HTML 文档。 Brackets 是用于 Web 开发的现代文本编辑器。 它是用 JavaScript 编写的。 它是专门为 Web 设计师和前端开发者创建的。
准备好文件后
当文档准备就绪时,即已经构建了它的 DOM 并且可以安全地对其进行操作,jQuery 会触发$(document).ready()
事件。 我们将 jQuery 代码放入此事件的处理器中。
$(document).ready(function() {
// jQuery code
});
$(function() {
// jQuery code
});
这些是文档就绪的事件处理器; 两者是等效的。 第二种方法是创建 jQuery 文档就绪事件处理器的推荐方法。
simple.html
<html>
<head>
<title>jQuery simple example</title>
<meta charset="utf-8">
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
</head>
<body>
<h2>Simple example</h2>
<script>
$(function() {
$('body').append("<div>Simple jQuery example</div>");
});
</script>
</body>
</html>
该示例在<body>
标签的末尾附加了<div>
标签。
$('body').append("<div>Simple jQuery example</div>");
$('body')
选择文档中的<body>
标签。 append()
方法将<div>
标签附加在<body>
标签的末尾。
测试与调试
浏览器包含供开发者进行测试和调试的工具。 在 Opera,Firefox 和 Chrome 浏览器中,通过 Ctrl + Shift + I
启动开发者控制台。
图:开发者控制台
在控制台窗口中,我们可以看到从console.log()
方法输出的错误消息。 它可用于评估 JavaScript 语句,检查和记录对象和属性。 在上图中,我们可以看到 jQuery html()
方法的输出,该方法获取<body>
元素的 HTML 代码。 输出显示在控制台窗口中。
<script>
$(function() {
console.log('Document is ready');
});
</script>
console.log()
方法可用于调试输出。
图:语法错误
在上图中,我们可以看到 jQuery 语法错误被捕获并显示在开发者控制台窗口中。
jQuery 选择器
jQuery 选择器用于选择 HTML 文档中满足某些条件的元素。 条件可以是它们的名称,ID,类名称,属性或它们的组合。
以下是可用选择器的部分列表:
$("*")
- 选择所有元素$("#first")
— 用id="first
选择元素$(".intro")
— 选择带有class="intro"
的所有元素$("div")
- 选择所有<div>
元素$("h2, div, p")
- 选择所有<h2>, <div>, <p>
元素$("li:first")
— 选择第一个<li>
元素$("li:last")
— 选择最后一个<li>
元素$("li:even")
— 选择所有偶数<li>
元素$("li:odd")
- 选择所有奇数<li>
元素$(":empty")
- 选择所有为空的元素$(":focus")
- 选择当前具有焦点的元素
在下面的示例中,我们将使用:root
选择器,该选择器选择<html>
标签。
root_selector.html
<!DOCTYPE html>
<html>
<head>
<title>jQuery root selector example</title>
<meta charset="utf-8">
<style>
.mycol { background-color: gray; border: 1px solid gray }
</style>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
</head>
<body>
<p>
A paragraph.
</p>
<script>
$(function() {
$(":root").addClass("mycol");
});
</script>
</body>
</html>
在示例中,文档的背景更改为灰色。
$(":root").addClass("mycol");
使用:root
选择器,选择文档的根元素,然后使用addClass()
方法向其中添加一个类。
selecting_elements.html
<!DOCTYPE html>
<html>
<head>
<title>jQuery selecting elements</title>
<meta charset="utf-8">
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
</head>
<body>
<p>Operating systems:</p>
<ul id="mylist" style="width:150px">
<li>Solaris</li>
<li>FreeBSD</li>
<li>Debian</li>
<li>NetBSD</li>
<li>Windows</li>
<li>Mac OS X</li>
</ul>
<script>
$(function() {
$("#mylist").css("border", "1px dashed gray");
$("li:odd").css("color", "blue");
});
</script>
</body>
</html>
在此示例中,我们有一个操作系统列表。 该列表带有蓝色虚线边框,并且每个奇数元素都有灰色背景。
$("#mylist").css("border", "1px dotted blue");
$("#mylist")
选择器选择 ID 等于mylist
的标签。 使用css()
方法,我们可以修改标签的外观。
$("li:odd").css("background-color", "gray");
使用$("li:odd")
选择器,我们选择所有奇数<li>
标签,然后使用css()
方法对其进行修改。
图:选择文档元素
在图中,我们可以看到列表周围的虚线边框和每隔一个列表元素的蓝色文本颜色。
链接方式
jQuery 允许链接方法调用。 方法链是对 jQuery 对象的 jQuery 方法调用的连续序列。
chaining.html
<!DOCTYPE html>
<html>
<head>
<title>jQuery chaining methods</title>
<meta charset="utf-8">
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<style>
.mypanel { width:150px; height:100px; background-color:blue }
</style>
</head>
<body>
<div class="mypanel"></div>
<script>
$(function() {
$(".mypanel").hide(1500).show(1500).hide(1500).show(1500);
});
</script>
</body>
</html>
在该示例中,我们有一个显示和隐藏两次的面板。 用show()
方法显示一个面板,用hide()
方法隐藏一个面板。
$(".mypanel").hide(1500).show(1500).hide(1500).show(1500)
在这里,我们看到了四个方法调用的链。 每个调用都返回一个 jQuery 对象,我们可以在该对象上调用另一个方法。
获取和设置内容
text()
方法获取匹配元素集中每个元素的组合文本内容(包括它们的后代),或设置匹配元素的文本内容。
getting_setting_content.html
<html>
<head>
<title>jQuery getting, setting elements</title>
<meta charset="utf-8">
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
</head>
<body>
<h2>Red car</h2>
<h3></h3>
<script>
$(function() {
var cont = $("h2").text();
$("h3").text(cont);
});
</script>
</body>
</html>
在示例中,我们获取<h2>
标签的内容并将其设置为<h3>
标签; 换句话说,我们将内容从第一个元素复制到第二个元素。
var cont = $("h2").text();
通过text()
方法,我们获得<h2>
标签的内容。
$("h3").text(cont);
在这一行中,我们将先前检索的内容设置为<h3>
标签。
绑定事件
on()
方法将一个或多个事件的事件处理器函数插入到当前选定的元素集。 当启动均匀(例如按钮单击)时,将触发事件处理器。
event_binding.html
<!DOCTYPE html>
<html>
<head>
<title>jQuery event binding example</title>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<style>
.mypanel { width:150px; height:100px; background-color:maroon }
</style>
</head>
<body>
<button id="btn">Toggle</button>
<br>
<br>
<div class="mypanel"></div>
<script>
$(function() {
$("#btn").on('click', function() {
$(".mypanel").slideToggle(2000);
});
});
</script>
</body>
</html>
在示例中,我们将事件处理器绑定到按钮元素上的click
事件。
<button id="btn">Toggle</button>
这是触发点击事件的按钮。
<script>
$(function() {
$("#btn").on('click', function() {
$(".mypanel").slideToggle(2000);
});
});
</script>
我们为按钮元素注册一个click
事件。 该事件触发一个函数,该函数在<div>
元素上调用slideToggle()
方法。 slideToggle()
方法以滑动方式显示或隐藏匹配的元素。
鼠标移动事件
当鼠标指针移至文档区域上方时,将触发鼠标移动事件。 事件处理器函数接收一个事件对象,其中包含与事件类型有关的数据。 在我们的例子中,它将包含鼠标指针的x
和y
坐标。
mouse_move_event.html
<!DOCTYPE html>
<html>
<head>
<title>jQuery mousemove event</title>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<style>
.mypanel { width:250px; height:200px; background-color:maroon }
</style>
</head>
<body>
<div class="mypanel"></div>
<br>
<div id="log"></div>
<script>
$(function() {
$(".mypanel").mousemove(function(e) {
var msg = "x: " + e.pageX + " y: " + e.pageY;
$("#log").text(msg);
});
});
</script>
</body>
</html>
如果我们将鼠标指针放在<div>
元素的区域上,则该示例显示它的x
和y
坐标。
<div class="mypanel"></div>
我们将在此元素的区域上监听鼠标移动事件。
<div id="log"></div>
坐标将显示在该记录的<div>
元素中。
$(".mypanel").mousemove(function(e) {
var msg = "x: " + e.pageX + " y: " + e.pageY;
$("#log").text(msg);
});
我们将事件处理器绑定到鼠标移动事件。 在事件处理器内部,我们使用pageX
和pageY
属性确定x
和y
坐标,并使用text()
方法更新日志记录元素。 mousemove()
方法是on("mousemove", handler)
方法的快捷方式。
图:鼠标移动事件
事件来源
事件源是触发事件的元素。 在事件处理器内部,我们可以使用$(this)
语法引用事件源。
event_source.html
<!DOCTYPE html>
<html>
<head>
<title>jQuery event source example</title>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<style>
.mybtn { }
</style>
</head>
<body>
<button class="mybtn">Button 1</button>
<button class="mybtn">Button 2</button>
<button class="mybtn">Button 3</button>
<br>
<br>
<div class="messages"></div>
<script>
$(function() {
$(".mybtn").on('click', function() {
var btn_lbl = $(this).text();
$(".messages").text(btn_lbl + " clicked");
});
});
</script>
</body>
</html>
在示例中,我们有三个按钮。 每个按钮具有相同的事件处理器。 当我们单击一个按钮时,会显示一条消息; 它告诉您单击了哪个按钮。
<button class="mybtn">Button 1</button>
<button class="mybtn">Button 2</button>
<button class="mybtn">Button 3</button>
这三个按钮具有相同的事件处理器。
<script>
$(function() {
$(".mybtn").on('click', function() {
var btn_lbl = $(this).text();
$(".messages").text(btn_lbl + " clicked");
});
});
</script>
类选择器$(".mybtn")
选择所有三个按钮。 我们将click
事件处理器附加到按钮上。 我们使用$(this)
构造引用事件源,并使用text()
方法确定事件的标签。 按钮的名称用于构建消息,该消息显示在下面的<div>
元素中。
图:事件源
在图中,我们可以看到在按钮下方显示的消息中单击了哪个按钮。
移除元素
remove()
方法从 DOM 中删除匹配的元素集。
remove_element.html
<!DOCTYPE html>
<html>
<head>
<title>jQuery removing element</title>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<style>
div { display: flex; align-items: center; justify-content: center;
width:150px; height:80px; margin:3px; border: 1px solid gray
}
</style>
</head>
<body>
<button id="btnf">Remove first</button>
<button id="btnl">Remove last</button>
<div>Panel 1</div>
<div>Panel 2</div>
<div>Panel 3</div>
<div>Panel 4</div>
<div>Panel 5</div>
<div>Panel 6</div>
<script>
$(function() {
$('#btnf').click(function() {
$('div:first').remove();
});
$('#btnl').click(function() {
$('div:last').remove();
});
});
</script>
</body>
</html>
在示例中,我们有两个按钮和六个面板。 第一个按钮删除第一个面板,第二个按钮删除最后一个面板。
$('#btnf').click(function() {
$('div:first').remove();
});
div:first
选择器选择第一个<div>
元素,然后remove()
方法将其从 DOM 中删除。
jQuery is()
方法
is()
方法针对选择器,元素或 jQuery 对象检查当前匹配的元素集,如果这些元素中的至少一个与给定参数匹配,则返回true
。
condition.html
<!DOCTYPE html>
<html>
<head>
<title>First jQuery example</title>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<style>
div { display: flex; align-items: center; text-align: center; width:150px;
height:100px; margin:3px; border: 1px solid gray }
</style>
</head>
<body>
<div id="pnl1">Panel 1</div>
<div id="pnl2">Panel 2</div>
<div id="pnl3">Panel 3</div>
<div id="pnl4">Panel 4</div>
<script>
$(function() { $("div").on('click', function() {
if ($(this).is('#pnl3')) {
console.log("Cannot hide panel 3");
} else {
$(this).hide(2000);
}
});
});
</script>
</body>
</html>
在示例中,我们有四个面板。 单击面板上的面板开始消失。 第三面板不消失。
<script>
$(function() { $("div").on('click', function() {
if ($(this).is('#pnl3')) {
console.log("Cannot hide panel 3");
} else {
$(this).hide(2000);
}
});
});
</script>
$(this)
语法引用事件源,即我们单击其上的面板。 使用is()
方法,我们检查元素是否为面板 3; 如果是面板 3,我们会在控制台上打印一条消息,并且不要将其隐藏。 其他面板用hide()
方法隐藏。
特效
在本节中,我们将展示一些基本的 jQuery 效果。
jQuery 滑动效果
slideUp()
方法以向上滑动显示匹配的元素,而slideDown()
方法以向下滑动显示。 方法的第一个参数是持续时间; 它是一个字符串或数字,确定动画将运行多长时间。 字符串可以是'slow'
或'fast'
; 默认值为 400 毫秒。
sliding.html
<!DOCTYPE html>
<html>
<head>
<title>jQuery sliding example</title>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<style>
.mypanel { width:150px; margin-top:10px;
height:100px; background-color:maroon }
</style>
</head>
<body>
<button id="btnSlideUp">Slide up</button>
<button id="btnSlideDown">Slide down</button>
<div class="mypanel"></div>
<script>
$(function() {
$('#btnSlideUp').click(function() {
$('.mypanel').slideUp('show');
});
$('#btnSlideDown').click(function() {
$('.mypanel').slideDown('show');
});
});
</script>
</body>
</html>
在示例中,我们有两个按钮。 一个按钮将向上滑动面板,另一个按钮将向下滑动面板。
$('#btnSlideUp').click(function() {
$('.mypanel').slideUp('show');
});
slideUp()
方法以向上滑动的方式为选定的元素设置动画; 该元素将从窗口中消失。
$('#btnSlideDown').click(function() {
$('.mypanel').slideDown('show');
});
slideDown()
方法以向下滑动的方式对元素进行动画处理,该元素出现在窗口中。
animate()
方法
animate()
方法对一组 CSS 属性执行自定义动画。 该方法的第一个参数称为属性。 它是动画将朝其移动的 CSS 属性和值的对象。 第二个参数是持续时间。
animation.html
<!DOCTYPE html>
<html>
<head>
<title>jQuery animation example</title>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<style>
.mypanel { position: relative; width:150px; margin-top:10px;
height:100px; background-color:maroon }
</style>
</head>
<body>
<button id="leftBtn">«</button>
<button id="rightBtn">»</button>
<div class="mypanel"></div>
<script>
$(function() {
$("#rightBtn").click(function() {
$(".mypanel").animate({ "left": "+=250px" }, "slow" );
});
$( "#leftBtn" ).click(function(){
$(".mypanel").animate({ "left": "-=250px" }, "slow" );
});
});
</script>
</body>
</html>
在示例中,我们有两个按钮。 第一个按钮将面板向左移动,第二个按钮将其向右移动。
$("#rightBtn").click(function() {
$(".mypanel").animate({ "left": "+=250px" }, "slow" );
});
这会将面板缓慢向左移动 250 像素。
$( "#leftBtn" ).click(function(){
$(".mypanel").animate({ "left": "-=250px" }, "slow" );
});
这会将面板缓慢向右移动 250 像素。
jQuery 淡入淡出效果
fadeIn()
方法通过将匹配的元素淡化为不透明来显示它们。 fadeOut()
方法通过将匹配的元素淡化为透明来隐藏它们。
fading.html
<!DOCTYPE html>
<html>
<head>
<title>jQuery fading example</title>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<style>
.mypanel { width:150px; margin-top:10px;
height:100px; background-color:maroon }
</style>
</head>
<body>
<button id="fadeOutBtn">Fade out</button>
<button id="fadeInBtn">Fade in</button>
<div class="mypanel"></div>
<script>
$(function() {
$('#fadeOutBtn').click(function() {
$('.mypanel').fadeOut('slow');
});
$('#fadeInBtn').click(function() {
$('.mypanel').fadeIn('slow');
});
});
</script>
</body>
</html>
在示例中,我们有两个按钮。 一个按钮淡入面板; 第二个按钮淡出面板。
$('#fadeOutBtn').click(function() {
$('.mypanel').fadeOut('slow');
});
此函数使用fadeOut()
方法淡出匹配的元素。
$('#fadeInBtn').click(function() {
$('.mypanel').fadeIn('slow');
});
此函数通过fadeIn()
方法淡入匹配的元素。
jQuery $.get()
方法
$.get()
方法使用 HTTP GET 请求从服务器请求数据。 该请求是异步 GET 请求。
在本节中,我们将创建一个 Java Web 应用。 单击一个按钮,将 AJAX GET 请求发送到 Java Servlet,该 Java Servlet 会以一条消息进行响应。
index.html
<!DOCTYPE html>
<html>
<head>
<title>jQuery GET message</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
</head>
<body>
<button id="btn">Get message</button>
<span id="log"></span>
<script>
$(function () {
$("#btn").click(function () {
$.get("MyServlet", function (data) {
$("#log").text(data);
});
});
});
</script>
</body>
</html>
我们有一个按钮,单击该按钮即可发送异步 GET 请求。
$(function () {
$("#btn").click(function () {
$.get("MyServlet", function (data) {
$("#log").text(data);
});
});
});
$.get()
方法的第一个参数是将请求发送到的 URL 字符串。 第二个参数是一个回调函数,如果请求成功,则执行该函数。 在回调函数内部,我们将返回的数据设置为日记记录元素。
MyServlet.java
package com.zetcode.web;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(name = "MyServlet", urlPatterns = {"/MyServlet"})
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/plain;charset=UTF-8");
try (PrintWriter out = response.getWriter()) {
Date date = new Date();
out.printf("Message from MyServlet: %s", date);
}
}
}
这是一个响应消息的 Java servlet。 该消息包含当前日期。
图:jQuery 异步 GET 请求
单击按钮,该按钮旁边的日志记录元素中将显示一条消息。
jQuery when()
方法
jQuery when()
方法执行具有异步事件的回调函数。
showing_hiding.html
<!DOCTYPE html>
<html>
<head>
<title>jQuery showing/hiding elements</title>
<meta charset="utf-8">
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<style>
div { display:flex; align-items:center; text-align:center; width:150px;
height:100px; margin:3px; border: 1px solid gray }
</style>
</head>
<body>
<button id="btn1">Hide all</button>
<div id="pnl1">Panel 1</div>
<div id="pnl2">Panel 2</div>
<div id="pnl3">Panel 3</div>
<div id="pnl4">Panel 4</div>
<script>
$(function() { $("#btn1").click(function() {
var task = $("div").toggle(3000);
$.when(task).done(function() {
if ($("#btn1").text().match("^Hide")) {
$("#btn1").text("Show all");
} else {
$("#btn1").text("Hide all");
}
});
});
});
</script>
</body>
</html>
在示例中,我们有一个按钮来隐藏/显示所有四个面板。 隐藏/显示元素的过程需要一些时间。 任务结束后,按钮的标签将相应更改:从全部隐藏到全部显示,反之亦然。
var task = $("div").toggle(3000);
创建一个新任务; 这需要 3 秒钟才能完成。 toggle()
方法显示或隐藏匹配的元素。
$.when(task).done(function() {
任务完成后将调用该函数。
if ($("#btn1").text().match("^Hide")) {
$("#btn1").text("Show all");
} else {
$("#btn1").text("Hide all");
}
现在,使用正则表达式,我们更改按钮的标签。
在本教程中,我们使用了 jQuery 库。
您可能也对以下相关教程感兴趣: jQuery 自动完成教程, Cheerio 教程,使用 jQuery DatePicker
和 Pyquery 教程。
Google 图表教程
原文: https://zetcode.com/web/googlecharts/
Google 图表教程是 Google 图表库的入门教程。 它显示了如何使用 Google 图表库在 JavaScript 中创建交互式图表。 在我们的示例中,我们创建了散点图,折线图和饼图。
Google 图表是一种交互式 Web 服务,可根据用户提供的信息创建图形图表。 用户使用嵌入在网页中的 JavaScript 提供数据和格式; 作为响应,服务发送图表图像。 该库提供了大量现成的图表类型。
图表具有一些默认外观,我们可以更改图表的外观。 图表具有高度的交互性,并公开事件,使我们可以将它们连接起来以创建复杂的结构。 图表使用 HTML5/SVG 技术呈现,以提供跨浏览器和跨平台的兼容性(包括 iPhone,iPad 和 Android)。
DataTable
图表填充有DataTable
类。 它是一个二维的可变值表。 它具有用于排序,修改和过滤数据的方法。 可以直接从网页,数据库或任何支持图表工具数据源协议的数据提供者中填充它。
散点图
散点图是一种图形或数学图,使用笛卡尔坐标显示一组数据的两个变量的值。 使用google.visualization.ScatterChart
创建一个散点图。
scatter.html
<html>
<head>
<script src="https://www.gstatic.com/charts/loader.js"></script>
<script>
google.charts.load('current', {'packages':['corechart']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn('string', 'Date');
data.addColumn('number', 'Price');
data.addRows([
['Mar 14', 43],
['Nov 14', 39],
['Jan 15', 42],
['Mar 15', 37],
['Dec 15', 34],
['Feb 16', 40]
]);
var options = {
title: "Gold Prices",
width: 600,
height: 400,
vAxis: {title: 'USD/kg'},
legend: { position: "none" }
};
var chart = new google.visualization.ScatterChart(document.getElementById('mychart'));
chart.draw(data, options);
}
</script>
</head>
<body>
<div id="mychart"></div>
</body>
</html>
在此示例中,我们创建了一个散点图。
<script src="https://www.gstatic.com/charts/loader.js"></script>
<script>
我们加载图表 API。
google.charts.load('current', {'packages':['corechart']});
第一步,我们加载可视化 API 和corechart
包。
google.charts.setOnLoadCallback(drawChart);
我们设置了在加载 Google 可视化 API 时运行的回调。
function drawChart() {
在drawChart()
函数中,我们创建并填充数据表,生成图表并绘制。
var data = new google.visualization.DataTable();
我们创建数据表。
data.addColumn('string', 'Date');
data.addColumn('number', 'Price');
用addColumn()
方法添加列。 参数是数据类型和标签。
data.addRows([
['Mar 14', 43],
['Nov 14', 39],
['Jan 15', 42],
['Mar 15', 37],
['Dec 15', 34],
['Feb 16', 40]
]);
数据通过addRows()
方法添加到数据表中。
var options = {
title: "Gold Prices",
width: 600,
height: 400,
vAxis: {title: 'USD/kg'},
legend: { position: "none" }
};
在这里,我们设置图表选项。 我们为图表赋予标题,设置其大小,垂直轴标签并禁用图例。
var chart = new google.visualization.ScatterChart(document.getElementById('mychart'));
我们使用google.visualization.ScatterChart
生成图表。 我们将图表选项传递给draw()
方法。
chart.draw(data, options);
该图表是用draw()
方法绘制的。 我们将图表选项传递给draw()
方法。
<body>
<div id="mychart"></div>
</body>
这是将保存图表的标记。
图:散点图
折线图
折线图是一种基本类型的图表,它将信息显示为由直线段连接的一系列数据点。 使用google.visualization.LineChart
创建折线图。
linechart.html
<html>
<head>
<script src="https://www.gstatic.com/charts/loader.js"></script>
<script>
google.charts.load('current', {'packages':['corechart']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var data = google.visualization.arrayToDataTable([
['Age', 'Salary'],
['18', 567],
['20', 612],
['25', 800],
['30', 980],
['40', 1410],
['50', 2350]
]);
var options = {
title: 'Average salary per age',
curveType: 'function',
width:900,
height:500,
vAxis: {title: 'Salary (Eur)'},
hAxis: {title: 'Age'},
legend: { position: 'bottom' }
};
var chart = new google.visualization.LineChart(document.getElementById('mychart'));
chart.draw(data, options);
}
</script>
</head>
<body>
<div id="mychart"></div>
</body>
</html>
在此示例中,我们有一个折线图,显示每个年龄段的平均工资。
var data = google.visualization.arrayToDataTable([
['Age', 'Salary'],
['18', 567],
['20', 612],
['25', 800],
['30', 980],
['40', 1410],
['50', 2350]
]);
arrayToDataTable()
是使用二维数组并将其转换为DataTable
的辅助方法。
var options = {
title: 'Average salary per age',
curveType: 'function',
...
我们可以通过将curveType
设置为function
来平滑线条。
var chart = new google.visualization.LineChart(document.getElementById('mychart'));
折线图是使用google.visualization.LineChart
生成的。
图:折线图
饼形图
饼图是圆形图,将其分成多个切片以说明数值比例。 使用google.visualization.PieChart
创建饼图。
piechart.html
<html>
<head>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.charts.load('current', {'packages':['corechart']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn('string', 'Fruit');
data.addColumn('number', 'Quantity');
data.addRows([
['Oranges', 38],
['Pears', 45],
['Plums', 24],
['Blueberries', 10]
]);
var options = {
'title': 'Fruits',
'titleTextStyle': {
'fontSize': '22',
},
'width':500,
'height':400
};
var chart = new google.visualization.PieChart(document.getElementById('mychart'));
chart.draw(data, options);
}
</script>
</head>
<body>
<div id="mychart"></div>
</body>
</html>
该示例创建一个饼图。
var data = new google.visualization.DataTable();
data.addColumn('string', 'Fruit');
data.addColumn('number', 'Quantity');
data.addRows([
['Oranges', 38],
['Pears', 45],
['Plums', 24],
['Blueberries', 10]
]);
在图表中,我们显示了可用水果的比例。
var options = {
'title': 'Fruits',
'titleTextStyle': {
'fontSize': '22',
},
'width':500,
'height':400
};
在图表选项中,我们设置图表标题,更改默认标题字体大小并设置图表的大小。
var chart = new google.visualization.PieChart(document.getElementById('chart_div'));
使用google.visualization.PieChart
创建饼图。
图:饼图
在本教程中,我们使用 Google 图表库创建了散点图,折线图和饼图。