JavaScript基础知识:函数进阶(一)
JavaScript基础知识:函数进阶(三)
一、旧时var
1. var 与 let 的区别
1) 没有块级作用域 (不是函数作用域就是全局作用域)
2) 允许重新声明
3)可在声明前使用,例如:
function sayHi() {
phrase = "Hello";
alert(phrase);
var phrase;
}
sayHi();
人们将这种行为称为“提升”(英文为 “hoisting” 或 “raising”),因为所有的 var 都被“提升”到了函数的顶部。
声明会被提升,但是赋值不会。
2. IIFE
以前javascript只有 var 一种声明变量的方式,并且没有块级作用域,所以就发明了一种模仿块级作用域的方法,就是立即调用函数表达式(immediately-invoked function expressions,IIFE),看起来长这样:
(function() {
var message = "Hello";
alert(message); // Hello
})();
解释下这段代码发生的事:
创建函数表达式( function(){ … } ),并立即调用 (function(){ … } )();
当JavaScript 引擎在主代码中遇见 function 时,会把它当成一个函数声明的开始。但是函数声明需要函数名 ,而且Javascript又不允许立即调用函数声明,所以用圆括号将函数声明包起来,为了告诉Javascript,这个函数是在另一个上下文中创建的,因此是一个函数表达式:它不需要函数名,可以立即调用
// 创建 IIFE 的方法
(function() {
alert("Parentheses around the function");
})();
(function() {
alert("Parentheses around the whole thing");
}());
!function() {
alert("Bitwise NOT operator starts the expression");
}();
+function() {
alert("Unary plus starts the expression");
}();
二、全局对象
全局对象提供了可以在任何地方使用的变量和函数,默认情况下,这些全局变量内置于语言或环境中;
在浏览器中是 window , nodeJs中 是 global ;
最近,globalThis 被作为全局对象的标准名称加入到了 JavaScript 中,所有环境都应该支持该名称。所有主流浏览器都支持它。
1)全局对象的所有属性都可以直接访问,例如:
alert('123');
//等同于
window.alert('123');
2)使用 var 声明的全局变量或函数,会变为全局对象的属性
3)使用polyfills
使用全局对象来测试对现代语言功能的支持,例如,测试是否存在内建的 Promise 对象(在版本特别旧的浏览器中不存在):
if (!window.Promise) {
alert("Your browser is really old!");
//如果没有(使用的是旧版浏览器),那么我们可以创建 “polyfills”:添加环境不支持但在现代标准中存在的功能
window.Promise = ... // 定制实现现代语言功能
}
三、函数对象
函数 == 值 (值都有类型) == 对象 ==>> 可以当做对象操作:增/删属性,按引用传递
1. 属性
1) " name " 获取函数的名字
function sayHi(){
alert('Hi');
}
alert(sayHi.name); // sayHi
2) " length " 返回函数参数的个数(rest参数不参与计算)
3)自定义属性
需要明确的一件事:函数的属性 不等于 函数的变量, 举例: sayHi.count = 0 与 let count = 0 不是一个概念
函数属性 有时 可以代替闭包,如下:
function makeCounter() {
// 不需要这个了
// let count = 0
function counter() {
return counter.count++;
};
counter.count = 0;
return counter;
}
let counter = makeCounter();
alert( counter() ); // 0
alert( counter() ); // 1
四、new Function
1)语法:
let func = new Function ([arg1, arg2, ...argN], functionBody);
参数的声明方式也可以是以下三种:
new Function('a', 'b', 'return a + b'); // 基础语法
new Function('a,b', 'return a + b'); // 逗号分隔
new Function('a , b', 'return a + b'); // 逗号和空格分隔
2)使用 new Function 创建的函数,它的 [[Environment]] 指向全局词法环境,而不是函数所在的外部词法环境。因此,在 new Function 中不能直接使用外部变量。
五、调度:setTimeout 和 setInterval
-
有时
不想立即调用函数,有两种方法实现:
- setTimeout 允许将函数 推迟一段时间后执行;
- setInterval 允许我们以一段的时间间隔后 重复运行 函数
1. setTimeout
1)语法:
let timerFuc = setTimeout(fun|code, [delay], [arg1], [arg2], ...)
2)参数说明:
fun | code 想要执行的函数 或 字符串,( 常用:函数 );
delay 延迟执行的时间,以毫秒为单位 ( 1000ms = 1s );
arg1 传入被执行函数的参数,例如:
function sayHi(str, name){
alert(str +' , '+ name + '!');
}
setTimeout(sayHi, 1000, 'Hello', 'John'); //Hello , John!
3)注意点:
setTimeout 期望得到的是对函数的引用, 而不是执行函数,
所以 上面的例子中 sayHi 后面没有括号没有括号没有括号
4)取消调度 clearTimeout
setTimeout 在调用时会返回一个 定时器标示符, 在 js 中,它是一个数字, 在nodejs中是一个对象;
let timerId = setTimeout(sayHi, 1000, 'Hello', 'John');
clearTimeout(timerId);
2. setInterval
语法同 setTimeout 语法,但 setTimeout 仅执行一次,setInterval 是周期性执行, 想要停止调用的话,使用 clearInterval(timerId)
3. 两者用法
对于周期性执行有两种方式:一、嵌套setTimeout;二、使用setInerval
嵌套的 setTimeout 能够精确地设置两次执行之间的延时,而 setInterval 却不能。
案例实现:编写一个函数 printNumbers(from, to),使其每秒输出一个数字,数字从 from 开始,到 to 结束。
第一种:**setInterval ** 方法实现
function printNumbers(from, to){
let num = from;
let timerId = setInterval(function(){
num += 1;
console.log(num);
if(num == to){
clearInterval(timerId);
}
},1000)
}
printNumbers(2,10);
第二种:**setTimeout ** 方法实现
function printNumbers(from,to){
let num = from;
setTimeout(function decrease(){
num += 1;
console.log(num);
if(num < to){
setTimeout(decrease,1000);
}
},1000)
}
printNumbers(2,10);
以上内容参考于 https://zh.javascript.info ,在此学习记录。。。