最近,听到李笑来说,讲解编程的过程中,举例子很重要。
而且,我最近看的各种javaScript工具书中的例子,也都有点复杂。
所以啊,我试着举一些简单又直观的例子,与各位苦学javaScript的同学,一起共勉!
这些例子里面,我将变量名称、函数名称尽量写短,让大家的精力,主要投入到理解逻辑,理解和整理思路上来,不要为长长的变量名、函数名称所干扰。
先抛出一个问题:
this是什么?this表达了什么?为什么要有this?
统计学生成绩的小例子,
对象s(scores的缩写)存储了三位同学的考试成绩,通过函数t(total的缩写)获得总分数,
var s= { ma: 90, li: 80, zhao: 70 }function t(n){ return n.ma+ n.li + n.zhao;}console.log("学生总成绩:"+t(s));
对象s被当做函数t的形参x,显式的传入了该函数内.
运行结果:
使用node命令查看
不使用参数的情况下,怎么办?
想隐式的传递对象,怎么办?
我们使用函数的上下文,函数的上下文,是除了函数的参数之外的、最常用的,让外部信息隐式的进入函数内的一种手段。
将上面的代码改一下:
var s= { ma: 90, li: 80, zhao: 70, t: t } function t(){ return this.ma + this.li + this.zhao; } console.log("学生总成绩:"+s.t());
上面的代码,去掉了函数t的形参,添加了this,然后在s对象内添加了函数t。
总结:函数的this是什么,前提条件是要看如何调用,不是看它如何定义。
再举一个大家生活中常见的例子,
大家出门时,要带上手机、钥匙、钱包,为了记住这些出门必带的东东,有人编了段子“伸手钥钱”,
那么,在javaScript中,我用函数调用链,把3样东西串起来,
3样东东,分别用拼音首字母代替:手机 --> sj , 钥匙 --> ys , 钱包 --> qb 。
我们想要的结果是,只需带上手机(执行函数sj),就能把3个东东都带上。
实例1:出门三件事:手机、钥匙、钱包
function sj(){ 'use strict';//使用严格模式 console.log('手机'); this.ys();}function ys(){ console.log('钥匙'); this.qb();}function qb(){ console.log('钱包');}sj();
上面的例子,试图跨越边界,使用this来隐式的引用函数的词法作用域,能成功吗?
先看结果:
使用node命令查看
结果报错了,当然,我们使用了严格模式,在浏览器运行的结果:
使用浏览器查看
上面的例子中,我们试图通过this.ys()来引用ys()函数,在严格模式下是不能成功的。(偷偷告诉你,非严格模式下chrome浏览器运行不报错)
想拿钥匙?
调用ys()最自然的方法是省略前面的this,请直接使用词法引用标示符ys()
使用node命令和运行在浏览器的结果
通过这个例子使用this和不使用this的对比,我们知道了:
this在任何情况下都不指向函数的词法作用域。
我再补充一点调用位置的知识,
调用位置就是函数在代码中被调用的位置,不是声明的位置
调用栈——为了到达执行位置所调用的所有函数,
这两个小知识,还是通过上面那个例子来解释。
function sj(){//当前调用栈是sj(手机)//调用位置是全局作用域 console.log('手机'); ys();//ys(钥匙)的调用位置}function ys(){//当前调用栈是sj(手机)--> ys(钥匙)//当前调用位置在sj(手机)中 console.log('钥匙'); qb();//qb(钱包)的调用位置}function qb(){//当前调用栈是sj(手机)--> ys(钥匙)--> qb(钱包)//当前的调用位置在ys(钥匙)中 console.log('钱包');}sj();
理解了调用位置和调用栈,才能理解this的绑定过程。