作用域,上下文,闭包

作用域

作用域决定了你的代码里的变量和其他资源在各个区域中的可见性。

优点:

为代码提供了一个安全层级,用户只能访问他们当前需要的东西

提升性能,比如变量访问速度,跟踪 bug 并减少 bug

解决不同范围的同名变量命名问题

在 JavaScript 中有两种作用域:

全局作用域:定义在函数之外的变量会被保存在全局作用域中

局部作用域(函数作用域):当变量定义在一个函数中时,变量就在局部作用域中,每个函数在调用的时候会创建一个新的作用域。作用域是在函数被创建的时候就定义的

ECMAScript 6 引入了let和const关键字。这些关键字可以代替var。

let likes = 'Coding';
const skills = 'Javascript and PHP';

和var关键字不同,let和const关键字支持在块级声明中创建使用局部作用域

if (true) {
var name = 'Hammad';
let likes = 'Coding';、
const skills = 'JavaScript and PHP';
}
console.log(name); // logs 'Hammad'
console.log(likes); // Uncaught ReferenceError: likes is not defined
console.log(skills); // Uncaught ReferenceError: skills is not defined

一个应用中全局作用域的生存周期与该应用相同。局部作用域只在该函数调用执行期间存在

上下文

上下文指的是在相同的作用域中的this的值。可以使用函数方法改变上下文,执行的时候确定的

在全局作用域中,上下文总是 Window 对象。

作为一个对象的方法,上下文就是这个方法所在的那个对象。

使用new关键字调用函数时上下文,上下文会设置为被调用的函数的实例

当在严格模式(strict mode)中调用函数时,上下文默认是 undefined。查资料

js的运行过程

第一阶段是创建阶段,是函数刚被调用但代码并未执行的时候。创建阶段主要发生了 3 件事。

创建变量对象

创建作用域链

设置上下文(this)的值

第二个阶段就是代码执行阶段,进行其他赋值操作并且代码最终被执行。

词法作用域

词法作用域(静态作用域)的意思是在函数嵌套中,内层函数可以访问父级作用域的变量等资源,在定义时就确定。

闭包

当内部函数试着访问外部函数的作用域链(词法作用域之外的变量)时产生闭包。闭包包括它们自己的作用域链、父级作用域链和全局作用域。

闭包不仅能访问外部函数的变量,也能访问外部函数的参数。

即使函数已经return,闭包仍然能访问外部函数的变量。这意味着return的函数允许持续访问外部函数的所有资源

当你的外部函数return一个内部函数,调用外部函数时return的函数并不会被调用。你必须先用一个单独的变量保存外部函数的调用,然后将这个变量当做函数来调用。

用闭包实现共有作用域和私有作用域

(function () {
// private scope
})();

函数结尾的括号告诉解析器立即执行此函数。我们可以在其中加入变量和函数,外部无法访问。但如果我们想在外部访问它们,也就是说我们希望它们一部分是公开的,一部分是私有的。我们可以使用闭包的一种形式,称为模块模式(Module Pattern),它允许我们用一个对象中的公有作用域和私有作用域来划分函数。

模块模式

var Module = (function() {
function privateMethod() {
// do something
}
return {
publicMethod: function() {
// can call privateMethod();
}
};
})();
Module.publicMethod(); // works
Module.privateMethod(); // Uncaught ReferenceError: privateMethod is not defined

Module 的return语句包含了我们的公共函数。私有函数并没有被return。函数没有被return确保了它们在 Module 命名空间无法访问。但我们的共有函数可以访问我们的私有函数,方便它们使用有用的函数、AJAX 调用或其他东西。

一种习惯是以下划线作为开始命名私有函数,并返回包含共有函数的匿名对象。这使它们在很长的对象中很容易被管理。向下面这样:

var Module = (function () {
function _privateMethod() {
// do something
}
function publicMethod() {
// do something
}
return {
publicMethod: publicMethod,
}
})();

立即执行函数表达式(IIFE)

另一种形式的闭包是立即执行函数表达式(Immediately-Invoked Function Expression,IIFE)。这是一种在 window 上下文中自调用的匿名函数,也就是说this的值是window。它暴露了一个单一全局接口用来交互。如下所示:

(function(window) {
// do anything
})(this);

使用 .call(), .apply() 和 .bind() 改变上下文

Call 和 Apply 函数来改变函数调用时的上下文。
context={a:1,y:2}
function hello(a,b) {
alert(this.a);
alert(a);
alert(b);
}
hello();
hello.call(context,"cc","dd"); //1,cc,dd
hello.apply(context,["cc","dd"]); //

Bind 并不是自己调用函数,它只是在函数调用之前绑定上下文和其他参数。

(function introduce(name, interest) {
console.log('Hi! I'm '+ name +' and I like '+ interest +'.');
console.log('The value of this is '+ this +'.')
}).bind(window, 'Hammad', 'Cosmology')();

猜你喜欢

转载自www.cnblogs.com/yaoyao-sun/p/10365422.html