前言

javascript中没有块级作用域(es6以前),javascript中作用域分为函数作用域和全局作用域。并且,大家可以认为全局作用域其实就是Window函数的函数作用域,我们编写的js代码,都存放在Window函数内(这是个假设),也就是说javascript中只有函数作用域(前面假设做前提下)。

作用域是什么

作用域是一个盒子,盒子内部的变量只能在当前盒子中使用,作用域盒子是可以嵌套的,内部盒子的变量对父级盒子是不可见的,因为盒子封闭了他们并且盒子不透明,但是盒子可以看到父级盒子内部定义的变量,因为内部这个盒子与父级的变量同处一个空间,他们是互相看得到的。就像css中的盒模型一样。

以上这个图分为3层作用域,全局作用域、foo函数作用域、bar函数作用域,我们可以清晰的看到三层作用域各自的范围。

this是什么

我们经常用到this,this是代表着什么?this是代表着当前方法执行的环境上下文,那么何为环境上下文,通俗的说,谁调用了函数,谁就是这个函数的环境上下文。例如:

function run () {
console.log(this)
} var o = {
run: run
} run() // window对象
o.run // o对象

在上述代码中,run是一个函数,首先执行run()返回了window对象,为什么呢?我们已经讲过,var定义的变量会默认挂在到window对象中去,那么function定义的函数呢,也会默认挂在到window对象中去,其实我们在执行一个函数如:run() 跟window.run()是一样的,所以,window调用了run,因此函数的this是window。

注意:this的绑定是产生在函数调用时,并非在函数定义时

var o = {
color: 'red',
getColor: function () {
console.log(this.color)
}
} var color = 'blue' var getColor = o.getColor o.getColor // red
getColor // blue

上述代码,我们将o.getColor方法赋值给了一个变量getColor,然后我们分别执行了两个方法,缺得到了不同的结果,对于o.getColor并没有什么疑问,但是初学者可能认为getColor返回的也应该是red,但事实是blue,这就说明了,this是产生在函数调用时,因为在o.getColor赋值语句,就相当于一下语句

var getColor = function () {
console.log(this.color)
}

o.getColor返回的是这个函数,并没有绑定this,也就是说getColor其实是被赋值了一个函数,仅此而已,this是在调用时绑定的,所以得到了那样的结果。

不要被模样给蒙蔽

看下面代码:

var o = {
run : function () {
setTimeout(function () {
console.log(this)
}, 1000)
}
}
o.run() // window对象

以上运行了o.run方法,隔一秒输出this,输出了window对象,初学者可能会疑问,o.run调用时明明是在o对象下啊,this应该是o对象啊!不错,有这个疑问说明对this有一定了解了,但是上面案例是在setTimeout方法中的回调函数中输出的this,此回调函数执行时,是以fn()方式执行的(涉及到异步回调),前面说过直接执行函数相当于window.fn,因此输出了window对象。

拓展回调:

回调是进行异步操作常用的功能,上面示例中,我们可以假设为setTimeout是这样定义的

function setTimeout (fun) {
fun()
} setTimeout (function () {
console.log(this)
})

可以看出,fun是直接调用的,输出的this必定是window对象。

暴力绑定this

有时候,我们需要强制某个函数中的this为某一对象,我们这时候需要暴力的绑定this,这里,暴力的方法有3个: call、apply、bind。下面通过一个简单的demo来看一下他们的用法。

var color = 'blue'

var o = {
color: 'red',
say: function (animal, beautiful) {
console.log(this.color + '颜色的' + animal + (beautiful ? '好看': '不好看'))
}
} var say= o.say say('猫', false) // blue颜色的猫不好看
say.call(o, '猫', true) // red颜色的猫好看
say.apply(o, ['猫', true]) // red颜色的猫好看
say.bind(o)('猫', true) // red颜色的猫好看
o.say.call(null, '猫', false) // blue颜色的猫不好看

我们这次将o函数加一个say方法,say方法接收两个参数,第一个是动物,第二个是布尔值代表好不好看,我们还是将o.say赋值给变量say。

say('猫', false) 如期返回了blue颜色

say.call(o, '猫', true),say.apply(o, ['猫', true]),say.bind(o)('猫', true) 这三个都返回了red,可见我们都暴力的绑定了this为o对象。

call和apply的第一个参数都是接收要绑定的对象,也就是告诉引擎:'我要让say方法在o对象的环境下运行,你给我帮顶一下',引擎回答:‘包在我身上’,然后我们就绑定成功了,接下来我们需要传递参数到方法中去,call方法是在第二个参数之后,按顺序的传递参数 到方法中去,apply方法不同,apply方法是在第二个参数以数组的方式将参数传递到方法中去。而bind方法是es5中的方法,用途就在于绑定this指向然后返回已绑定好了的函数,因此,以上三个都输出了red

同样o.say绑定到null或者undefined,引擎会自动绑定到全局对象window下面。

进阶:函数的执行过程

本着菜鸟的思路,努力讲述一下简单的函数执行背后的历程,有错误请指正。

function fn (a, b) {
var c = 2;
function f () {...}
} var o = {} fn.call(o,1,'ok')

函数fn执行,会首先产生一个函数活动对象,这个活动对象对外是不可见的,该示例中,call方法先绑定了此次调用的this指向o,fn函数活动对象通过参数之间的赋值形成arguments对象,然后进行了函数内部的初始化变量,最后执行函数内部的赋值过程。过程如下:

function fn (a = 1, b = 'ok') {
var c
var f
//活动对象初始化完毕,进行函数体内的其他操作,这根变量提升和函数声明提升有关
c = 2
f = function () {...}
}

总结

总而言之,函数是javascript中最主要的结构,this是javascript甚至每一门高级语言中都需要的动态绑定的指针。能力一般,水平有限,如有错误,轻喷轻骂。

javascript中的this与函数讲解的更多相关文章

  1. avascript中的this与函数讲解

    徐某某 一个半路出家的野生程序员 javascript中的this与函数讲解 前言 javascript中没有块级作用域(es6以前),javascript中作用域分为函数作用域和全局作用域.并且,大 ...

  2. [转]Javascript中的自执行函数表达式

    [转]Javascript中的自执行函数表达式 本文转载自:http://www.ghugo.com/javascript-auto-run-function/ 以下是正文: Posted on 20 ...

  3. 深入理解javascript中的立即执行函数(function(){…})()

    投稿:junjie 字体:[增加 减小] 类型:转载 时间:2014-06-12 我要评论 这篇文章主要介绍了深入理解javascript中的立即执行函数,立即执行函数也叫立即调用函数,通常它的写法是 ...

  4. 使用Ajax在javascript中调用后台C#函数

    使用Ajax在javascript中调用后台C#函数 最近一段时间在紧跟一个网站的项目,数据库中用户表的UserName要求是唯一的,所以当用户选定一个用户名进行注册时要首先检查该用户名是否已被占用, ...

  5. 在javascript中关于变量与函数的提升

    在javascript中关于变量与函数的提升 一.简介 在javascript中声明变量与函数的执行步骤: 1.先预解析变量或函数声明代码,会把用var声明的变量或者函数声明的代码块进行提升操作 2. ...

  6. javascript中的立即执行函数(function(){…})()

    javascript中的立即执行函数(function(){…})() 深入理解javascript中的立即执行函数,立即执行函数也叫立即调用函数,通常它的写法是用(function(){…})()包 ...

  7. 深入理解javascript中的立即执行函数

    这篇文章主要介绍了深入理解javascript中的立即执行函数,立即执行函数也叫立即调用函数,通常它的写法是用(function(){…})()包住业务代码,使用jquery时比较常见,需要的朋友可以 ...

  8. JavaScript中的内置函数

    JavaScript中的内置函数 制作人:全心全意 在使用JavaScript语言时,除了可以自定义函数之外,还可以使用JavaScript的内置函数,这些内置函数是由JavaScript语言自身提供 ...

  9. JavaScript 中对变量和函数声明提前的演示样例

    如题所看到的,看以下的演示样例(能够使用Chrome浏览器,然后F12/或者右键,审查元素.调出开发人员工具,进入控制台console输入)(使用技巧: 控制台输入时Shift+Enter能够中途代码 ...

随机推荐

  1. WaitType:CXPACKET

    CXPACKET 等待类型是SQL Server 并发执行一个query时产生的.在run一个big query时,SQL Server充分利用系统的所有资源(CPU,Memory,IO),在最短时间 ...

  2. OC-封装

    一.      set方法和get方法 1.          set方法和get方法的使用场合 @public的成员可以被随意赋值,应该使用set方法和get方法来管理成员的访问(类似机场的安检.水 ...

  3. 洛谷P1211 [USACO1.3]牛式 Prime Cryptarithm

    P1211 [USACO1.3]牛式 Prime Cryptarithm 187通过 234提交 题目提供者该用户不存在 标签USACO 难度普及- 提交  讨论  题解 最新讨论 题面错误 题目描述 ...

  4. win下 golang 跨平台编译

    mac 下编译其他平台的执行文件方式请参看这篇文章,http://www.cnblogs.com/ghj1976/archive/2013/04/19/3030703.html  本篇文章是win下的 ...

  5. 在TFS2013上删除项目

    TFSDeleteProject 会永久性损坏团队项目,之后无法恢复该项目. 您应该在使用 TFSDeleteProject 之前备份所有重要的项目数据. 若要使用 TFSDeleteProject  ...

  6. 捕获Java线程池执行任务抛出的异常

    捕获Java线程池执行任务抛出的异常Java中线程执行的任务接口java.lang.Runnable 要求不抛出Checked异常, public interface Runnable { publi ...

  7. C++的三大特性之一继承

    一.继承的相关基本概念 1.继承的定义     在C++中,可以使用继承来使新类得到已定义的一些类中的特性,这就好比与孩子从父亲母亲得到遗传类似,所以我们称原有的类为基类或父类,用原有类来生成新的类的 ...

  8. [c#美味] Guid ToString 格式知多少?

    在日常编程中,Guid是比较常用的,最常见的使用就是如下所示: string id = Guid.NewGuid().ToString(); 这条语句会生成一个新的Guid并转成字符串,如下: // ...

  9. JS截取字符串:slice(),substring()和substr()

    var string='abcdefg' 1.slice() string.slice(startLocation [, endLocation]) ps1:2个参数可以为负数,若参数值为负数,则将该 ...

  10. Ora中select某时间段记录sql语句

    要查找某时间段的记录,例如查找2013-11-1到2013-11-30的记录. ' group by user_name, user_id 注意:SQL语句中含有sum累加函数,末尾要加group b ...