nodejs学习笔记

相等运算符=====

==,它会自动转换数据类型再比较,很多时候,会得到非常诡异的结果;

===,它不会自动转换数据类型,如果数据类型不一致,返回false,如果一致,再比较。

由于JavaScript这个设计缺陷,不要使用==比较,始终坚持使用===比较。

NaN

NaN这个特殊的Number与所有其他值都不相等,包括它自己:

NaN === NaN; // false

唯一能判断NaN的方法是通过isNaN()函数:

数组

JavaScript的数组可以包括任意数据类型,如:

[1, 2, 3.14, 'Hello', null, true];

创建数组的方法:

1. var arr = [1, 2, 3.14, 'Hello', null, true];
2. new Array(1, 2, 3); // 创建了数组[1, 2, 3]

变量

使用=对变量进行赋值。可以把任意数据类型赋值给变量,同一个变量可以反复赋值,而且可以是不同类型的变量,但是要注意只能用var申明一次.

var a = 123; // a的值是整数123
a = 'ABC'; // a变为字符串

多行字符串

由于多行字符串用\n写起来比较费事,所以最新的ES6标准新增了一种多行字符串的表示方法,用反引号 `` 表示

模板字符串

var message = '你好, ' + name + ', 你今年' + age + '岁了!';
var message = `你好, ${name}, 你今年${age}岁了!`;

复制数组

如果不给slice()传递任何参数,它就会从头到尾截取所有元素。利用这一点,我们可以很容易地复制一个Array

var arr = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];
var aCopy = arr.slice();
aCopy; // ['A', 'B', 'C', 'D', 'E', 'F', 'G']
aCopy === arr; // false

给对象删除属性

delete xiaoming.age; // 删除age属性

判断对象是否拥有属性

如果要检测xiaoming是否拥有某一属性,可以用in操作符,如果in判断一个属性存在,这个属性不一定是xiaoming的,它可能是xiaoming继承得到的

var xiaoming = {
    name: '小明',
    birth: 1990,
    school: 'No.1 Middle School',
    height: 1.70,
    weight: 65,
    score: null
};
'name' in xiaoming; // true
'grade' in xiaoming; // false

要判断一个属性是否是xiaoming自身拥有的,而不是继承得到的,可以用hasOwnProperty()方法:

var xiaoming = {
    name: '小明'
};
xiaoming.hasOwnProperty('name'); // true
xiaoming.hasOwnProperty('toString'); // false

JavaScript把nullundefined0NaN和空字符串` `;视为false,其他值一概视为true

循环

for … in

for循环的一个变体是for ... in循环,它可以把一个对象的所有属性依次循环出来

请注意,for … in对Array的循环得到的是String而不是Number。

Map和Set

初始化Map需要一个二维数组,或者直接初始化一个空Map

var m = new Map([['Michael', 95], ['Bob', 75], ['Tracy', 85]]);
m.get('Michael'); // 95

var m = new Map(); // 空Map
m.set('Adam', 67); // 添加新的key-value

要创建一个Set,需要提供一个Array作为输入,或者直接创建一个空Set

var s1 = new Set(); // 空Set
var s2 = new Set([1, 2, 3]); // 含1, 2, 3

iterable

ArrayMapSet都属于iterable类型。

具有iterable类型的集合可以通过新的for ... of循环来遍历。

var a = [1, 2, 3];
for (var x of a) {
}
console.log('你的浏览器支持for ... of');

for ... of循环和for ... in循环有何区别?

for ... in循环遍历的实际上是对象的属性名称,当给Array对象添加了额外的属性后,遍历时会遍历得到

for ... of,只循环集合本身的元素,添加的额外属性并不会遍历得到

函数定义

第一种:

function abs(x) {
    if (x >= 0) {
        return x;
    } else {
        return -x;
    }
}

第二种:(匿名方式)

var abs = function (x) {
    if (x >= 0) {
        return x;
    } else {
        return -x;
    }
};

arguments关键字

arguments,它只在函数内部起作用,利用arguments,你可以获得调用者传入的所有参数。arguments类似Array但它不是一个Array

// foo(a[, b], c)
// 接收2~3个参数,b是可选参数,如果只传2个参数,b默认为null:

function foo(x) {
    console.log('x = ' + x); // 10
    for (var i=0; i<arguments.length; i++) {
        console.log('arg ' + i + ' = ' + arguments[i]); // 10, 20, 30
    }
}
foo(10, 20, 30);

rest关键字

rest参数只能写在最后,前面用...标识,传入的参数先绑定ab,多余的参数以数组形式交给变量rest

如果传入的参数连正常定义的参数都没填满,也不要紧,rest参数会接收一个空数组(注意不是undefined)。

function foo(a, b, ...rest) {
    console.log('a = ' + a);
    console.log('b = ' + b);
    console.log(rest);
}

foo(1, 2, 3, 4, 5);
// 结果:
// a = 1
// b = 2
// Array [ 3, 4, 5 ]

变量的局部作用域

function foo() {
    for (var i=0; i<100; i++) {
        //
    }
    i += 100; // 仍然可以引用变量i
}

js中用let替代var可以申明一个块级作用域的变量

function foo() {
    var sum = 0;
    for (let i=0; i<100; i++) {
        sum += i;
    }
    // SyntaxError:
    i += 1;
}

解构赋值(直接对多个变量同时赋值)

数组元素进行解构赋值时,用[...]括起来

var [x, y, z] = ['hello', 'JavaScript', 'ES6'];
// x, y, z分别被赋值为数组对应元素:
console.log('x = ' + x + ', y = ' + y + ', z = ' + z);

对对象进行解析赋值时,用{...}括起来

var person = {
    name: '小明',
    age: 20,
    gender: 'male',
    passport: 'G-12345678',
    school: 'No.4 middle school'
};

// 把passport属性赋值给变量id:
let {name, passport:id} = person;
name; // '小明'
id; // 'G-12345678'
// 注意: passport不是变量,而是为了让变量id获得passport属性:
passport; // Uncaught ReferenceError: passport is not defined

解构赋值在很多时候可以大大简化代码,例如,交换两个变量xy的值

var x=1, y=2;
[x, y] = [y, x]

方法

在一个对象中绑定函数,称为这个对象的方法。

var xiaoming = {
    name: '小明',
    birth: 1990,
    age: function () {
        var y = new Date().getFullYear();
        return y - this.birth;
    }
};

xiaoming.age; // function xiaoming.age()
xiaoming.age(); // 今年调用是25,明年调用就变成26了

在一个方法内部,this是一个特殊变量,它始终指向当前对象

在一个函数内部如果调用了this,那么这个this指向视情况而定

举例:

function getAge() {
    var y = new Date().getFullYear();
    return y - this.birth;
}

var xiaoming = {
    name: '小明',
    birth: 1990,
    age: getAge
};

xiaoming.age(); // 25, 正常结果
getAge(); // NaN

如果以对象的方法形式调用,比如xiaoming.age(),该函数的this指向被调用的对象,要保证this指向正确,必须用obj.xxx()的形式调用

如果单独调用函数,比如getAge(),此时,该函数的this指向全局对象,也就是window

箭头函数

 => x * x 

相当于匿名函数:

function (x) {
    return x * x;
}

标准对象

//包装类
var n = new Number(123); // 123,生成了新的包装类型
//普通函数  
var n = Number('123'); // 123,相当于parseInt()或parseFloat()

构建对象

调用构造函数千万不要忘记写new。为了区分普通函数和构造函数,按照约定,构造函数首字母应当大写,而普通函数首字母应当小写

function Student(name) {
    this.name = name;
    this.hello = function () {
        alert('Hello, ' + this.name + '!');
    }
}

var xiaoming = new Student('小明');
xiaoming.name; // '小明'
xiaoming.hello(); // Hello, 小明!

回调函数的同步和异步

同步优先、异步靠边、回调垫底

同步回调函数(函数的执行顺序从上而下)

var callback = function(arg3) {
    console.log('callback Totle is:' + arg3)
  }

function fn(arg1, arg2, cb) {
  var Total = arg1 + arg2;
  cb(Total);
  console.log('mainFunction Totle is:' + Total)
}

fn(2, 2, callback)   // 调用fn()函数,并传入2, 2, callback作为参数

异步回调函数(在函数的最后执行)

如何判断?

setTimeout()函数支持异步处理

function f2() {

    console.log('f2 finished') 
}

function f1(cb) {

    setTimeout(cb,1000)        //用setTimeout()模拟耗时操作
    console.log('f1 finished')
}

f1(f2);    //得到的结果是 f1 finished ,f2 finished
Share