在C#中我们都基本上不讲作用域,因为一切都是自然而然的(用语言描述反而有些困难)。但JavaScript的作用域,让人非常头大!
如果一个变量在函数体内部(用var)声明,则该变量的作用域为整个函数体,在函数体外不可引用该变量。(另见:let)
不同函数内部的同名变量互相独立,互不影响。
这样被声明的变量被称之为:局部变量。
function scope() { var sname = '李志博'; console.log('in function:' + sname); } scope(); console.log('out function:' + sname);另外,注意不要晕:
猜一猜这段代码的执行结果:
function blockScope() { if (true) { var i = 986; } console.log('i=' + i); } blockScope();
@想一想@:为什么?有哪里不对劲么?
不在任何函数内定义的变量具有全局作用域,被称之为全局变量。
演示:
如果script只是在HTML页面中使用,全局变量还可以接受(而且比较方便);
但随着JavaScript规模扩大,一个项目可能引用多个(第三方/其他人写的)类库(js文件),各个文件间的名称冲突就越来越难以避免,给开发/维护带来极大的问题!这就被称之为“全局变量污染”。
实际上,var定义的:
演示:
window.alert = function (message){ console.log(message); }
@猜一猜@:再次调用alert()会什么情况?
或者你无意中声明了一个window已有的同名函数:
function alert(message) { console.log(message); }同时一个HTML页面因为.js文件引用,包含了别人的代码,想一想会出现什么情况?
而且一般来说,这些改动页面刷新之后就会“消失”
然而,我发现了一个例外:window.name。演示:name不会因为页面刷新而改变……
观察以下代码:
var sname = "飞哥"; function smart() { alert(`${sname}最帅`); } function reallySmart() { var sname = '子祥'; smart(); //局部变量sname有更高优先级 console.log(sname); } reallySmart(); //假如var声明在后面 //var sname = "飞哥";
reallySmart()调用smart(),smart()中需要sname但又没有声明sname,怎么办?
由var声明的变量的作用范围,其作用域由是由其源代码的书写位置,(而不是在哪里执行)决定的。
所谓词法(lexical),指的是:词法作用域根据源代码中声明变量的位置来确定该变量在何处可用。
//var age = 100; function outFunc(sname) { var age = 0; function innerFunc() { alert(age); //age定义在innerFunc()之外 } innerFunc(); //var age = 0; }
这样就形成了一个作用域链:JavaScript会沿着这个链条由内向外查找,直到undefined。
@想一想@:如何剪切/粘贴第一个函数,才能显示:子祥最帅?
体会:JavaScript在处理大型项目,进行工程化开发方面先天不足!由此诞生了很多“奇巧淫技”,以及不断进化的ES标准。
但你以为这样就结束了?too young too simple啊!作为一个“先天严重不足,后天各种补丁”的语言,这一切才刚刚开始……
使用“模拟名称空间”技术,构建一个函数函数yz.fei.get(number);
setInterval(console.log(`源栈欢迎你`)`, 100);这里面实际上是用到了JavaScript的eval()函数:(仅做了解!)
eval('alert(`atai帅呆了`);'); //eval()可以将字符串当做源代码执行
我们前面学习过对象可以存储数据(属性),其实对象中也可以存储函数(在对象中声明的函数通常被称之为方法method)
var wpz = { name: '王胖子', study: function () { alert('好好学习天天向上'); } }; wpz.study(); //用对象调用方法
复习:变量提升
以命名方式声明的函数也可以提升。(演示:略)
那么,赋值给变量的匿名函数呢?
演示:
@想一想@:为什么?
@想一想@:能不能在sum()函数内部获得未声明的参数(6)?
所以,JavaScript额外赠送一个arguments:
这就会方便很多,比如:sum()函数现在就可以接收任意多个的参数:
function sum() { var sum = 0; for (var i = 0; i < arguments.length; i++) { sum += arguments[i]; } return sum; }
通过arguments下标,我们也可以确定参数位置,给中间的参数赋默认值等……
之前我们学习过用花括号({})可以生成生成一个匿名 对象。
匿名类对象,就是一个没有类名的对象。
JavaScript号称是一个“面向对象”的语言,还是提供了很多内置类型的。
演示:native code
之前我们学过的所有基本(primitive)类型,都有对应的类的:String / Number / Boolean / Array(数组),注意他们的首字母大写。
var n = new Number(123);
我们就能得到一个相应的对象。得到的对象一样可以按基本类型变量使用:
new Number(123) -23 //100
但是,他们属于
new Number(123) == 123 //true new Number(123) === 123 //false,因为 typeof new Number(123) //Object
复习:typeof 123 结果是什么?
@猜一猜@:这样的代码结果是什么?
Number(888) + 98 //注意Number()前面没有new
这是因为在JavaScript中没有真正的“类”的定义,类就是函数,函数也可以是类。(后文详述)
所以你可能会觉得有无new都无所谓。但是:
Boolean('false') //true new Boolean('false') //false
找谁说理去?!
以上这些包装函数,知道就行,不建议在开发中使用。
将每天/课的作业用不同的js文件分隔:
多快好省!前端后端,线上线下,名师精讲
更多了解 加: