JavaScript学习记录1
发布时间 : 2019-10-12 00:13
阅读 :
1 背景 最近在学习JavaScript,今天学到了下面的内容,做个回顾吧。
作用域、作用域链精解、立即执行函数、闭包、闭包精细版
2 学习内容 2.1 作用域、作用域链精解基本概念
运行期上下文 当函数执行时,会创建一个称为执行期上下文的内部对象。一个执行期上下文定义了一个函数执行时的环境,函数每次执行时对应的执行上下文都是独一无二的,所以多次调用一个函数会导致创建多个执行上下文,当函数执行完毕,它所产生的执行上下文被销毁。
查找变量 从作用域链的顶端依次向下查找
[[scope]] 每个JavaScript函数都是一个对象,对象中有些属性我们可以访问,但有些不可以,这些属性仅供JavaScript引擎存取,[[scope]]就是其中一个。 [[scope]]指的就是我们所说的作用域,其中存储了运行期上下文的集合。
作用域链 [[scope]]中所存储的执行期上下文对象的集合,这个集合呈链式链接,我们把这种链式链接叫作用域链。
2.1.1 示例 1 2 3 4 5 6 7 8 9 function a() { function b() { var b = 234; } var a = 123; b(); } var glob = 100; a();
2.1.2 函数作用域链详解:
2.2 立即执行函数 2.2 功能: 此类函数没有声明,在一次执行过后即释放,适合做初始化工作。 实例如下
1 2 3 4 5 (function () { var a = 1; var b = 2; console.log(a + b); }())
1 2 3 (function (a , b , c) { console.log(a + b + c * 2); }(1 , 2 , 3))
1 2 3 4 5 var result = (function (a , b , c) { var d = a + b * 2 + c * a; return d }(1 , 2 , 3)) console.log(result);
两种常用写法
(function() {} () ); W3C建议使用第一种 (function() {} ) ();
阿里巴巴曾经的一个考试题
1 2 3 function test(a , b , c , d) { console.log( a + b + c + d); }(1 , 2 , 3 , 4);
上面的代码就相当于下面的代码,讲函数test()的声明与(1 , 2 , 3 , 4);分开执行,但不报错也不输出任何的东西
1 2 3 4 function test(a , b , c , d) { console.log( a + b + c + d); } (1 , 2 , 3 , 4);
2.3 闭包 2.3.1 基本概念 闭包:当函数内部被保存到外部时,将会生成闭包。闭包会导致原有作用域链不释放,造成内存泄漏。
1 2 3 4 5 6 7 8 9 10 11 12 13 function a() { function b() { var bb = 234; aa++; console.log(aa); } var aa = 123; return b; } var glob = 100; var demo = a(); demo(); demo();
代码执行期上下文过程
函数a返回的是b的引用
2.3.2 作用 2.3.2.1 实现共有变量(函数累加器) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function add() { var count = 123; function demo() { count++; console.log(count); } return demo; } var counter = add(); counter(); counter(); counter(); counter(); counter(); counter();
2.3.2.2 可以做缓存(存储结构) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function eater() { var food = ""; var obj = { eat : function () { console.log( "I am eating " + food); food = ""; }, push: function (myFood) { food = "myFood"; } } return obj; } var eater1 = eater(); eater1.push("banana"); eater1.eat();
2.3.2.3 可以实现封装,属性私有化 2.3.2.4 模块化开发,防止污染全局变量 2.3.3 详解 经典代码
1 2 3 4 5 6 7 8 9 10 11 12 13 function test() { var arr = []; for(var i = 0; i < 10; i++) { arr[i] = function () { document.write(i + " "); } } return arr; } var myArr = test(); for(var j = 0; j < 10; j++) { myArr[j](); }
代码执行结果
代码执行过程,test()函数中的arr[i] = function() {}执行时并不执行function中的代码,只是传了一个引用值给arr[i],等到真正执行的时候才会回来看function中的代码并执行 要解决上述矛盾,必须使用立即执行函数,代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function test() { var arr = []; for(var i = 0; i < 10; i++) { (function (j) { arr[j] = function () { document.write(j + " "); } }(i)); } return arr; } var myArr = test(); for(var j = 0; j < 10; j++) { myArr[j](); }
2.3.4 基本规律 只有表达式才能被执行
上面的代码称为函数声明,不是表达式,后面加()后会爆出低级语法错误
而下面的代码会正常执行,相当于var demo = function () {console.log(“hello”);}是一个表达式,运行完一次之后就不能再运行了,相当于立即执行函数
1 2 3 var demo = function () { console.log("hello"); }();
再函数声明前面加上 + - ! 后面加()都能将其变成函数表达式,也类似于立即执行函数,代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 + function test() { console.log("hello"); }(); - function test() { console.log("hello"); }(); ! function test() { console.log("hello"); }(); ![](https://img-blog.csdnimg.cn/2019092214481018.png)
阿里曾经一道笔试题 使用原生js,addEventListener,给每个li元素绑定一个click事件,输出它们的顺序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 <!doctype html> <html> <head> <meta charset="utf-8"> <title>demo</title> <style> *{ margin : 0; padding : 0; } ul { list-style: none; } li:nth-of-type(2n) { background-color : red; } li:nth-of-type(2n + 1) { background-color : green; } </style> </head> <body> <ul> <li>first</li> <li>second</li> <li>third</li> <li>forth</li> </ul> <script> function test() { var liCollection = document.getElementsByTagName('li'); for(var i = 0; i < liCollection.length; i++) { (function (j) { liCollection[j].onclick = function() { console.log(j); } }(i)) } } test(); </script> </body> </html>
2.3.5 扩展 写一个方法,求一个字符串的字节长度。(提示:字符串有一个方法charCodeAt() ,一个中文占两个字节,一个英文占一个字节)
定义和方法
charCodeAt()方法可返回指定位置字符的Unicode编码,这个返回值是0~65535之间的整数。(当返回值 <= 255时,为英文,当返回值 > 255时为中文)
语法
1 stringObject.charCodeAt(index)
eg:
1 2 3 4 <script> var str = "Hello, World!"; document.write(str.charCodeAt(1)); //输出101 </script>
代码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 function getBytesLen(str) { var count = 0; for(var i = 0; i < str.length; i ++) { if(str.charCodeAt(i) <= 255) { count ++; } else if(str.charCodeAt(i) > 255) { count += 2; } } console.log(count); } getBytesLen("Hello, World!我爱矿大");
简化代码
1 2 3 4 5 6 7 8 9 10 11 function getBytesLen(str) { var len = str.length; var count = len; for(var i = 0; i < len; i ++) { if(str.charCodeAt(i) > 255) { count ++; } } console.log(count); } getBytesLen("Hello, World!我爱矿大");
结果如下图
微店前端面试题
写出下面程序的执行结果(此题考查逗号运算符的结果,结果返回最后一个逗号后面的表达式的值)
1 2 3 4 5 6 7 8 9 var f = ( function f() { return "1"; }, function g() { return 2; } ()); console.log(typeof f);
1 2 3 4 5 var x = 1; if(function f() {}) { x += typeof f; } console.log(x);
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达,可以邮件至 xingshuaikun@163.com。