JavaScript this
当前执行 代码 的环境对象,在非严格模式下,总是指向 一个 对象,在严格模式下可以是任意值。(MDN)
this 指向的是当前的 代码 上下文环境,所以不同情况下的 this 指向也不同。
1. 全局下的 this
在全局环境下, this 指向全局对象。
全局对象和宿主环境相关,在浏览器下,全局对象就是 window 对象,在 node.js 中,全局对象是 global 对象。
window === this ; // 输出 :true
新的标准提供了 globalThis 关键字来 获取 全局对象,这样就能抹平宿主的差异来操作处理全局对象了。
2. 函数 中的 this
函数 在不同情况下,其 this 的指向也不同。
2.1 对象下的 方法
方法 也是 一个 函数 ,如果通过对象 调用 一个 函数 , 函数 的 this 就会指向这个对象。
var person = { age : , name : '鸽子王' , skill : '放鸽子' , say : function ( ) { console . log ( '来一段自我介绍:' ) ; console . log ( '我是' + this . name ) ; console . log ( '我今年' + this . age + '岁' ) ; console . log ( '我最擅长' + this . skill ) ; } , } ; person . say ( ) ;
say 函数 作为对象下的 方法 ,在被 调用 后,其 this 指向的是他所在的对象, 在这里 就是 person 对象。
2.2 原型链上 方法 的 this
原型链上的 方法 ,this 指向的也是 调用 该 方法 的对象。
var __proto__ = { sum : function ( ) { return this . number1 + this . number2 ; } , } ; var object = Object . create ( __proto__ ) ; object . number1 = ; object . number2 = ; console . log ( object . sum ( ) , ) ; // 输出 :3
Object.create 做就就是将参数作为原型,创建 一个 对象。
所以 object 的第一原型就是 __proto__ 对象。
number1 和 number2 都是 object 变量的 属性 ,但却可以被 sum 方法 中的 this 访问到,所以在原型链的 方法 中,this 指向的就是 调用 该 方法 的对象。
2.3 getter / setter 下的 this
getter 和 setter 下的 this 也会指向 调用 该 getter 和 setter 的对象。
var object = { _name : '鸽子王' , get name ( ) { return this . _name ; } , set name ( val ) { console . log ( val ) ; this . _name = val ; } } ; console . log ( object . name ) ; // 输出 :鸽子王 object . name = '鸽子天王' ; // 输出 :鸽子天王 console . log ( object . name ) ; // 输出 :鸽子天王
getter 和 setter 本质上也可以理解成两个 函数 ,作为对象下的 函数 ,在 调用 的时候 this 也会指向该对象。
2.4 作为 DOM 节点的事件处理器
作为 DOM 节点的事件处理器的时, 函数 的 this 会指向这个 DOM 对象。
< div > < button > 点击我 </ button > </ div > < script > document . querySelector ( 'button' ) . addEventListener ( 'click' , function ( ) { this . innerHTML = '被点击了!' ; } ) ; </ script >
2.5 作为 一个 内联的事件处理器
内联的事件处理器,其 this 指向的是 DOM 节点自身。
< div > < button onclick = "console.log(this); console.log(this === document.querySelector('button'))" > 点击我 < / button > < / div >
这个规则有局限性,只有最外层的 this 符合这个规则。
< div > < button onclick = "function test() { console.log(this) }; test() ;" > 点击我 < / button > < / div >
test 函数 的 this 指向的是全局对象 window 。
2.6 其他大部分情况下
排开上述的几个情况,剩下的 函数 大部分情况下在 调用 时,this 指向的是全局对象,在浏览器中就是 window 对象。
function fn ( ) { console . log ( this ) ; console . log ( this === window ) ; } fn ( ) ;
这样 调用 函数 ,其 this 指向的就是 window 对象了。
有的时候可能会搞混以下情况:
var object = { username : '咸鱼' , fn : function ( ) { console . log ( this . username ) ; function thisTest ( ) { console . log ( this . username ) ; console . log ( this === window ) ; } thisTest ( ) ; } , } ; object . fn ( ) ;
这里 thisTest 方法 输出 的 username 就会是个 undefined,因为他的 this 指向的是 window,因为他不属于 object 对象的 一个 方法 ,所以 this 就指向了 window。
在回调 函数 中经常会碰到这个问题:
var info = { account : '123' , password : '456' , login : function ( cb ) { setTimeout ( function ( ) { cb ( { account : this . account , password : this . password , } ) ; } , ) ; } } ; info . login ( function ( info ) { console . log ( info ) ; } ) ;
这里回调 函数 获取 的账号和密码是 undefined ,原因就是 this 的指向问题。
通常会使用保留上层 this 的方式 解决 这个问题。
var info = { account : '123' , password : '456' , login : function ( cb ) { var _this = this ; setTimeout ( function ( ) { cb ( { account : _this . account , password : _this . password , } ) ; } , ) ; } } ; info . login ( function ( info ) { console . log ( info ) ; } ) ;
这样就能 解决 这个问题。
另外 一个 情况也很容易混淆 this :
var object = { user : 'no.1' , say : function ( ) { console . log ( this . user ) ; } , } ; var say = object . say ; object . say ( ) ; // 输出 :"no.1" say ( ) ; // 输出 :undefined
这是因为把 object 下的 say 方法 单独赋值给 say 变量的时候,其就作为了 window 下的 一个 方法 ,所以他的 this 指向的是 window。
在严格模式中,这种情况下的 this 会变成 undefined 。
2.7 构造 函数
在 JavaScript 构造 函数 也被成为 对象构造器 ,用于产生对象。
构造 函数 的声明和普通 函数 几乎没有区别:
function Point ( x , y ) { this . x = x ; this . y = y ; } var point = new Point ( , ) ; console . log ( point . x ) ; // 输出 :1 console . log ( point . y ) ; // 输出 :2
构造 函数 使用 new 关键字来构造对象。所以当 一个 函数 被使用 new 关键字 调用 时,这个 函数 就会作为 一个 构造 函数 。
在 一个 构造 函数 被 调用 后,其内部的 this 会指向 一个 对象,具体的 内容 可以参考 构造 函数 章节。
@H_803_1 404 @3. 修改 this
3.1 call 方法 和 apply 方法
函数 具有 call 方法 和 apply 方法 ,这两个 方法 可以在 调用 函数 的时候指定 函数 的 this。
var object = { user : 'no.1' , } ; function say ( ) { console . log ( this . user ) ; } say ( ) ; // 输出 :undefined say . call ( object ) ; // 输出 :"no.1" say . apply ( object ) ; // 输出 :"no.1"
通过 call 和 apply 方法 将 say 函数 执行时候的 this 设置为 object 对象。
call 方法 从第二个参数开始,表示是要传递给当前 函数 的参数。
var object = { user : 'no.1' , } ; function fn ( arg1 , arg2 , arg3 ) { console . log ( this , arg1 , arg2 , arg3 , ) ; } fn . call ( object , , , ) ;
apply 的第二个参数是个数组,数组里面的项会按数组的顺序作为参数传递给 函数 。
var object = { user : 'no.1' , } ; function fn ( ) { console . log ( this , arguments , ) ; } fn . apply ( object , [ , , ] ) ;
通过 arguments 关键字就可以看到当前 函数 的参数,通常在需要 修改 this ,又不确定参数的情况下,会使用 apply 来 修改 this。
3.2 bind
bind 方法 用于给 一个 函数 永久绑定 一个 指定的 this,bind 不会 修改 原 函数 ,会返回 一个 新的 函数 。
var obj1 = { value : '今天打砖' } ; var obj2 = { value : '明天打转' } ; var fn = function ( ) { console . log ( this ) ; } ; var bindFn1 = fn . bind ( obj1 ) var bindFn2 = bindFn1 . bind ( obj2 ) ; bindFn1 ( ) ; bindFn2 ( ) ;
可以看到 bindFn1 被绑定了 obj1 作为 this,之后不论怎么操作,他的 this 都会是 obj1 。
bind 还有更多灵活的 用法 ,参数也可以绑定,有关 bind、call、apply 这三个 方法 的更详细的信息可以查阅对应的文档。
4. 小结
理解好 this 的处理机制可以设计出更加完善的 JavaScript 应用程序。
this 在 ES6 的箭头 函数 中的表现也有所不同,可以查阅 ES6 中有关箭头 函数 的 内容 。
严格模式 ? ?JavaScript instanceof声明:本文来自网络,不代表【好得很程序员自学网】立场,转载请注明出处:http://haodehen.cn/did92447