Nodejs
Nodejs是服务器端运行JavaScript的开源、跨平台运行环境。
国内可以去阿里云镜像站
https://npm.taobao.org/mirrors/node
Visual Studio Code
下载 https://code.visualstudio.com/Download
支持windows、mac、Linux平台。
新版VS Code Windows版分为System 和 User两个版本,当前用户使用安装User版即可。
有代码自动完成功能,还可以安装Node exec插件,将写的js跑在nodejs上。
js是弱类型,不需要强制类型转换,会隐式类型转换。
NaN,即Not a Number,转换数字失败。它和任何值都不等,和自己也不等,只能使用Number.isNaN(NaN)
声明
var 声明一个变量
let 声明一个块作用域中的局部变量
const 声明一个常量
JS中的变量声明和初始化是可以分开的
var a // 只是声明,a为undefined
let b
console.log(1,a,b)
[out]:1 undefined undefined
a = 1
b = 'a string'
console.log(2,a,b)
[out]: 2 1 'a string'
var会把变量提升到当前全局或函数作用域。
总结:
遇到字符串,加号就是拼接字符串,所有非字符串隐式转换为字符串。
如果没有字符串,加号把其他所有类型都当数字处理,非数字类型隐式转换为数字。 undefined特殊,因为它都没
有定义值,所以转换数字失败得到一个特殊值NaN。
如果运算符是逻辑运算符,短路符,返回就是短路时的类型。没有隐式转换。
除非你十分明确,否则不要依赖隐式转换。写代码的时候,往往为了程序的健壮,请显式转换。
字符串
// 字符串插值,要求在反引号字符串中。python3.6支持
let name="tom", age = 19
console.log(`Hi, my name is ${name}. I am ${age}`)
[out]:Hi, my name is tom. I am 19
ES6提供了反引号定义一个字符串,可以支持多行,还支持插值。
let school = 'magedu'
console.log(school.charAt(2)) // g,string返回指定索引处的字符,所需字符的从零开始索引。
console.log(school[2]) // g ,同上
console.log(school.toUpperCase()) // MAGEDU,大写
console.log(school.concat('.com')) // 连接,string返回包含两个或多个字符串连接的字符串,附加到字符串末尾的字符串。
console.log(school.slice(3)) // 切片,支持负索引
console.log(school.slice(3,5))
console.log(school.slice(-2, -1))
console.log(school.slice(-2))//不包括end所指示的字符。如果未指定此值,则子字符串将继续到stringObj的末尾。
let url = "www.magedu.com"
console.log(url.split('.'))
console.log(url.substr(7,2)) // 返回子串从何处开始,取多长
console.log(url.substring(7,10)) // 返回子串,从何处开始,到什么为止
let s = 'magedu.edu'
console.log(s.indexOf('ed')) // 3,从头开始查找对应索引
console.log(s.indexOf('ed', 4)) // 7,如果指定将从此开始查找,返回匹配第一个找的索引值
console.log(s.replace('.edu', '.com'))
s = ' \tmag edu \r\n'
console.log(s.trim()) // 去除两端的空白字符。trimLeft、trimRight是非标函数,少用
console.log('-'.repeat(30))//重复
数值型number
八进制0755。注意0855,将被认作十进制,因为8不在八进制中。ES6中最好使用0o前缀表示八进制。
Number.parseInt() //取整
console.log(Math.random()) // (0, 1)间任意数字
console.log(1/2) // 0.5自然除
console.log(Math.round(3/2)) // 2,四舍五入
console.log(1/0) // 无异常,返回无穷
++ 和 –
单目运算符,代表变量自增、自减
i++ 先用i,用完之后i再自增加1
++i i先自增,再使用i
i = 0;
let a = ++i+i+++i+++i;// 等价于
++i + i++ + i++ + i
console.log(a); // 1 + 1 + 2 + 3
[out]:7
let i = 0
let a = i++
console.log(a, i) // 打印什么(0,1)
console.log(a, i++) // 打印什么(0,1)
a = -i++
console.log(a, ++i) // 打印什么(-2,4)
比较运算符
>、<、>=、<= 没有什么区别
!=、==
!、=
== 宽松相等,进行类型转换,
=== 严格相等,不进行类型转换
// 宽松比较
console.log(300 == '300') // true
console.log('200' == '200')//true
// 严格比较 ===
console.log(300 === '300')//false
console.log('200'==='200')// true
会先都转换为数字.建议比较的时候,一律使用 === 和 !==
三元运算符
条件表达式?真值:假值
console.log(('3' > 30)?'真':'假')
[out]:假
逗号运算符
let a = 4+5, b = true, c=a > 20 ?'t':'f'
console.log(a) //9
console.log(c)// f
function test() {
return 3, a + b, c = a++
}//3,10,9
console.log(test()) // 9
console.log(c) // 9,function 中的全局变量c 覆盖了之前的值
其他
console.log('a' instanceof String) // false
console.log(1 instanceof Number) // false
a = new String('b')
console.log(a instanceof String) // true
console.log(new Number(1) instanceof Number) // true
console.log(a instanceof Object) // true
console.log(typeof('a')) //string
console.log(typeof 'a') //string
console.log(typeof a) //object
instanceof 要求必须明确使用类型定义变量,就是对象必须是new关键字声明创建的。它可以用于继承关系的判断。
typeof就是返回对象的类型字符串。
x = 42;
var y = 43;
let z = 60;
myobj = new Number();
myobj.h = 4; // create property h
console.log(delete x); // returns true (如果隐式声明,可以删除)
console.log(delete y); // returns false (如果使用var声明,则不能删除)
console.log(delete z); // returns false
console.log(delete Math.PI); // returns false (无法删除预定义属性)
console.log(delete myobj.h); // returns true (可以删除用户定义的属性)
console.log(delete myobj); // returns true (如果隐式声明,可以删除)
console.log('~~~~~~~~~~~~~~~~~~~~')
var trees = new Array("redwood", "bay", "cedar", "oak", "maple");
for(var i=0;i<trees.length;i++)
console.log(trees[i])
console.log('==================')
delete trees[3]; // 数组中元素被删除,但空着的位置是undefined
for(var i=0;i<trees.length;i++)
console.log(trees[i])
in 判断属性是否在对象内
let trees = new Array("redwood", "bay", "cedar", "oak", "maple");
console.log(0 in trees); // returns true ,0在数组对象的index中
console.log(3 in trees); // returns true ,3在数组对象的index中
console.log(6 in trees); // returns false,6不在数组对象的index中
console.log("bay" in trees); // return false,bay不是属性,它是值
console.log("length" in trees); // returns true,length是对象的属性
console.log('~~~~~~~~~~~~~~~~~~~~')
delete trees[3];
console.log(3 in trees); // return false
for(var i=0;i<trees.length;i++)
console.log(trees[i]);
console.log('~~~~~~~~~~~~~~~~~~~~')
// Custom objects
let mycar = {
color: "red",
year: 1998
};
console.log("color" in mycar); // returns true
console.log("model" in mycar); // returns false
console.log('year' in mycar) // true
运算符优先级
逗号运算符优先级最低,比赋值语句还低。
记不住,就使用括号。
表达式
function * inc() {
let i = 0, j = 7
while (true) {
yield i++
if (!j--) return 100
}
}
let gen = inc()
for (let i=0;i<10;i++)
console.log(gen.next())
[out]:{ value: 0, done: false }
{ value: 1, done: false }
{ value: 2, done: false }
{ value: 3, done: false }
{ value: 4, done: false }
{ value: 5, done: false }
{ value: 6, done: false }
{ value: 7, done: false }
{ value: 100, done: true }
{ value: undefined, done: true }
每次调用next() 方法返回一个对象,这个对象包含两个属性:value 和 done,value 属性表示本次 yield 表达式的
返回值,done 属性为布尔类型。done是false表示后续还有yield语句执行,如果执行完成或者return后,done为
true。
switch…case分支语句
switch (expression) {
case label_1:
statements_1
[break;]
case label_2:
statements_2
[break;]
...
default:
statements_def
[break;]
}
最大的问题,就是穿透问题,一定要在case中恰当的使用break语句,否则就会继续顺序向下执行。
let x = 5 // 换成1试一试
switch (5) {
case 0:
console.log('zero')
break;
case 1:
console.log('one');
case 2:
console.log('two');
case 3:
console.log('three');
break;
case 5:
case 4:
console.log('four');
default:
console.log('other')
// break;
}
[out]: four
other
switch…case语句都可以写成多分支结构。
for循环
// C风格for循环
for ([initialExpression]; [condition]; [incrementExpression])
{
statement
}
for(var x=0,y=9;x<10;x++,y--){
console.log(x*y)
}
while循环 和 do…while循环
while (condition)
statement
条件满足,进入循环,条件为真,继续循环
do
statement
while (condition);
先进入循环,然后判断,为真就继续循环
let x = 10;
while (x--) {
console.log(x);
}
console.log('~~~~~~~~~~~~~~~~')
do {
console.log(x);
}while(x++<10)
// 分析这个程序的打印结果
[out]:
9
8
7
6
5
4
3
2
1
0
~~~~~~~~~~~~~~~~
-1
0
1
2
3
4
5
6
7
8
9
10
九九乘法表
for(let i = 1;i<10;i++){
line = "";
for (let j = 1;j<=i;j++){
line += `${j}*${i} = ${i*j} `;
}
console.log(line)
}
for…in循环
对象操作语句for…in用来遍历对象的属性
for (variable in object) {
statements
}
// 数组
let arr = [10, 20, 30, 40];
console.log(arr[1]) // 20
for (let x in arr)
console.log(x); // 返回索引
for (let index in arr)
console.log(`${index} : ${arr[index]}`); //插值
// C风格
for(let i=0;i<arr.length;i++)
console.log(arr[i]);
// 对象
let obj = {
a:1,
b:'magedu',
c:true
};
console.log(obj.a);
console.log(obj['b']); // 对象属性当索引访问
console.log(obj.d); // undefined
console.log('~~~~~')
for (let x in obj)
console.log(x); // 属性名
for (let key in obj) // 返回数组的index
console.log(`${key} : ${obj[key]}`);
[out]:
20
0
1
2
3
0 : 10
1 : 20
2 : 30
3 : 40
10
20
30
40
1
magedu
undefined
~~~~~
a
b
c
a : 1
b : magedu
c : true
for in 循环返回的是索引或者key,需要间接访问到值。
数组反正返回的是索引,C风格for循环操作可能方便点。根据个人喜好选择。
对象用for in合适。
for…of 循环
ES6的新语法
// for of
let arr = [1,2,3,4,5]
let obj = {
a:1,
b:'magedu',
c:true
}
for (let i of arr) { // 返回数组的元素
console.log(i)
}
for (let i of obj) {// 异常,不可以迭代
console.log(i)
}
注意:for … of 不能迭代一个普通对象。
原因是,of后面必须是一个迭代器(TypeError: obj[Symbol.iterator] is not a function)
可类比python中的for in,例如for x in [ ]
记住:数组可用for…in和for…of,
obj只能用for…in
for迭代的差别
function sum(arr){
for (let x in arr){ // 遍历index或对象属性
console.log(x, typeof(x), arr[x]);
}
for (let x of arr){ // 遍历元素
console.log(x, typeof(x));
}
for (let x=0;x<arr.length;x++){ // 自己定义索引数值遍历
console.log(x, typeof(x), arr[x]);
}
}
sum([3,6,9]);
[out]:
0 string 3
1 string 6
2 string 9
3 'number'
6 'number'
9 'number'
0 'number' 3
1 'number' 6
2 'number' 9
Symbols类型
ES6提供Symbol类型,内建原生类型。
let sym1 = Symbol()
let sym2 = Symbol('key1')
let sym3 = Symbol('key1')
console.log(sym2 == sym3) // false,symbol值是唯一的,返回一个新的惟一符号值。新符号对象的描述
1.作为对象的属性key
let s = Symbol()
let t = 'abc'
let a = {
[s]:'xyz', // symbol做key,注意要使用中括号,这个key一定唯一
t:'ttt',
[t]:'ooo'
}
console.log(a)
console.log(a[s])
a[s] = 2000
console.log(a[s])
[out]:
{ t: 'ttt', abc: 'ooo', [Symbol()]: 'xyz' }
xyz
2000
2.构建常量
// 以前用法
var COLOR_RED = 'RED';
var COLOR_ORANGE = 'ORANGE';
var COLOR_YELLOW = 'YELLOW';
var COLOR_GREEN = 'GREEN';
var COLOR_BLUE = 'BLUE';
var COLOR_VIOLET = 'VIOLET';
// 现在
const COLOR_RED = Symbol();
const COLOR_ORANGE = Symbol();
const COLOR_YELLOW = Symbol();
const COLOR_GREEN = Symbol();
const COLOR_BLUE = Symbol();
const COLOR_VIOLET = Symbol();
函数
function 函数名(参数列表) {
函数体;
return 返回值;
}
function add(x,y){
return x+y;
}
console.log(add(3,5));
函数表达式
使用表达式来定义函数,表达式中的函数名可以省略,如果这个函数名不省略,也只能用在此函数内部。
// 匿名函数
const add = function(x,y){
return x + y;
};
console.log(add(4,6));
// 有名字的函数表达式
const sub = function fn(x,y){
return x -y;
};
console.log(sub(4,3));
//console.log(fn(3, 2)); // fn只能用在函数内部
// 有名字的函数表达式
const sum = function _sum(n){
if (n===1) return n;
return n + _sum(--n)// _sum只能内部使用
}
console.log(sum(5));
练习
1.完成一个计数器counter
const counter = function (){
let c = 0;
return function(){
return ++c;
};
};
const c = counter()
console.log(c())
console.log(c())
console.log(c())
counter的生成器版本
const counter = (function *(){
let c = 1
while (true){
yield c++
}
})()
console.log(counter.next())
console.log(counter.next())
console.log(counter.next())
2.完成一个map函数:可以对某一个数组的元素进行某种处理
const map = function(arr,fn){
let newarr = [];
for (let i in arr){
newarr[i] = fn(arr[i]);
}
return newarr
}
console.log(map([1,2,3,4],function(x) {return x++}))
console.log(map([1,2,3,4],function(x) {return ++x}))
console.log(map([1,2,3,4],function(x) {return x+1}))
console.log(map([1,2,3,4],function(x) {return x+=1}))
[out]:
[ 1, 2, 3, 4 ]
[ 2, 3, 4, 5 ]
[ 2, 3, 4, 5 ]
[ 2, 3, 4, 5 ]
箭头函数
箭头函数就是匿名函数,它是一种更加精简的格式。
将上例中的你们函数更改为箭头函数
// 以下三行等价
console.log(map([1,2,3,4], (x) => {return x*2}));
console.log(map([1,2,3,4], x => {return x*2}));
console.log(map([1,2,3,4], x => x*2));
箭头函数参数
如果一个函数没有参数,使用()
如果只有一个参数,参数列表可以省略小括号()
多个参数不能省略小括号,且使用逗号间隔
箭头函数返回值
如果函数体部分有多行,就需要使用{},如果有返回值使用return。
如果只有一行语句,可以同时省略大括号和return。
只要有return语句,就不能省略大括号。 console.log(map([1,2,3,4], x => {return ++x})) ,有return必须有大括号。
如果只有一条非return语句,加上大括号,函数就成了无返回值了,例如 console.log(map([1,2,3,4], x =>
{x2})); 加上了大括号,它不等价于 x =>{return x2} 。因此,记住 x => x*2 这种正确的形式就行了。
普通函数
const add = (x,y) => x + y
console.log(add(4, 5))
// 缺省值
const add1 = (x, y=5) => x + y
console.log(add1(4, 7))
console.log(add1(4))
const add2 = (x=6,y) => x+y
console.log(add2())//相当于add(6, undefined)
console.log(add2(1))//相当于add(1, undefined)
console.log(add2(y=2,z=3)) // 相当于add2(2,3)
[out]:
9
11
9
NaN
NaN
5
1、JS中并没有Python中的关键字传参
2、JS只是做参数位置的对应
3、JS并不限制默认参数的位置
4.建议,默认参数写到后面,这是一个好的习惯。
可变参数(rest parameters剩余参数)
JS使用…表示可变参数(Python用*收集多个参数)
const sum = function (...args){
let result = 0
for (let x in args){
result += args[x]
}
return result
};
console.log(sum(3,6,9))
[out]:18
arguments对象
函数的所有参数会被保存在一个arguments的键值对对象中。
(function (p1, ...args) {
console.log(p1)
console.log(args)
console.log('----------------')
console.log(arguments) // 对象
for (let x of arguments) // 该对象可以使用of
console.log(x);
})('abc', 1,3,5)
[out]:
abc
[ 1, 3, 5 ]
----------------
[Arguments] { '0': 'abc', '1': 1, '2': 3, '3': 5 }
abc
1
3
5
参数解构
和Python类似,Js提供了参数解构,依然使用了…符号来解构。
const add = (x, y) => {console.log(x,y);return x + y};
console.log(add(...[100,200]))
console.log(add(...[100,200,300,3,5,3]))
console.log(add(...[100]))
[out]:
100 200
300
100 200
300
100 undefined
NaN
Js支持参数解构,不需要解构后的值个数和参数个数对应。
返回值
const add = (x, y) => {return x,y};
console.log(add(4,100)); // 返回什么?
[out]:100
表达式的值
类C的语言,都有一个概念——表达式的值
赋值表达式的值:等号右边的值。
逗号表达式的值:类C语言,都支持逗号表达式,逗号表达式的值,就是最后一个表达式的值。
a = (x = 5, y = 6, true);
console.log(a);
b = (123, true, z = 'test')
console.log(b)
function c() {
return x = 5, y = 6, true, 'ok';
}
console.log(c());
[out]:true
test
ok
所以,JS的函数返回值依然是单值
严格模式:使用"use strict";,这条语句放到函数的首行,或者js脚本首行