浅谈JS作用域和闭包
函数表达式和函数声明
console.log(a)
let a =1
fn('里斯')//不会报错
function fn(name) {
console.log();
}
fn1();//会保错,因为fn1为undefeated
const fn1=function fn(name) {
console.log();
}
执行上下文(变量提升)
- 范围:一段<script> 或者一个函数
- 全局:变量定义、函数声明 一段<script>
- 函数:变量定义、函数声明、this、arguments
this
- this需要在执行时才能确认值,定义时无法确认
- this作为普通函数执行,指向的是window
- this作为对象执行,指向的是调用者对象
- this作为构造函数执行,指向的是构造函数对象
- call apply bind
作用域
- 无块级作用域
if(true) {
const name='zhangsan'
}
console.log(name);// 'zhangsan'
- 全局作用域和函数作用域
const a=12;// 全局变量,全局都可以访问,该变量容易被污染
function() {
const b =32; // 函数作用域 函数内部可以访问
console.log(a); /// a变量在函数中没有定义,那么该变量称之为自由变量
console.log(b);
}
- 指向函数对象与函数调用
var xiaoming = {
name: '小明',
birth: 1990,
age: function () {
var y = new Date().getFullYear();
return y - this.birth;
} };
xiaoming.age; // 只是一个Func对象
xiaoming.age(); // Func的执行
- apply
function getAge() {
var y = new Date().getFullYear();
return y - this.birth;
}
var user= {
name: '小明',
birth: 1990,
age: getAge
};
user.age(); //
getAge.apply(user, []); // 25, this指向user, 参数为空
- call
Math.max.apply(null, [3, 5, 4]); // 5
Math.max.call(null, 3, 5, 4); // 5
function test(x,y='world'){
console.log('');
}
- bind
const ageFunc=function getAge() {
var y = new Date().getFullYear();
return y - this.birth;
}.bind({birth:20})
- rest参数
function foo(a, b, ...rest) {
console.log('a = ' + a);
console.log('b = ' + b);
console.log(rest);//3,4,5
}
foo(1, 2, 3, 4, 5);
- This对象的绑定
function getAge() {
var y = new Date().getFullYear();
return y - this.birth;
}
var user= {
name: '小明',
birth: 1990,
age: getAge
};
xiaoming.age(); // 当通过user对象去调用指向age,那么getAge Func中的this对象指向的是调用者,即词法作用域
getAge(); // 如果直接getAge()执行,那么相当this属于window对象
闭包
- 通过返回一个函数然后延迟执行
- 如果里函数引用了外函数的某个变量,那这个变量就能享受和全局变量一样的特权,不会被回收!因为该变量一直被Child函数一直访问着。同时享受全局变量不会被销毁的特权的闭包变量多到一定数量了,那内存就要撑爆了,一旦超过了计算机能接受的内存阀值,就会导致内存泄漏
函数作为返回值
函数作为参数传递
返回函数是根据作用域链一层一层往上找,找到即可,不是执行时生效,而是定义时生效
- 函数作为返回值
function F() {
let a = 10
return function() {
console.log(a) // 自由变量 父级作用域中寻找
}
}
let a =23 let f = new F() f() // 10
- 函数作为参数传递
function F() {
let a = 10
return function() {
console.log(a) // 自由变量 父级作用域中寻找
}
}
function F1(fn) {
let a = 120
fn()
}
let f = new F()
let f1 = new F1(f)
f1() // 10
特性
懒执行
function lazy_sum(arr) {
var sum = function () {
return arr.reduce(function (x, y) {
return x + y;
});
}
return sum;
}
var results=lazy_sum([1,2,3,4,5]);
私有变量
function rememberCount(initial ) {
var count = initial || 0;
return {
inc: function() {
count = count + 1;
return count;
}
}
}
var rc=rememberCount();
rc.inc(); //1
rc.inc(); //2
rc.inc(); //3
注意
function count() {
var arr = [];
for (var i=1; i<=3; i++) {
arr.push(function () {
return i * i;
});
}
return arr;
}
var results = count();
var f1 = results[0];
var f2 = results[1];
var f3 = results[2];
f1(); // 16 f2(); // 16 f3(); // 16
(function (x) {
return x * x;
})(3); // 9
function (x) { return x * x } (3);// 语法会解析错误
(function (x) { return x * x }) (3);
function count() {
var arr = [];
for (var i=1; i<=3; i++) { //创建了3个function对象,保护了i变量的污染
arr.push((function (n) {
return function () {
return n * n;
}
})(i));
}
return arr;
}
var results = count();
var f1 = results[0];
var f2 = results[1];
var f3 = results[2];
f1(); // 1
f2(); // 4
f3(); // 9
实际开发中的闭包应用
- 用于封装变量,收敛权限
function isHasWatchList(){
const _list =[];
return function (id) {
if(_list.indexOf(id) >= 0){
return false;
} else {
_list.push(id);
return true;
}
}
}
// 使用
const hasWatchList = new isHasWatchList();
hasWatchList('10') // true
hasWatchList('10') // false
hasWatchList('10') // false
浅谈JS作用域和闭包的更多相关文章
- 浅谈JS中的闭包
浅谈JS中的闭包 在介绍闭包之前,我先介绍点JS的基础知识,下面的基础知识会充分的帮助你理解闭包.那么接下来先看下变量的作用域. 变量的作用域 变量共有两种,一种为全局变量,一种为局部变量.那么全局变 ...
- 浅谈 js eval作用域
原文:浅谈 js eval作用域 就简单聊下如何全局 eval 一个代码. var x = 1; (function () { eval('var x = 123;'); })(); console. ...
- 浅谈JS中 var let const 变量声明
浅谈JS中 var let const 变量声明 用var来声明变量会出现的问题: 1. 允许重复的变量声明:导致数据被覆盖 2. 变量提升:怪异的数据访问.闭包问题 3. 全局变量挂载到全局对象:全 ...
- 浅谈JavaScript中的闭包
浅谈JavaScript中的闭包 在JavaScript中,闭包是指这样一个函数:它有权访问另一个函数作用域中的变量. 创建一个闭包的常用的方式:在一个函数内部创建另一个函数. 比如: functio ...
- 浅谈 js 语句块与标签
原文:浅谈 js 语句块与标签 语句块是什么?其实就是用 {} 包裹的一些js代码而已,当然语句块不能独立作用域.可以详细参见这里<MDN block> 也许很多人第一印象 {} 不是对象 ...
- 浅谈JS严格模式
浅谈JS严格模式 简介 何为严格模式?严格模式(strict mode)即在严格的条件下运行,在严格模式下,很多正常情况下不会报错的问题语句,将会报错并阻止运行. 但是,严格模式可以显著提高代码的健壮 ...
- 浅谈JS之AJAX
0x00:什么是Ajax? Ajax是Asynchronous Javascript And Xml 的缩写(异步javascript及xml),Ajax是使用javascript在浏览器后台操作HT ...
- 浅谈 js 正则字面量 与 new RegExp 执行效率
原文:浅谈 js 正则字面量 与 new RegExp 执行效率 前几天谈了正则匹配 js 字符串的问题:<js 正则学习小记之匹配字符串> 和 <js 正则学习小记之匹配字符串优化 ...
- 浅谈 js 字符串之神奇的转义
原文:浅谈 js 字符串之神奇的转义 字符串在js里是非常常用的,但是你真的了解它么?翻阅<MDN String>就可以了解它的常见用法了,开门见山的就让你了解了字符串是怎么回事. 'st ...
随机推荐
- Java中int与Integer的区别
转自https://www.cnblogs.com/guodongdidi/p/6953217.html import java.lang.Integer; public class intDemo{ ...
- 护航SMB网络安全 应选择新一代防火墙
当前,各种规模的企业都遭遇着日益增多的网络攻击,而其中以中小企业(SMB)为代表的广大群体则更加面临敏感数据.公司资产和知识产权不断暴露在风险中的窘境.为了帮助企业应对这一挑战,新一代防火墙的采购与部 ...
- MUI框架-03-自定义MUI控件样式
MUI框架-03-自定义MUI控件样式 开发请查阅:官方文档:http://dev.dcloud.net.cn/mui/ui/ 如何自定义MUI控件样式 mui 以 iOS 7的 UI 为基础,补充了 ...
- Android 线程池的类型、区别以及为何要用线程池
每个 Android 应用进程在创建时,会同时创建一个线程,我们称之为主线程,负责更新 UI 界面以及和处理用户之间的交互,因此,在 Android 中,我们又称之为 UI 线程.一个进程中 UI 线 ...
- Linux-文件目录命令
黑色 代表是普通的文件 蓝色 代表是目录(文件夹) 紫色 代表是图片文件 绿色 代表是可以执行的文件(脚本文件)-->存放linux命令的 红色 代表是压缩文件 clear:清屏pwd:显示当前 ...
- Java Web开发中的转发和重定向的问题
Java Web的页面实现跳转有两种方式,一种是转发,另外一种是重定向.一般来说,转发比重定向快.重定向会经过客户端,转发却不会. 转发 request.getRequestDispatcher(&q ...
- Docker-commit镜像提交
docker commit:提交容器副本使之成为一个新的镜像 docker commit -a="作者名" -m="提交的描述信息" 容器id 新建的镜像名称: ...
- 数组list操作,切片
a=range(10) a[11:0:-1] #倒序输出 a[0:9:2] #输出2,4,6,8 a[-3:] #输出7,8,9 a.append(11) #追加一个元素 a.count(11) #统 ...
- CocoaPods -- ios项目中安装和使用CocoaPods
CocoaPods是什么? 当你开发iOS应用时,会经常使用到很多第三方开源类库,比如JSONKit,AFNetWorking等等.可能某个类库又用到其他类库,所以要使用它,必须得另外下载其他类库,而 ...
- codeforces 17C Balance(动态规划)
codeforces 17C Balance 题意 给定一个串,字符集{'a', 'b', 'c'},操作是:选定相邻的两个字符,把其中一个变成另一个.可以做0次或者多次,问最后可以生成多少种,使得任 ...