关于this指向的问题

函数的this在调用时绑定的,完全取决于函数的调用位置(也就是函数的调用方法)。为了搞清楚this的指向是什么,必须知道相关函数是如何调用的。

全局上下文-->指向window

console.log(this);

这里的this指向的是window

函数上下文

普通函数调用模式

var aa = 123
        var wzh = function () {
            var aa = 456
            console.log(this.aa); //123
            console.log(this); // 'window'
        }
        wzh();

你可能会误以为window.wzh()是调用的,所以是指向window。虽然本例中window.wzh确实等于wzhaa等于window.aa。上面代码中这是因为在ES5中,全局变量是挂载在顶层对象(浏览器是window)中。 事实上,并不是如此,就比如下面这种

let name2 = 'window2';
        let www = function () {
            console.log(this === window); // true
            console.log(this.name2); //undefined
        }
        www()

这个例子中let没有给顶层对象中(浏览器是window)添加属性,window.name2和window.www都是undefined

对象中的函数(方法)调用模式

var name = 'window';
        var www = function () {
            console.log(this.name);
        }
        var student = {
            name: 'wzh',
            www: www,
            other: {
                name: 'other',
                www: www,
            }
        }
        student.www(); // 'wzh'
        student.other.www(); // 'other'
        // 用call类比则为:
        student.www.call(student);
        // 用call类比则为:
        student.other.www.call(student.other);

构造函数调用模式

function Student(name) {
            this.name = name;
            console.log(this); // {name: 'wzh'}
            // 相当于返回了
            // return this;
        }
        var result = new Student('wzh');

使用new操作符调用函数,会自动执行以下步骤。

  • 创建了一个全新的对象。
  • 这个对象会被执行[[Prototype]](也就是__proto__)链接。
  • 生成的新对象会绑定到函数调用的this
  • 通过new创建的每个对象将最终被[[Prototype]]链接到这个函数的prototype对象上。
  • 如果函数没有返回对象类型Object(包含Functoin, Array, Date, RegExg, Error),那么new表达式中的函数调用会自动返回这个新的对象。

由此可以知道:new操作符调用时,this指向生成的新对象。 特别提醒一下,new调用时的返回值,如果没有显式返回对象或者函数,才是返回生成的新对象

原型链中的调用模式

function Student(name){
    this.name = name;
}
var s1 = new Student('www');
Student.prototype.wzh= function(){
    console.log(this.name);
}
s1.wzh(); // '若川'

会发现这个似曾相识。这就是对象上的方法调用模式。自然是指向生成的新对象。 如果该对象继承自其它对象。同样会通过原型链查找。

DOM事件处理函数调用

<button class="button">onclick</button>
<ul class="list">
    <li>1</li>
    <li>2</li>
    <li>3</li>
</ul>
<script>
    var button = document.querySelector('button');
    button.onclick = function(ev){
        console.log(this);
        console.log(this === ev.currentTarget); // true
    }
    var list = document.querySelector('.list');
    list.addEventListener('click', function(ev){
        console.log(this === list); // true
        console.log(this === ev.currentTarget); // true
        console.log(this);
        console.log(ev.target);
    }, false);
</script>

onclickaddEventerListener是指向绑定事件的元素。 一些浏览器,比如IE6~IE8下使用attachEventthis指向是window。 顺便提下:面试官也经常考察ev.currentTargetev.target的区别。 ev.currentTarget是绑定事件的元素,而ev.target是当前触发事件的元素。比如这里的分别是ulli。 但也可能点击的是ul,这时ev.currentTargetev.target就相等了。

总结

如果要判断一个运行中函数的 this 绑定, 就需要找到这个函数的直接调用位置。 找到之后 就可以顺序应用下面这四条规则来判断 this 的绑定对象。

  1. new 调用:绑定到新创建的对象,注意:显示return函数或对象,返回值不是新创建的对象,而是显式返回的函数或对象。
  2. call 或者 apply( 或者 bind) 调用:严格模式下,绑定到指定的第一个参数。非严格模式下,nullundefined,指向全局对象(浏览器中是window),其余值指向被new Object()包装的对象。
  3. 对象上的函数调用:绑定到那个对象。
  4. 普通函数调用: 在严格模式下绑定到 undefined,否则绑定到全局对象。

ES6 中的箭头函数:不会使用上文的四条标准的绑定规则, 而是根据当前的词法作用域来决定this, 具体来说, 箭头函数会继承外层函数,调用的 this 绑定( 无论 this 绑定到什么),没有外层函数,则是绑定到全局对象(浏览器中是window)。 这其实和 ES6 之前代码中的 self = this 机制一样。

DOM事件函数:一般指向绑定事件的DOM元素,但有些情况绑定到全局对象(比如IE6~IE8attachEvent)。

一定要注意,有些调用可能在无意中使用普通函数绑定规则。 如果想“ 更安全” 地忽略 this 绑 定, 你可以使用一个对象, 比如 ø = Object.create(null), 以保护全局对象。

面试官考察this指向就可以考察new、call、apply、bind,箭头函数等用法。从而扩展到作用域、闭包、原型链、继承、严格模式等。这就是面试官乐此不疲的原因。

本文摘自:若川

来源:稀土掘金
链接:https://juejin.cn/post/6844903746984476686

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值