JS进阶第一课【this,严格模式,闭包】
一、this
解析器在每次调用函数的时候都会向函数内部传递一个隐含的参数,即this
1、普通函数:指向window
2、对象方法:指向该对象
3、构造函数:指向实例对象(原型对象里面的方法也是指向实例)
<script> // 普通函数 var test = function(){ console.log("this",this); } test();//window // 对象方法 var obj ={ say:test } obj.say();//obj // 构造函数 function Person(){ this.create = test } var p1 = new Person() p1.create();//Person </script>
4、事件绑定:绑定事件的对象
<ul> <li>1</li> <li>2</li> <li>3</li> </ul> <script> // 事件 var list = document.querySelectorAll('li'); for(var i = 0;i<list.length;i++){ list[i].onclick = function(){ console.log("this",this);//li } } </script>
5、定时器:指向window
<script> // 定时器 setTimeout(function(){ console.log("this",this);//window }) </script>
6、立即执行函数:指向window
<script> // 立即执行函数 (function(){ console.log("this",this);//window })() </script>
JavaScript会提供一些函数方法来帮助我们更优雅地处理函数内部this指向问题,常用的有:call()、apply()、bind()
二、call()
1、格式
调用函数名().call(指向谁,参数1,参数2...)
2、作用
(1)可以直接调用函数
(2)可以改变函数this指向
<script> var x=10; var y=20; var count = { x:1, y:2, } function total(a){ console.log("this",this); console.log(a); console.log(this.x+this.y); } total(100); total.call(count,100); </script>
(3)可以实现继承(构造函数)
<script> function Father(uname){ console.log("Father",this); this.userName = uname; } function Son(uname){ console.log("Son",this); Father.call(this,uname); } var p1 = new Son('张三'); console.log(p1); </script>
三、apply()
1、格式
调用函数().apply(thisArg,[arhsArray])
(1)thisArg:在函数运行时的this指向
(2)arhsArray:要传递的值(必须包含在数组里面)
(3)返回值就是函数(函数的返回值),因为是在调用函数
2、作用
(1)与call()相同,可以直接调用函数,可以改变函数this指向
(2)参数必须是数组
<script> var x=10; var y=20; var count ={ x:1, y:2, } function total(a,b){ console.log("this",this); console.log(a,b); console.log(this.x+this.y); } total(100,200); total.apply(count,[100,200]); </script>
(3)常用于借助属性的内置函数求最大、最小值
<script> var arr =[10,5,6,71,4,61]; console.log(Math.max(10,5,6,71,4,61)); console.log(Math.max.apply(Math,arr)); </script>
3、拓展
(1)...arr:扩展,可以把整个数组拆出来
<script> var arr =[10,5,6,71,4,61]; console.log(Math.max(...arr)); </script>
四、bind()【常用】
1、格式
函数名.bind(指向的对象,参数1,参数2...)
2、作用
(1)不会调用函数,但是能改变函数内部的this指向
(2)返回直接对原函数的拷贝
<script> var x=10; var y=20; var count ={ x:1, y:2, } function total(a){ console.log('this',this); console.log(a); console.log(this.x+this.y); } total(100); console.log(total.bind(count,10)); var f = total.bind(count,10); f(); </script>
(3)函数不需要立即调用,又需要改变函数内部的this指向
3、代码例子:发送验证码(点击按钮后禁用3秒,才可以再点击使用)
<button>发送验证码</button> <script> var btn = document.querySelector("button"); btn.onclick = function(){ console.log("this",this); this.disabled = true; setTimeout(function(){ console.log("this",this); this.disabled = false; }.bind(this),3000) } </script>
call()、apply()、bind()总结
1、相同点:都可以改变函数内部的this指向
2、区别点:
(1)call和apply都会调用函数,但是bind不会调用函数
(2)call和apply传递参数不一样
①call传递参数形式arg1,arg2
②apply必须是数组形式[arg1,arg2]
3、主要应用场景
(1)call常用于继承,如子级函数需要获取父级函数的参数
(2)apply常用于与数组有关,如借助数学内置对象,实现求数组最大、最小值
(3)bind常用于不调用函数又想改变函数this指向,如定时器里的this指向
五、严格模式
JavaScript除了提供正常模式外,还提供了严格模式(strict mode),es5的严格模式是采用具有限制性的
1、目的
(1)消除一些语法的不合理,不严谨,减少一些怪异行为,如:没有声明变量,就去使用(2)消除代码运行的一些不安全之处,保证代码运行的正常,增加代码运行的安全性
(3)提高编译器的效率,提高运行的速度
(4)关键字不能做变量名,如:class、export、extends、import、super
2、开启严格模式
(1)语句:use strict
(2)为所有语句开启
①未开启时
<script> a = 1; console.log(a); </script>
②开启时
<script> "use strict"; a = 1; console.log(a); </script>
(3)为函数内部开启
<script> b = 1; console.log(b); (function(){ "use strict"; a = 1; console.log(a); })() </script>
3、严格模式的变化
(1)变量必须先声明再赋值
(2)this指向的改变,全局作用域中的函数,指向变成了undefined而不是原来的window了
①未开启时
<script> var test = function(){ console.log("this",this); } test(); </script>
②开启时
<script> "use strict"; var test = function(){ console.log("this",this); } test(); </script>
(3)构造函数必须加new调用,否则this会报错
①未开启时
<script> function Person(){ this.sex = '女'; } Person(); console.log(window.sex); </script>
<script> "use strict"; function Person(){ this.sex = '女'; } Person(); console.log(window.sex); </script>
③开启,new时
<script> "use strict"; function Person(){ this.sex = '女'; } var sxx =new Person(); console.log(sxx.sex); </script>
六、*闭包【面试官常问:什么是闭包?🧐】
1、概念:有权访问另一个函数作用域中的变量的函数
一个作用域可以访问另一个作用域内部的局部变量
2、作用
(1)延伸作用域范围
①
<script> function fn1(){ var num =10; function fn2(){ console.log(num); } fn2() } fn1() </script>
②立即执行函数(小闭包):在循环的点击事件里面,立即执行函数里面的所有函数都可以拿到需要的变量
未使用立即执行函数小闭包
<ul> <li>1</li> <li>2</li> <li>3</li> </ul> <script> var list = document.querySelectorAll('li'); for(var i = 0; i<list.length;i++){ list[i].onclick = function(){ console.log(i);//无论点击第几个li,均获取的是i=3,这是错误的 } } </script>
使用立即执行函数小闭包后
<ul> <li>1</li> <li>2</li> <li>3</li> </ul> <script> var list = document.querySelectorAll('li'); for(var i = 0; i<list.length;i++){ (function(i){ list[i].onclick = function(){ console.log(i);//这样获取的i才是正确的对应li下标 } })(i) } </script>
(2)避免变量被资源回收机制销毁
<script> function add(){ var a = 0; return function addCount(){ a++; console.log(a); } } var count = add(); count();//1 count();//2 </script>
3、缺点
(1)函数局部变量一直存在,占用内存
(2)任意造成内存泄露
4、删除闭包
count = null;
JavaScript的基本语法(变量、数据类型、运算符等等),流程控制(顺序、分支、循环),数组,函数(作用域、预解析),对象(自定义、内置),DOM(节点操作、获取元素),BOM(定时器、回调函数、同步异步) JQuery框架的入口函数,隐式迭代,排他思想,链式编程,样式操作,属性操作,事件监听