文章目录
1. 作用域
作用域: function声明时的作用域,所以函数参数的取值范围为函数本身所在的作用域
var a = 1;
var x = function () {
console.log(a);
};
function f() {
var a = 2;
x();
}
f() // 1
2. 闭包
2.1 概念理解
衍生概念: 闭包 >> 定义在一个函数内部的函数:
- 当函数外部想要调用函数(f1)内部的局部变量,可以在函数内部定义一个子函数(f2),子函数可以使用父函数的局部变量,如果将子函数返回,就可以在外部使用局部变量 --链式作用域结构
- f2即为闭包
function f1() {
var n = 999;
function f2() {
console.log(n);
}
return f2;
}
var result = f1();
result(); // 999
2.2 状态保留
外部调用局部变量依赖于闭包,也就是闭包的诞生环境(函数),所以,外部调用结束之前函数会一直存在于内存里
函数调用的过程中,局部变量一直存在,且保留
function increment(start) {
//start局部变量
return function () {
return start++;// start += 1局部变量改变
};
}
var inc = increment(5);
inc() // 5
inc() // 6
inc() // 7
2.3 封装对象的私有属性和方法
function Person(name) {
var _age;
function setAge(n) {
_age = n;
}
function getAge() {
return _age;
}
return {
name: name,
getAge: getAge,
setAge: setAge
};
}
var p1 = Person('张三');
p1.setAge(25);
p1.getAge() // 25
2.4 缺点
外层函数的每次运行都会产生一个新的闭包,并且闭包中保存外层函数的内部变量,根据上文中提到的状态保留,内存消耗大,影响网页性能
3. 参数
多个参数: 传的参数少于参数列表个数时,忽略后面的参数;同名参数,取后者
function f(a, a) {
console.log(a);
}
f(1) // undefined
//同名参数取后者,因为只有一个参数,第二个参数被忽略,所以undefined
4. 函数提升
JS将函数名视为变量名function f(){}会被函数提升
var f = function () {
console.log('1');
}
function f() {
console.log('2');
}
f() // 1 ;后者函数提升,后声明函数覆盖先声明的同名函数,所以结果为1
赋值逻辑不会被提升
console.log(a);
console.log(b);
var a;
var b = 1;
undefined // a被变量提升
undefined // b被变量提升,但是赋值不会被提升
f();
var f = function (){};
// TypeError: undefined is not a function;赋值不被提升
5. 立即调用函数表达式(IIFE)
Immediately-Invoked Function Expression
在 JavaScript 中,圆括号()
是一种运算符,跟在函数名之后,表示调用该函数。比如,print()
就表示调用print
函数。
// 语句
function f() {}
// 表达式
var f = function f() {}
- JavaScript 引擎规定,如果
function
关键字出现在行首,一律解释成语句 - 不让
function
出现在行首,则解释为表达式
(function(){ /* code */ }());
// 或者
(function(){ /* code */ })();
通常情况下,只对匿名函数使用这种“立即执行的函数表达式”。它的目的有两个:一是不必为函数命名,避免了污染全局变量;二是 IIFE 内部形成了一个单独的作用域,可以封装一些外部无法读取的私有变量。
6. eval命令
eval 以独立存在有意义的字符串为参数,并执行,否则报错
eval的作用域为当前作用域,所以会造成变量污染; 严格模式下eval内部声明的变量不会影响外部作用域,但依然可以访问外部作用域的变量.依然会有安全风险
(function f() {
'use strict';//使用严格模式
eval('var foo = 123');
console.log(foo); // ReferenceError: foo is not defined
})()
(function f() {
'use strict';
var foo = 1;
eval('foo = 2');
console.log(foo); // 2
})()
eval的参数如果不是字符串,则原样返回
eval(123);//123
eval的别名调用作用域为全局作用域,即使在函数内部,依然为全局作用域
6.1 应用场景
从服务器动态获取代码来执行;可能会有被攻击者通过eval代码注入导致风险
感谢补充与修改建议
参考链接:
函数提升
eval不是魔鬼
Javascript教程
JS严格模式