无论项目开发还是应付面试,this指向问题你都没办法回避,花几分钟搞定它!我尽可能的用简单的语言来描述。
1. 默认this绑定window
当在全局的上下文中调用this,此时this指向是默认的window。
<body><script>let name = '哈哈'console.log(this) //这里的this 处于全局上下文 指向的便是windowconsole.log(this.name) // 此时this.name 相当于window.name, 即全局作用域下的name ‘哈哈’</script></body>
输出结果为:
2. 隐式绑定this
隐式绑定是指,谁调用就指向谁!
(其实与第一种默认绑定原理相同,第一种就是在window对象中调用的this)
<body><script>let name = '哈哈'let obj = {name:"嘿嘿",getName: function(){console.log(this.name) // 此时的this便是obj , 因此输出是嘿嘿}}obj.getName() </script></body>
注意:
如果再getName中再加一个函数,test()
<body><script>let name = '哈哈'let obj = {name:"嘿嘿",getName: function(){console.log(this)console.log(this.name)function test(){console.log(this)console.log(this.name)}test()}}obj.getName()</script></body>
输出结果如下:
这表明,getName中的this指向的是obj,但test()中的this指向的是window! 也就是说虽然test()在getNmae内部,但两个this没关系,仍然是谁调用指向谁,test()没有指明调用者相当于默认为window。
另外补充几个特例:
<script>// 一些api可以指定this指向var obj2 = {name:"嘻嘻"}var arr=[1,2,12]// 对于arr.forEach 函数 ,当不传第二个参数时,默认this指向windowarr.forEach(function(item,index,arr){console.log(this)})// 当有第二个参数时,指向指定的obj2arr.forEach(function(item,index,arr){console.log(this)},obj2)// sort 也是指向windowarr.sort(function(){console.log(this)})</script>
结果:
3. 显式绑定 call、apply、bind
三者都是用来显式指定this的指向,主要区别在于传参方式不同
<script>console.log('88888')var obj3 = {name:'吼吼'}function f3(a,b,c){console.log(a,b,c)console.log("我的this是",this)}f3(1,2,3)f3.call(obj3,4,5,"call")f3.apply(obj3,[4,5,"apply"])f3.bind(obj3)(4,5,"bind") // bind特殊点是,其返回的是个函数</script>
执行结果:
注:当指定的对象不存在时,this仍指向默认的window
比如:call(undefind)
4. new绑定
指使用构造函数创建对象时,this指向新创建的对象
var obj = new foo()
这时this指向新创建的对象obj
5. 优先级 new>显式>隐式>默认
6. 箭头函数
箭头函数是ES6新增的创建函数方法。但箭头函数和普通函数不同,箭头函数内部是没有this的指向的,箭头函数中的this实际上是向外层一级一级的查找作用域中的this(直到this有定义)
看代码比较好理解:
<script>console.log("箭头函数")function foo(){console.log(this) // 因被obj4调用,所以this指的是obj4var test2 = function(){console.log(this) // 上面以及分析过了,此处指的是 window}var test = ()=> {console.log(this) // 但是这里的this 指向的仍是 obj4 与父级作用域的this是相同的}test()test2()}var obj4 = {a:"哦哦",foo:foo}obj4.foo()</script>