函数表达式和函数声明

变量/函数声明都会提前
console.log(a)
let a =1
那么打印出来的a为 undefined,因为会将a提到前面并赋予默认值undefined
函数声明:函数声明会将函数提到调用函数变量的前面
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的执行
 
同时strict模式下(use strict)让函数的this指向undefined,事实是无论是strict模式,this指向undefined或window,可以通过apply和call来控制this的指向的,完成this的绑定。
 
  • apply
它接收两个参数,第一个参数就是需要绑定的this变量,第二个参数是Array,表示函数本身的参数。
用apply修复getAge()调用

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
apply是通过将参数进行打包成数组Array的方式传入,call是通过将参数以顺序的方式传入Func

Math.max.apply(null, [3, 5, 4]); // 5
Math.max.call(null, 3, 5, 4); // 5

  

对于普通的函数this的指向一般设置为null
默认值
function test(x,y='world'){
console.log('');
}
  • bind
bind 通过函数变量的方式调用bind函数绑定this对象指向
const ageFunc=function getAge() { 
var y = new Date().getFullYear();
return y - this.birth;
}.bind({birth:20})
当我们调用时ageFunc()执行函数时,函数指向{birth:20}这个Object对象
 
  • 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对象

  

单独调用函数,比如getAge(),此时,该函数的this指向全局对象,也就是window

闭包

定义: 内部函数可以引用外部函数的参数和局部变量,当内部函数返回函数时,相关参数和变量都保存在返回的函数中,这种称为“闭包(Closure)”
 
  1. 通过返回一个函数然后延迟执行
  2. 如果里函数引用了外函数的某个变量,那这个变量就能享受和全局变量一样的特权,不会被回收!因为该变量一直被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]);
当去调用results()时才会去真正计算求和
私有变量
在面向对象语言中,一般在函数内部通过private定义私有变量,而在闭包中则通过内部函数携带状态返回。
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
在返回的对象中,实现了一个闭包,该闭包携带了局部变量count,并且,从外部代码根本无法访问到变量count。换句话说,闭包就是携带状态的函数,并且它的状态可以完全对外隐藏起来

注意

在闭包中,函数内部定义了数组的变量,当函数返回函数,内部的变量还被新的函数所引用,而是直到调用了f()才执行
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];
返回结果并非是我们想象的1,4,9
f1(); // 16 f2(); // 16 f3(); // 16
全部都是16!原因就在于返回的函数引用了变量i,但它并非立刻执行。等到3个函数都返回时,它们所引用的变量i已经变成了4,因此最终结果为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作用域和闭包的更多相关文章

  1. 浅谈JS中的闭包

    浅谈JS中的闭包 在介绍闭包之前,我先介绍点JS的基础知识,下面的基础知识会充分的帮助你理解闭包.那么接下来先看下变量的作用域. 变量的作用域 变量共有两种,一种为全局变量,一种为局部变量.那么全局变 ...

  2. 浅谈 js eval作用域

    原文:浅谈 js eval作用域 就简单聊下如何全局 eval 一个代码. var x = 1; (function () { eval('var x = 123;'); })(); console. ...

  3. 浅谈JS中 var let const 变量声明

    浅谈JS中 var let const 变量声明 用var来声明变量会出现的问题: 1. 允许重复的变量声明:导致数据被覆盖 2. 变量提升:怪异的数据访问.闭包问题 3. 全局变量挂载到全局对象:全 ...

  4. 浅谈JavaScript中的闭包

    浅谈JavaScript中的闭包 在JavaScript中,闭包是指这样一个函数:它有权访问另一个函数作用域中的变量. 创建一个闭包的常用的方式:在一个函数内部创建另一个函数. 比如: functio ...

  5. 浅谈 js 语句块与标签

    原文:浅谈 js 语句块与标签 语句块是什么?其实就是用 {} 包裹的一些js代码而已,当然语句块不能独立作用域.可以详细参见这里<MDN block> 也许很多人第一印象 {} 不是对象 ...

  6. 浅谈JS严格模式

    浅谈JS严格模式 简介 何为严格模式?严格模式(strict mode)即在严格的条件下运行,在严格模式下,很多正常情况下不会报错的问题语句,将会报错并阻止运行. 但是,严格模式可以显著提高代码的健壮 ...

  7. 浅谈JS之AJAX

    0x00:什么是Ajax? Ajax是Asynchronous Javascript And Xml 的缩写(异步javascript及xml),Ajax是使用javascript在浏览器后台操作HT ...

  8. 浅谈 js 正则字面量 与 new RegExp 执行效率

    原文:浅谈 js 正则字面量 与 new RegExp 执行效率 前几天谈了正则匹配 js 字符串的问题:<js 正则学习小记之匹配字符串> 和 <js 正则学习小记之匹配字符串优化 ...

  9. 浅谈 js 字符串之神奇的转义

    原文:浅谈 js 字符串之神奇的转义 字符串在js里是非常常用的,但是你真的了解它么?翻阅<MDN String>就可以了解它的常见用法了,开门见山的就让你了解了字符串是怎么回事. 'st ...

随机推荐

  1. 【javascript】javascript设计模式mixin模式

    概述: Mixin是JavaScript中用的最普遍的模式,几乎所有流行类库都会有Mixin的实现.任意一个对象的全部或部分属性拷贝到另一个对象上. 一 .混合对象 二 .混合类

  2. webapi 实体作为参数,自动序列化成xml的问题

    原文:http://bbs.csdn.net/topics/392038917 关注 Ray_Yang Ray_Yang 本版等级:   #6 得分:0回复于: 2016-10-27 21:30:51 ...

  3. 用Appium让Android功能自动化测试飞起来

    前言 做Android端功能自动化已有2年多的时间了,使用过的功能自动化框架有Robotium.Uiautomator.Appium.最近研究自动化case复用的方案,调研了Appium的自动化框架, ...

  4. Windows ->> Windows Server 2012打开管理添加“我的电脑”桌面图标途径

    Windows Server 2012打开管理添加“我的电脑”桌面图标途径 rundll32.exe shell32.dll,Control_RunDLL desk.cpl,,0

  5. leetcode Ch2-Dynamic Programming II

    一. Longest Valid Parentheses 方法一.一维DP class Solution { public: int longestValidParentheses(string s) ...

  6. [翻译] MagicPie

    MagicPie Powerful pie layer for creating your own pie view. PieLayer provide great animation with si ...

  7. C# 特性 System.ComponentModel 命名空间属性方法大全,System.ComponentModel 命名空间的特性

    目录: System.ComponentModel 特性命名空间与常用类 System.ComponentModel.DataAnnotations ComponentModel - Classes ...

  8. 3.5星|《刷屏:视频时代的风传法则》:YouTube热门视频回顾与分析

    刷屏:视频时代的疯传法则 作者2010年加入YouTube.本书是作者对YouTube上的热门视频的回顾与分析.第2-9章各讲一个类别的热门视频:恶搞.混音.网络歌曲.广告.现场目击.知识与科技.小众 ...

  9. December 06th 2016 Week 50th Tuesday

    Behind every beautiful thing, there is some kind of pain. 美丽背后,必有努力. No pains, no gains. But it seem ...

  10. December 21st 2016 Week 52nd Wednesday

    Keep conscience clear, then never fear. 问心无愧,永不畏惧. I find it is very difficult for me to keep consci ...