一.函数
JS函数有个很大的坑,就是调用时参数可以和定义时不一致,这真是。。。
并且每个函数执行到return语句时会返回,如果没有写return,默认返回undefined
有2种典型的定义函数的方式:
1>.
function abs(x) {
if (x >= 0) {
return x;
} else {
return -x;
}
}
2>.
var abs = function (x) {
if (x >= 0) {
return x;
} else {
return -x;
}
};
这种方式abs可以视为指向该函数的变量,因为中JS函数也是一个对象。可以理解为将匿名函数赋给变量abs;
调用函数:我们可以用typeof关键字对参数类型进行检查,类似于java的instanceof
function abs(x) {
if (typeof x !== 'number') {
throw 'Not a number';
}
if (x >= 0) {
return x;
} else {
return -x;
}
}
二.arguments关键字
arguments只在函数内部起作用,并且永远指向当前函数的调用者传入的所有参数。arguments类似Array但它不是一个Array,这意味着我们不定义任何参数也是可以拿到参数的
'use strict'
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);
function abs() {
if (arguments.length === 0) {
return 0;
}
var x = arguments[0];
return x >= 0 ? x : -x;
}
abs(); // 0
abs(10); // 10
abs(-9); // 9
arguments的常见用法是用来判断参数个数,如下:
// foo(a[, b], c)
// 接收2~3个参数,b是可选参数,如果只传2个参数,b默认为null:
function foo(a, b, c) {
if (arguments.length === 2) {
// 实际拿到的参数是a和b,c为undefined
c = b; // 把b赋给c
b = null; // b变为默认值
}
// ...
}
三.rest参数,(ES6)新增:rest参数只能参数额写在最后,前面用...标识,从运行结果可知,传入的参数先绑定a、b,多余的参数以数组形式交给变量rest,所以,不再需要arguments我们就获取了全部参数。
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 ]
foo(1);
// 结果:
// a = 1
// b = undefined
// Array []
四.变量的作用范围与解构赋值
代码说话,我觉得一看就懂:
1>
'use strict';
function foo() {
var x = 1;
x = x + 1;
}
x = x + 2; // ReferenceError! 无法在函数体外引用变量x
2>
function foo() {
var x = 1;
x = x + 1;//2
}
function bar() {
var x = 'A';
x = x + 'B';//AB
}
3>
function foo() {
var x = 1;
function bar() {
var y = x + 1; // bar可以访问foo的变量x!
}
var z = y + 1; // ReferenceError! foo不可以访问bar的变量y!
}
变量提升:
'use strict';
function foo() {
var x = 'Hello, ' + y;
console.log(x); //Hello, undefined
var y = 'Bob';
}
foo();
因此,在函数内部定义的我们可以理解为局部变量,不在任何函数内定义的变量就具有全局作用域,JavaScript默认有一个全局对象window,全局作用域的变量实际上被绑定到window的一个属性:course和访问window.course是一样的
我们可以这么写:
// 定义唯一的全局变量MYAPP:
var MYAPP = {};
// 定义其他变量:
MYAPP.name = 'myapp';
MYAPP.version = 1.0;
// 定义其他函数:
MYAPP.foo = function () {
return 'foo';
};
局部作用域:
这是普通的方式,
'use strict';
function foo() {
for (var i=0; i<100; i++) {
//
}
i += 100; // 仍然可以引用变量i
}
ES6中新增了一个关键字:let,用let替代var可以申明一个块级作用域的变量:
'use strict';
function foo() {
var sum = 0;
for (let i=0; i<100; i++) {
sum += i;
}
console.log(i += 1); // SyntaxError:
}
ES6中新增了一个关键字const, 来声明常量:
'use strict';
const PI = 3.14;
PI = 3; // 某些浏览器不报错,但是无效果!
PI; // 3.14
ES6还引入了解构赋值,可以同时对一组变量进行赋值:
'use strict';
// 如果浏览器支持解构赋值就不会报错:
var [x, y, z] = ['hello', 'JavaScript', 'ES6'];
// x, y, z分别被赋值为数组对应元素:
console.log('x = ' + x + ', y = ' + y + ', z = ' + z);
以及嵌套的解构赋值:
let [x, [y, z]] = ['hello', ['JavaScript', 'ES6']];
x; // 'hello'
y; // 'JavaScript'
z; // 'ES6'
ES6中的解构赋值还可以忽略某些元素:
let [, , z] = ['hello', 'JavaScript', 'ES6']; // 忽略前两个元素,只对z赋值第三个元素
z; // 'ES6'
对于对象也可以结构赋值:
'use strict';
var person = {
name: '小明',
age: 20,
gender: 'male',
passport: 'G-12345678',
school: 'No.4 middle school'
};
var {name, age, passport} = person;
// name, age, passport分别被赋值为对应属性:
console.log('name = ' + name + ', age = ' + age + ', passport = ' + passport);
还可以设置默认值:
var person = {
name: '小明',
age: 20,
gender: 'male',
passport: 'G-12345678'
};
// 如果person对象没有single属性,默认赋值为true:
var {name, single=true} = person;
name; // '小明'
single; // true
解构赋值典型应用场景:
1.交换2个数的值:
var x=1, y=2;
[x, y] = [y, x]
2.获取当前页面的域名和路径:
var {hostname:domain, pathname:path} = location;
五.对象的方法,例子如下:
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了
2.在一个方法内部,this是一个特殊变量,它始终指向当前对象,也就是xiaoming这个变量。所以,this.birth可以拿到xiaoming的birth属性。(象java中的this)
var xiaoming = {
name: '小明',
birth: 1990,
age: getAge
};
function getAge() {
var y = new Date().getFullYear();
return y - this.birth;
}
xiaoming.age(); // 25, 正常结果
getAge(); // NaN
but,如果以对象的方法形式调用,比如xiaoming.age(),该函数的this指向被调用的对象,也就是xiaoming,这是符合我们预期的。
如果单独调用函数,比如getAge(),此时,该函数的this指向全局对象,也就是window。
所以说,弱类型语言还是很坑爹~
因此我们一般调用对象的方法必须用obj.xxx()的形式!
我们的结论是,this,在非strict模式下,如果在函数定义的外部,它指向全局对象window;在strict模式下,如果在函数定义的外部,它指向undefined;
六:高阶函数:
JS的函数其实都指向某个变量。既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。
'use strict';
function add(x, y, f) {
return f(x) + f(y);
}
var x = add(-5, 6, Math.abs); // 11
console.log(x);
sort()函数是一个高阶函数,他的运用如下:
'use strict';
var arr = [10, 20, 1, 2];
arr.sort(function (x, y) {
if (x < y) {
return -1;
}
if (x > y) {
return 1;
}
return 0;
});
console.log(arr); // [1, 2, 10, 20]
七.JS的闭包:跳过。。。(暂时不想看)
八.箭头函数(ES6新增):跳过,估计现在遇不到
九.generator(生成器)(ES6新增)引入的新的数据类型:跳过,估计现在遇不到
十.JS中的包装对象:类似java中int 和 Integer 的关系
var n = new Number(123); // 123,生成了新的包装类型
var b = new Boolean(true); // true,生成了新的包装类型
var s = new String('str'); // 'str',生成了新的包装类型
上面三个变量已经成了object。
总结两点:
1.没事别用什么new String(),new Number()这些骚操作。。。老老实实用变量直接赋值=.=
2.用parseInt()或parseFloat()来转换任意类型到number;
先到这里。。。=.=