普通函数
function foo(a, b){
return a + b;
}
foo(10, 20)
>>> 30
匿名函数
var f = function(){console.log(123)};
f()
>>> 123
自执行函数
(function(a,b){return a + b})(10, 20)
>>> 30
内置函数forEach
传一个参数:
var a1 = [11, 22, 33, 44, 55];
a1.forEach(function(i){
console.log(i);
})
>>> 11
22
33
44
55
传两个参数:
var a1 = [11, 22, 33, 44, 55];
a1.forEach(function(k, inde){
console.log(k, inde);
})
>>> 11 0
22 1
33 2
44 3
55 4
分析:第二个参数为其value在数组中所对应的索引值
传三个参数:
var a1 = [11, 22, 33, 44, 55];
a1.forEach(function(k, inde, z){
console.log(k, inde, z);
})
>>> 11 0 (5) [11, 22, 33, 44, 55]
22 1 (5) [11, 22, 33, 44, 55]
33 2 (5) [11, 22, 33, 44, 55]
44 3 (5) [11, 22, 33, 44, 55]
55 4 (5) [11, 22, 33, 44, 55]
分析:第三个参数为迭代的数组
内置函数.map()
1 var a1 = [11, 22, 33, 44, 55]; 2 a1.map(function(i){ 3 return i + 1 4 }) 5 6 >>> (5) [12, 23, 34, 45, 56]
解析:将a1数组中的各个元素分别加1,最终以数组的形式返回结果.
当不给函数传值时,函数返回NaN.
1 function foo(a, b){ 2 return a + b; 3 } 4 foo() 5 6 >>> NaN
分析: foo函数需要两个函数,函数调用时没有给传参数,结果返回NaN.
当函数返回值为多个时,最终返回的结果为最后一个.
1 function bar(a, b){ 2 return 10, 20, 30; 3 } 4 var x = bar(); 5 x 6 7 >>> 30
例外一种情况:
1 function bar(a, b){ 2 return 10, 20, 30; 3 } 4 var x, b = bar() 5 x 6 7 >>> 30 8 9 b 10 11 >>> 30 12 13 x, b 14 15 >>> 30
当函数传入值的个数多余接收参数的数量时,多余的参数将不会被使用.
1 function foo(a, b){ 2 return a + b 3 } 4 foo(10, 20, 300) 5 6 >>> 30
实现简单加法器:
function mySum(a, b){
var ret = 0;
for (var i=0; i < arguments.length; i++){
ret += arguments[i];
}
return ret;
}
mySum(10, 20) // 传入两个值
>>> 30
mySum(10, 20, 30) // 传入三个值
>>> 60
mySum(10) // 传入一个值
>>> 10
mySum() // 不穿值时输出0
>>> 0
箭头函数
var a1 = [11, 22, 33, 44, 55];
a1.forEach((i)=>{
console.log(i);
})
>>> 11
22
33
44
55
箭头函数是匿名函数的简写,箭头函数的this是固定的.
变量加在顺序:
function f1(){
var x1 = 100;
}
x1
>>> Uncaught ReferenceError: x1 is not defined
at <anonymous>:1:1
在全局中无法调用局部变量.
var x2 = 200;
function f2(){
console.log(x2);
}
f2()
>>> 200
在局部作用域中可以调用全局变量.
var x2 = 200;
function f2(){
x2 += 1;
}
x2
>>> 200 // 打印x2直接调用x2,此时函数f2还没有执行,调用的是全局变量x2=200.
f2()
x2
>>> 201 // 在执行函数f2之后,x2增加1,然后调用x2,此时全局变量中的x2值为201.
作用域:
首先在函数内部查找变量,找不到则到外层函数查找,逐步找到最外层。
例1:
var city = 'BeiJing';
function f() {
var city = 'ShangHai';
function inner(){
var city = 'ShenZhen';
console.log(city);
}
inner();
}
f();
>>> ShenZhen
函数从上往下执行,city的值为'BeiJing',当执行到f()时,开始执行f()的函数体,执行完成之后,此时的city的值为'ShangHai',函数再往下执行,当执行到inner()时,开始执行inner的函数体,此时的city的值为'ShenZhen',然后执行打印,此时console的作用域中有city并且其值为'ShenZhen',所以打印结果为'ShenZhen'。
例2:
var city = 'BeiJing';
function Bar() {
console.log(city);
}
function f() {
var city = 'ShangHai';
return Bar;
}
var ret = f();
ret();
>>> BeiJing
函数由上至下开始执行,此时city的值为'BeiJing',然后执行ret(),此时的ret为f(),执行f函数的函数体,此时city的值为'ShangHai',返回Bar,此时的ret()为Bar(),执行Bar函数的函数体,打印city,但是函数Bar的作用域中没有city变量,然后去外层作用域即全局作用域中查找,全局作用域中city的值为'BeiJing',所以打印结果为'BeiJing'.
例3:闭包
var city = 'BeiJing';
function f() {
var city = 'ShangHai';
function inner() {
console.log(city);
}
return inner;
}
var ret = f();
ret();
>>> ShangHai
函数由上至下开始执行,,此时city的值为'BeiJing',执行ret(),此时的ret为f函数,开始执行f的函数体,此时的city的值为'ShangHai',返回inner,此时的ret为inner函数,接着执行inner的函数体,打印city,但是inner的局部作用域中没有city,就像外层作用域查找,外层作用域的city的值为'ShangHai',所以打印结果为ShangHai.
语法分析:
JavaScript中在调用函数的那一瞬间,会先进行词法分析.
词法分析的过程:
当函数调用的前一瞬间,会先形成一个激活对象:Active Object(AO),并会分析一下3个方面:
1. 函数参数,如果有,则将此参数赋值给AO,且值为undefined.如果没有,则不做任何操作.
2. 函数局部变量,如果AO上有同名的值,则不做任何操作.如果没有,则将此变量赋值给AO,并且值为undefined.
3. 函数声明,如果AO上有,则会将AO上的对象覆盖.如果没有,则不做任何操作.
函数内部无论是使用参数还是使用局部变量都到AO是上找.
例1:
var age = 18;
function foo(){
console.log(age);
var age = 22;
console.log(age);
function age() {
console.log('呵呵');
}
console.log(age);
}
foo();
>>> ƒ age() {
console.log('呵呵');
}
>>> 22
>>> 22
内置对象和方法
JavaScript中所有的事务都是对象: 字符串、数字、数组、日期、等等。在JavaScript中对象是拥有属性和方法的数据。
区分s1 = 'yingying'和s2 = new String('yingying')的区别:
var s1 = 'yingying';
var s2 = new String('yingying');
s1
>>> "yingying"
s2
>>> String {"yingying"}
s2.length
>>> 8
typeof s1
>>> "string"
typeof s2
>>> "object"
s2. slice(2, 5)
>>> "ngy"
玩儿法二:
var o1 = {'a': 100, 'b': 200};
o1.length
>>> undefined
对象不能使用length属性计算长度.
var o1 = {'a': 100, 'b': 200};
for(var i in o1){
console.log(i);
}
>>> a
b
循环对象(相当于python中的字典)时打印的是对象(相当于python中的字典)的key.
var o1 = {'a': 100, 'b': 200}; // 创建对象的方式
o1['a']
>>> 100
o1.a
>>> 100
o1['a']相当于o1.a.
var o2 = new Object(); // 创建对象的另外一种方式;
o2.name = 'yingying';
>>> "yingying"
o2
>>> {name: "yingying"}
创建一个对象:
var Person = function(dream){
this.dream = dream;
};
var p1 = new Person('咸鱼翻身');
p1
>>> Person {dream: "咸鱼翻身"}
p1.dream
>>> "咸鱼翻身"
Person.prototype.makeDream = function(){
console.log('在做白日 梦!');
}
>>> ƒ (){
console.log('在做白日 梦!');
}
var p2 = new Person('鲤鱼打挺');
p2.dream
>>> "鲤鱼打挺"
p2.makeDream
>>> ƒ (){
console.log('在做白日 梦!');
}
var Yellow = function(dream){
Person.call(this, dream);
}
Yellow.prototype = Object.create(Person.prototype)
Yellow.prototype.constructor = Yellow;
Yellow.prototype.sing = function(){
console.log('龙的传人');
}
var p3 = new Yellow('没有蛀牙!')
p3.dream
>>> "没有蛀牙!"
p3.makeDream()
>>> 在做白日 梦!
p3.sing()
>>> 龙的传人
Date对象
方法一: 不指定参数
var d1 = new Date();
console.log(d1.toLocaleString());
>>> 2018/9/5 下午6:10:12
方法二:参数日期字符串
var d2 = new Date("2004/3/20 11:12");
console.log(d2.toLocaleString());
var d3 = new Date("04/03/20 11:12");
console.log(d3.toLocaleString());
>>> 2004/3/20 上午11:12:00
2020/4/3 上午11:12:00
方法三:参数为毫秒数
var d3 = new Date(5000);
console.log(d3.toLocaleString());
console.log(d3.toUTCString());
>>> 1970/1/1 上午8:00:05
Thu, 01 Jan 1970 00:00:05 GMT
方法四:参数为年月日小时分钟秒毫秒
var d4 = new Date(2004,2,20,11,12,0,300);
console.log(d4.toLocaleString()); //毫秒并不直接显示
>>> 2004/3/20 上午11:12:00
Date对象的方法:
var d = new Date();
d
>>> Wed Sep 05 2018 18:47:41 GMT+0800 (中国标准时间)
d.getDate() // 获取日
>>> 5
d.getDay() // 获取星期
>>> 3
d.getMonth() // 获取月(0-11)(获取的月加1为当前月份)
>>> 8
d.getFullYear() // 获取完整年份
>>> 2018
d.getYear() // 获取年份
>>> 118
d.getHours() // 获取小时
>>> 18
d.getMinutes() // 获取分钟
>>> 47
d.getMilliseconds() // 获取毫秒
>>> 272
d.getTime() // 获取时间戳
>>> 1536144461272
将当前时间格式化为指定格式:
function timeFormat(){
var weekDict = {
1: '星期一',
2: '星期二',
3: '星期三',
4: '星期四',
5: '星期五',
6: '星期六',
7: '星期日',
};
var d = new Date();
var y = d.getFullYear().toString();
var m = d.getMonth().toString();
var D = d.getDate().toString();
var h = d.getHours().toString();
var M = d.getMinutes().toString();
var w = d.getDay();
var week = weekDict[w];
var ret = y.concat('-', m, '-', D, ' ', h, ':', M, ' ', week);
console.log(ret);
}
timeFormat()
>>> 2018-8-5 19:56 星期三 // 示例时间
序列化:
var o1 = {'name': 'yingying', 'age': 20};
o1
>>> {name: "yingying", age: 20}
var s1 = JSON.stringify(o1); // 序列化
s1
>>> "{"name":"yingying","age":20}"
JSON.parse(s1) // 反序列化
>>> {name: "yingying", age: 20}
正则
验证手机号的合法性:
var r1 = new RegExp('^1[3-9]\\d{9}$'); // \d的\需要转译
r1.test('18812342234')
>>> true
var r1 = new RegExp('^1[3-9][0-9]{9}$');
r1.test('18812342234')
>>> true
另一种创建正则的方式:
/^1[3-9][0-9]{9}$/.test('18812342234')
>>> true
/^1[3-9]\d{9}$/.test('18812342234') // 在这种创建方式相加不需要转译
>>> true
JS正则大坑:
坑一:
var r3 = new RegExp('^[a-zA-Z][a-zA-Z0-9]{5,11}$')
r3.test('yingying')
>>> true
r3.test() // 没有输入则按照undefined去匹配;
>>> true
r3.test(undefined) // 将undefined按照字符串'undefined'去匹配;
>>> true
r3.test('undefined')
>>> true
坑二:
正则表达式中不能有空格,否则将会出现异常.
var s1 = 'ying Ying';
s1.replace('i', '哈哈')
>>> "y哈哈ng Ying"
s1.replace(/i/, '哈哈')
>>> "y哈哈ng Ying"
s1.replace(/y/i, '哈哈')
>>> "哈哈ing Ying"
s1.replace(/y/gi, '哈哈')
>>> "哈哈ing 哈哈ing"
i表示忽略大小写的匹配模式
g表示全局匹配模式
出现这种情况的原因是在匹配过程中,当匹配成功是,系统会保留一个指针,当下次匹配时从指针的位置开始匹配,直到结束位置.当到结束位置还未匹配成功就返回False,下次再从起始位置开始.
var r5 = /alex/g;
r5.test('alex')
>>> true
r5.test('alex')
>>> false
r5.test('alex')
>>> true
r5.lastIndex
>>> 0
r5.test('alex')
>>> true
r5.lastIndex
>>> 4
r5.test('alex')
>>> false
r5.lastIndex
>>> 0
正则表达式加上g就会记录一个lastInedx属性用来记录下次从哪里开始匹配.
随机数
Math.random() // 产生0到1之间的随机数
>>> 0.0640924093253199
取最大值
Math.max(10, 20, 30)
>>> 30
round
Math.round(6.5)
>>> 7
开平方
Math.sqrt(0.1)
>>> 0.31622776601683794