函数
不能在条件语句中声明函数
name属性返回紧跟在function关键字之后的那个函数名。
length属性返回函数定义中参数的个数。
函数的toString方法返回函数的源码。
如果函数A调用函数B,函数B不会引用函数A的内部变量。
var x = function (){
console.log(a);
};
function y(f){
var a = 2;
f();
}
y(x)
// ReferenceError: a is not defined
//函数x是在函数y体外声明的,作用域绑定外层,因此找不到函数y的内部变量a,导致报错。
函数体执行到return就返回结果,如果没有return,也会返回,返回值为undefined
调用函数:
调用函数传入的参数可以比定义的少,没有传入的为undefined;
调用函数传入的参数也可以比定义函数的参数多,多出的参数不影响;
arguments指向调用函数传入的参数,类似数组但不是数组
rest参数:rest参数是ES6新标准
function(a,b,...rest) {
console.log(a);
console.log(b);
console.log(...rest);
}
rest参数接收多出的全部参数,为一个数组
如果传入的参数比定义的参数多,多出的参数存入数组rest[];
如果传入的参数比定义的少或者刚好和定义的一样多,则rest为一个空数组,不是undefined;
rest参数只能写在最后,前面用...标识;
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
// [ 3, 4, 5 ]
foo(1);
// 结果:
// a = 1
// b = undefined
// []
变量作用域
声明在函数中的变量只在该函数内有效:如果一个变量在函数体内部申明,则该变量的作用域为整个函数体,在函数体外不可引用该变量;
不同函数内部的同名变量互相独立,互不影响;
定义在一个函数内部的函数,内部函数可以使用外部函数的变量,外部函数不可以使用内部函数的变量;
变量提升:提升变量的声明到函数的顶部,变量的赋值位置不变;
全局变量:不在函数内声明的变量是全局变量,JavaScript有一个全局对象window,可以以window的属性的方式调用全局变量;顶层函数也可以作为window的方法调用:
var x = 1;
function a() {
console.log("a function");
}
alert(window.x);//1;
alert(x);//1
window.a();//console.log("a funciton");
a();//console.log("a funciton");
可以通过将一个函数赋值给一个变量保存这个函数:
var oldalert = window.alert;//把原来的alert保存在变量oldalert中
window.alert= function() { console.log("a new alert") };//改变了alert函数的用处
alert();//此时执行alert()方法,已经不再弹窗了,可以看到控制台的输出信息
oldalert("the old alert");//因为原来的alert被保存起来了,可以通过oldalert调用原来的方法
window.alert=oldalert;//恢复原来的alert方法
alert("recorver");//原来的alert恢复了
命名空间:
不同JavaScript文件定义的同名全局变量会造成冲突
解决方法:
只命名一个唯一的全局变量,其他的变量作为该全局变量的属性,函数作为该全局变量的方法;
局部作用域:
局部变量的作用域只在声明该变量的函数中
对于for循环内声明的变量,是没有块级作用域的;
一个函数内的for循环内声明的变量,作用域还是这一整个函数
ES6引入了let声明一个变量,有块级作用域
ES6引入了const声明一个常量,有块级作用域,如果试图改变该常量的值,不会报错但是无效
ES6之前不能声明一个常量,通常用变量名大写来表示他是一个常量但是却是可以被修改的(不是真的常量)
this:
var xiaoming = {
name: '小明',
birth: 1990,
age: function () {
function getAgeFromBirth() {
var y = new Date().getFullYear();
return y - this.birth;
}
return getAgeFromBirth();//返回值是一个函数的执行结果
}
};
xiaoming.age(); //调用xiaoming.age方法,返回值是执行一个getAgeFromBirth函数,因为是返回这个函数再调用,所以调用的对象是window,即getAgeFromBirth方法的this指向window(非严格模式下),window.birth是未定义undefined,严格模式下this指向undefined,所以undefined.birth报错
解决方法:
1var that=this;//在一开始将this赋给一个变量,在后面需要this的地方使用这个变量,以保证this的正确指向
2 apply和call:指明this的指向:函数.apply(参数一,参数二);//函数是需要改变其this指向的函数,参数一是this的指向、某个对象,参数二是函数本身所需的参数
函数.call(参数一,参数二);//参数同上,唯一的区别是,apply()把参数打包成Array再传入;call()把参数按顺序传入。
高阶函数:接受一个函数作为它的参数
数组的map方法:arr.map(fn):对数组arr的每一个元素遍历传入函数fn执行,返回一个新的数组
数组的reduce方法:arr.reduce(fn):对数组一个元素执行fn函数,把结果继续和序列的下一个元素做累积计算
function fn(x,y) {
return x*y;
}
var arr=[1,2,3,4];
arr.reduce(fn);//做连乘,相当于f(f(f(1,2),3),4);
数组的filter方法:arr.filter(fn):遍历数组元素,根据fn的返回值如果为真,保留该元素,返回值为假,滤除该元素;返回一个新的数组,不修改原来数组
filter的回调函数fn可以有三个参数element元素本身, index元素索引, self数组本身
数组的sort方法:排序规则比较复杂,sort是一个高阶函数,可以通过给sort传一个自定义的比较函数作为参数,让数组按照我们的规则排序
//从小到大排序
var arr = [10, 20, 1, 2];
arr.sort(function (x, y) {
if (x < y) {
return -1;
}
if (x > y) {
return 1;
}
return 0;
}); // [1, 2, 10, 20]
//从大到小排序
var arr = [10, 20, 1, 2];
arr.sort(function (x, y) {
if (x < y) {
return 1;
}
if (x > y) {
return -1;
}
return 0;
}); // [20, 10, 2, 1]
闭包
函数的返回值是一个函数
在一个函数内部定义一个函数,并将这个内部函数作为外部函数的结果返回,当调用外部函数时,返回的是他的内部函数,需要再次调用这个内部函数执行
function outerfn(o) {
var x = o;
function innerfn() {
return x*x;
}
return innerfn;
}
var inc = outerfn(3);
//var inc ;
//inc=outerfn(3);执行了一次外部函数,x=o=3;返回了一个函数innerfn();这个函数可以使用外部函数的变量,并且记住了他的值
inc();//调用了这个内部函数,返回9
每次调用外部函数都会返回一个新的函数,即使传入相同的参数;
相关参数和变量都保存在返回的函数中,这种程序结构称为“闭包(Closure)”
function count() {
var arr = [];
for (var i=1; i<=3; i++) {
arr.push(function () {
return i * i;
});//把三个函数放在数组arr中
}
return arr;//将数组返回,数组元素是三个相同的函数,因为这个函数没有执行,所以i还是i,仍然是一个引用的变量
}
var results = count();//返回一个数组,数组中有三个相同的函数,i的值变成4
var f1 = results[0];//把数组中的第一个函数赋给f1
var f2 = results[1];//把数组中的第一个函数赋给f2
var f3 = results[2];//把数组中的第一个函数赋给f3
//其实三个函数都是一样的,引用了同一个变量i,这个i已经变成了4
f1();//16,执行这个匿名函数
f2();//16,执行这个匿名函数
f3();//16,执行这个匿名函数
匿名函数的立即执行:
(function (n) {
console.log(n);
})(3);
function count() {
var arr = [];
for (var i=1; i<=3; i++) {
arr.push((function (n) {
return function () {
return n * n;
}
})(i));//每次都立即执行这个外部的匿名函数,将对应的i值传给n,n是一个局部变量,只在它自己那个匿名函数中有作用
}
return arr;//返回一个数组,数组中有三个匿名函数,这三个匿名函数分别引用他们各自的局部变量n,分别是1,2,3
}
var results = count();
var f1 = results[0];
var f2 = results[1];
var f3 = results[2];
f1(); // 1
f2(); // 4
f3(); // 9
闭包就是携带状态的函数,并且它的状态可以完全对外隐藏起来。
JavaScript的类型:
number,string,Boolean,object,undefined,function;
123,NaN是number
“haha” 是string
true,false 是boolean
undefined是undefined
Math.abs();是function
[],null和{}是object
用typeof不可以区分出object,null和array
包装对象:
var s = new String('123');//typeof(s):object
var n = new Number(123);//typeof(n):object
var b = new Boolean(true);//typeof(b):object
包装对象将原始值的类型转换成了object
new Number(123)===123//false
不使用new时,
var s = String('123');//typeof(s):string
var n = Number(123);//typeof(n):number
var b = Boolean(true);//typeof(b):boolean
几条规则:
用parseInt()或parseFloat()来转换任意类型到number;
用String()来转换任意类型到string,或者直接调用某个对象的toString()方法;
typeof操作符可以判断出number、boolean、string、function和undefined;
判断Array要使用Array.isArray(arr);
判断null请使用myVar === null;
判断某个全局变量是否存在用typeof window.myVar === 'undefined';
函数内部判断某个变量是否存在用typeof myVar === 'undefined'。
instanceof:
var o = {};
var a = [];
o instanceof Array;//false
a instanceof Array;//true
JSON
JSON实际上是JavaScript的一个子集。
json中的数据类型:
number:和JavaScript的number完全一致;
boolean:就是JavaScript的true或false;
string:就是JavaScript的string;
null:就是JavaScript的null;
array:就是JavaScript的Array表示方式——[];
object:就是JavaScript的{ ... }表示方式。
JSON还定死了字符集必须是UTF-8,表示多语言就没有问题了。为了统一解析,JSON的字符串规定必须用双引号"",Object的键也必须用双引号""。
JavaScript对象转为json数据格式:
JSON.stringify(参数一,参数二,参数三);
参数一:要转化的对象
参数二:要输出的属性,可以是一个数组,可以省略,也可以是一个函数,对键值对进行处理后返回
参数三:分隔符,可以省略
var xiaoming = {
name: '小明',
age: 14,
gender: true,
height: 1.65,
grade: null,
'middle-school': '"W3C" Middle School',
skills: ['JavaScript', 'Java', 'Python', 'Lisp'],
};
JSON.stringify(xiaoming,['name', 'skills'], ' ');
//结果:
"{
"name": "小明",
"skills": [
"JavaScript",
"Java",
"Python",
"Lisp"
]
}"
可以给xiaoming定义一个toJSON()的方法,直接返回JSON应该序列化的数据:
var xiaoming = {
name: '小明',
age: 14,
gender: true,
height: 1.65,
grade: null,
'middle-school': '"W3C" Middle School',
skills: ['JavaScript', 'Java', 'Python', 'Lisp'],
toJSON: function () {
return { // 只输出name和age,并且改变了key:
'Name': this.name,
'Age': this.age
};
}
};
JSON.stringify(xiaoming); // '{"Name":"小明","Age":14}'
json格式转JavaScript对象:
JSON.parse(object,[function]);
object是要转化的json,function是可选的一个转换函数