ZetCode-JavaScript-教程-一-

龙哥盟 / 2024-11-20 / 原文

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()函数,我们可以获得nameage属性的值。

$ 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()函数,我们获得nameage属性,并形成两个新列表。

$ 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.ltR.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);

在示例中,我们按agename属性以升序对用户列表进行排序。

$ 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 findfindLast函数

find()函数返回与谓词匹配的列表的第一个元素;如果不匹配,则返回undefinedfindLast()函数返回列表中与谓词匹配的最后一个元素,如果没有元素匹配,则返回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()函数创建一个数字数组。 该函数接受startendstep参数。

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值是必需的,startstep是可选的。 end不包含在内; 因此,不包括值 10。

const vals2 = _.range(0, 15);

在这里,我们指定startstep参数。 我们创建一个值数组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()函数根据谓词函数创建两个数组。 通过数组解构操作,我们将创建的数组分配给两个变量:nums2nums3

$ 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());

该程序将打印数字数组的平均值。

minmax()

minmax()函数分别返回最小值和最大值。

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' } ]

数组通过nameoccupation键排序。

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.yamldefault.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 或容器中。 由于开发大部分是在本地计算机上完成的,因此环境变量可以通过setexport等命令放置到本地环境变量中,或者存储在本地.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

我们有三个变量:HOSTDATABASEPORT。 我们使用大写字母来遵守命名约定。

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选项停在第一个错误的验证,否则返回发现的所有错误。 默认为trueconvert选项尝试将值转换为所需的类型。 它也默认为true

callback是使用签名function(err, value)的可选同步回调方法。 如果验证失败,则err包含错误原因,否则为nullvalue是应用了任何类型转换和其他修饰符的值。

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-cligulpgulp-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目录运行该页面。

Displaying data in Handsontable component

图:在 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数据库,并将有关该数据库的一些信息写入控制台。 要检查创建的数据库,我们转到浏览器开发者工具的存储检查器。

Storage browser in Chrome

图: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

我们安装cheeriorequestlocal-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');

我们包括cheeriorequest模块。 使用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);
});

该示例循环访问ulli标签,并打印数组中元素的文本。

$ 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

headmainul元素包含三个以上的子代。 不包含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');

我们包括axiosfs模块。

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

我们也将使用jsonserveraxios

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 代码。 首先,我们安装了axiosjson-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 中使用正则表达式。

正则表达式用于文本搜索和更高级的文本操作。 正则表达式是内置工具,如grepsed,文本编辑器(如 vi,emacs),编程语言(如 JavaScript,Perl 和 Python)。

JavaScript 正则表达式

在 JavaScript 中,我们使用斜线//RegExp对象构建正则表达式。

模式是一个正则表达式,用于定义我们正在搜索或操纵的文本。 它由文本文字和元字符组成。 元字符是控制正则表达式计算方式的特殊字符。 例如,使用\s,我们搜索空白。

创建模式后,可以使用其中一个函数将模式应用于文本字符串。 函数包括test()match()search()replace()

下表显示了一些正则表达式:

正则表达式 含义
. 匹配任何单个字符。
? 一次匹配或根本不匹配前面的元素。
+ 与前面的元素匹配一次或多次。
* 与前面的元素匹配零次或多次。
^ 匹配字符串中的起始位置。
` 正则表达式
--- ---
. 匹配任何单个字符。
? 一次匹配或根本不匹配前面的元素。
+ 与前面的元素匹配一次或多次。
* 与前面的元素匹配零次或多次。
^ 匹配字符串中的起始位置。
匹配字符串中的结束位置。
| 备用运算符。
[abc] 匹配abc
[a-c] 范围; 匹配abc
[^abc] 否定,匹配除abc之外的所有内容。
\s 匹配空白字符。
\w 匹配单词字符; 等同于[a-zA-Z_0-9]

测试函数

test()方法执行搜索以查找正则表达式和指定字符串之间的匹配项。 它返回truefalse

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关键字设置属性。 使用thisfunction关键字创建方法。 使用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 被描述为一种无逻辑的模板引擎,因为它没有任何明确的控制流语句,例如ifelse条件语句或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 响应:timedatemilliseconds_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}}

Rendering JSON data from Servlet with Mustache

图:使用 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 驱动程序。 有两个驱动程序可用:mysqlmysql2; 我们选择了后者。

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,这使我们能够链接方法调用。

注意:如果没有传递回调,MongoClientconnect将返回一个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 驱动程序。 有两个驱动程序可用:mysqlmysql2; 我们选择了后者。

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 还创建了另外两个列:createdAtupdatedAt。 可以使用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 asyncawait

在下一个示例中,我们使用asyncawait关键字。

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();

我们使用asyncawait关键字返回带有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();

在示例中,我们选择iddescription列。

$ 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 offsetlimit

使用offsetlimit属性,我们可以定义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');

});

在示例中,我们有两个模型:EmployeeProject。 我们使用belongsTo在两个模型之间创建一对一关联。 我们将数据添加到模型中。

let Employee = sequelize.define('employees', {
    name: Sequelize.STRING
});

let Project = sequelize.define('projects', {
    name: Sequelize.STRING
});

我们定义了两个模型。

Employee.belongsTo(Project);

我们在EmployeeProject模型之间创建一对一关联。 外键在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();

首先,我们创建两个表:userstasks

在第二步中,我们用数据填充表。

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();

在第二个示例中,我们将promiseasync/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');

我们有employeesprojects。 员工只能分配到一个项目。

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');

我们有userstasks。 用户可以执行一个或多个任务。 一个任务只能由一个用户拥有。

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');

我们包括pgramda模块。

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/awaitnode-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

最后,我们启动开发服务器。

Sample application

图:示例应用

在本教程中,我们使用了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

DocumentquerySelector()方法返回文档中与指定选择器或一组选择器匹配的第一个元素。 如果找不到匹配项,则返回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()循环中,我们遍历列表并将类附加到每个元素。

Selecting elements with Document.querySelector

图:使用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_HEIGHTC_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); 

这两个数组存储蛇的所有关节的xy坐标。

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()随机选择苹果对象的xy坐标。 apple_xapple_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变量设置为truemove()函数中使用此变量来更改蛇对象的坐标。 还要注意,当蛇向右行驶时,我们不能立即向左转。

Snake game

图:贪食蛇 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对象。 它具有四个属性:namedescriptionfinisheddueDate

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标签。

Reading JSON from URL with JQuery

图:使用 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扩展名。

Source of a simple HTML document

图:一个简单的 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 text editor

图:括号文本编辑器

上图显示了一个在 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 启动开发者控制台。

Developer console

图:开发者控制台

在控制台窗口中,我们可以看到从console.log()方法输出的错误消息。 它可用于评估 JavaScript 语句,检查和记录对象和属性。 在上图中,我们可以看到 jQuery html()方法的输出,该方法获取<body>元素的 HTML 代码。 输出显示在控制台窗口中。

<script>
    $(function() { 
        console.log('Document is ready');
    });
</script>  

console.log()方法可用于调试输出。

Syntax error

图:语法错误

在上图中,我们可以看到 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()方法对其进行修改。

Selecting document elements

图:选择文档元素

在图中,我们可以看到列表周围的虚线边框和每隔一个列表元素的蓝色文本颜色。

链接方式

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()方法以滑动方式显示或隐藏匹配的元素。

鼠标移动事件

当鼠标指针移至文档区域上方时,将触发鼠标移动事件。 事件处理器函数接收一个事件对象,其中包含与事件类型有关的数据。 在我们的例子中,它将包含鼠标指针的xy坐标。

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>元素的区域上,则该示例显示它的xy坐标。

<div class="mypanel"></div>

我们将在此元素的区域上监听鼠标移动事件。

<div id="log"></div>

坐标将显示在该记录的<div>元素中。

$(".mypanel").mousemove(function(e) {

    var msg = "x: " + e.pageX + " y: " + e.pageY;  

    $("#log").text(msg);
});

我们将事件处理器绑定到鼠标移动事件。 在事件处理器内部,我们使用pageXpageY属性确定xy坐标,并使用text()方法更新日志记录元素。 mousemove()方法是on("mousemove", handler)方法的快捷方式。

Mouse move event

图:鼠标移动事件

事件来源

事件源是触发事件的元素。 在事件处理器内部,我们可以使用$(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>元素中。

Event source

图:事件源

在图中,我们可以看到在按钮下方显示的消息中单击了哪个按钮。

移除元素

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 asynchronous GET request

图: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>

这是将保存图表的标记。

Scatter chart

图:散点图

折线图

折线图是一种基本类型的图表,它将信息显示为由直线段连接的一系列数据点。 使用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生成的。

Line chart

图:折线图

饼形图

饼图是圆形图,将其分成多个切片以说明数值比例。 使用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创建饼图。

Pie chart

图:饼图

在本教程中,我们使用 Google 图表库创建了散点图,折线图和饼图。