void()
仅仅是代表不返回任何值,但是括号内的表达式还是要运行,如
void(alert("Wornning!"))
- 用四个空格缩进而不是TAB,因为不同编辑器 TAB 键的解析不一样。
- 函数可以在声明之前调用:
myFunction(5);
function myFunction(y) {
return y * y;
}
使用表达式定义函数时无法提升。
var x = function (a, b) {return a * b};
var z = x(4, 3);
- 对于函数自调用,必须通过把函数表达式外面添加括号(来说明它是一个函数表达式)再调用,否则会报错,如下实例:
function () { document.write( "Hello! 我是自己调用的" );}();
// 报错:Uncaught SyntaxError: Unexpected token (
正确写法:
(function () { document.write( "Hello! 我是自己调用的" );})();
现在我们知道函数表达式后面紧跟 () 会自动调用,但是如果把函数表达式赋给一个变量则不需要添加括号也可以直接调用,下方的代码中,函数表达式的主体部分会执行,并且会返回一个字符串给 a:
var a = function () {
document.write("Hello! 我是自己调用的" + "<br />");
return '返回的东西';
}();
document.write(a);
- 箭头函数
// ES5
var x = function(x, y) {
return x * y;
}
// ES6
const x = (x, y) => x * y;
有的箭头函数都没有自己的 this。 不适合顶一个 对象的方法。
当我们使用箭头函数的时候,箭头函数会默认帮我们绑定外层 this 的值,所以在箭头函数中 this 的值和外层的 this 是一样的。
箭头函数是不能提升的,所以需要在使用之前定义。
使用 const 比使用 var 更安全,因为函数表达式始终是一个常量。
如果函数部分只是一个语句,则可以省略 return 关键字和大括号 {},这样做是一个比较好的习惯:
实例
const x = (x, y) => { return x * y };
注意:IE11 及更早 IE 版本不支持箭头函数。
- ES6 支持函数带有默认参数,就判断 undefined 和 || 的操作:
实例(ES6)
function myFunction(x, y = 10) {
// y is 10 if not passed or undefined
return x + y;
}
myFunction(0, 2) // 输出 2
myFunction(5); // 输出 15, y 参数的默认值
-
JavaScript 函数有个内置的对象 arguments 对象。
argument 对象包含了函数调用的参数数组。 -
函数内改变函数外的变量,函数外的变量并不会改变值。
-
计数器demo->函数闭包
var add = (function () {
var counter = 0;
return function () {return counter += 1;}
})();
注意: 为什么上面这段代码没有直接写的function add (){...}
而是把function
赋值给了变量add
呢?
我们通常会想当然的认为每次调用add()
都会重走一遍add()中的代码块, 但其实不然。
注意add
方法中的return
, 它return
的并不是1,2,3这样的数值,而是return
了一个方法,并且把这个方法赋值给了add
变量。
那么在这个function
自运行一遍之后,其实最后赋值给add
的是return counter += 1
这段代码。
所以后面每次调用add()
其实都是在调用return counter += 1
再结合文章之前所说的, 闭包会持有父方法的局部变量并且不会随父方法销毁而销毁, 所以这个counter
其实就是来自于第一次function
执行时创建的变量。
也可以分解成:
function outerFunction() {
var counter = 0;
function innerFunction(){
return counter += 1;
}
return innerFunction;
/*
注意 typeof innerFunction 是:function;而typeof innerFunction()是number;
*/
}
var add = outerFunction();
/*
调用 outerFunction()返回的是内部函数innerFucntion,那么调用几次add()将调用几次
内部函数inner Function,内部函数公用了counter,所以能够计数,所以说闭包就是将内部嵌套函数变成外部可调用的。
*/
add();
add();
add();
makeAdder 函数:
function makeAdder(x) {
return function(y) {
return x + y;
};
}
var add5 = makeAdder(5);
var add10 = makeAdder(10);
console.log(add5(2)); // 7
console.log(add10(2)); // 12
在这个示例中,我们定义了 makeAdder(x)
函数,它接受一个参数x
,并返回一个新的函数。返回的函数接受一个参数y
,并返回x+y
的值。
从本质上讲,makeAdder
是一个函数工厂 — 他创建了将指定的值和它的参数相加求和的函数。在上面的示例中,我们使用函数工厂创建了两个新函数 — 一个将其参数和 5 求和,另一个和 10 求和。
add5
和 add10
都是闭包。它们共享相同的函数定义,但是保存了不同的词法环境。在 add5
的环境中,x 为 5。而在add10
中,x 则为 10。
-
事件传递有两种方式:冒泡与捕获。
事件传递定义了元素事件触发的顺序。 如果你将<p>
元素插入到<div>
元素中,用户点击<p>
元素, 哪个元素的click
事件先被触发呢?
在 冒泡 中,内部元素的事件会先被触发,然后再触发外部元素,即:<p>
元素的点击事件先触发,然后会触发<div>
元素的点击事件。
在 捕获 中,外部元素的事件会先被触发,然后才会触发内部元素的事件,即:<div>
元素的点击事件先触发 ,然后再触发<p>
元素的点击事件。
addEventListener()
方法可以指定useCapture"
参数来设置传递类型:
addEventListener(event, function, useCapture);
默认值为false
, 即冒泡传递,当值为true
时, 事件使用捕获传递。 -
使用
addEventListener
的时候,又无法使用,是因为:
x = document.getElementById("myBt");
// x ---> null
可以这么写:
window.onload = function () {
var x = document.getElementById("myBt");
x.addEventListener("click", myFunction);
};
- IE 8 及更早 IE 版本,Opera 7.0及其更早版本不支持
addEventListener()
和removeEventListener()
方法。但是,对于这类浏览器版本可以使用detachEvent()
方法来移除事件句柄:
element.attachEvent(event, function);
element.detachEvent(event, function);
跨浏览器解决方法:
var x = document.getElementById("myBtn");
if (x.addEventListener) {
// 所有主流浏览器,除了 IE 8 及更早版本
x.addEventListener("click", myFunction);
} else if (x.attachEvent) {
// IE 8 及更早版本
x.attachEvent("onclick", myFunction);
}