this--函数的执行主体

this--函数的执行主体

技术杂谈小彩虹2021-07-09 17:41:29100A+A-

THIS

this:函数的执行主体

this的创建

首先需要明确,this是执行上下文的一个属性,而不是说是某个变量对象的属性,是一个与执行上下文相关的特殊指针。在实际开发中应该避免eavl函数,所以我们讨论主要的是全局执行上下文和函数私有执行上下文中的this

function add(a,b){
    console.log(this);
    return a + b;
}
add(1,2);	// 生成函数执行上下文,并入栈执行

如何判断执行上下文this的指向,其中最重要的一项指标就是判断函数执行的服务对象,这个服务对象就是当前函数执行的主体。但像上述 add 函数执行不知道为谁服务的情况下,那么他的this就会指向window。(不清不楚全按window处理)

this指向问题

1. 事件绑定

给当前元素的某一个事件行为绑定函数,方法执行时的this就是绑定的当前元素本身(IE6~8,基于attachEvent实现的DOM2事件绑定,绑定的方法中的this不是操作的元素,而是window)

document.body.onclick = function(){
    // this -> body
};
document.body.addEventListener('click',function(){
    // this -> body
});

2. 函数执行

函数执行时,看函数执行之前是不是通过的方式调用,有前面是谁,执行主体this就是谁,没有一律按window算(在JS的严格模式下,没有,方法中的this是undefined)

function fn(){
    console.log(this);
}
let obj = {
    name:'xxx',
    fn:fn
}
fn();       //this:window
obj.fn();   //this:obj 
  • 自执行函数中的this一般都是window,严格模式下是undefined

  • 回调函数中的this一般都是window,严格模式下是undefined

setTimeout中传入的是回调函数,所以这里的this是window,而不是obj。

let obj = {
    name:'xxx',
    fn(){
        setTimeout(function(){
            this.name = "Tom";
        },1000);
    }
}
obj.fn()    //this => window
// 将setTimeout中的回调函数写成箭头函数的形式,就可以解决这个问题了

3. 箭头函数的上下文中没有this

箭头函数在创建执行上下文的时候,在初始化上下文环境时,不会创建this属性,所以在箭头函数中如果使用到this会根据作用域链向上级上下文寻找

let obj = {add};
function add(a,b){
    console.log(this);
    let fn = (a,b) => {
        console.log(this);	// obj
        return a + b;
    }
    return fn(a,b);		// obj
}
obj.add(1,1);	// 2

4. 构造函数时的this

函数在new执行时,会创建一个实例对象,而this指向的就是这个实例对象

function fn(){
    this.a = 1;
    this.b = 1;
    this.add = function(){
        return this.a + this.b;
    }
}
let obj = new fn();	// obj = {a:1,b:1,add} 函数new执行创建的实例对象
obj.add();		//2

5. 基于call、apply和bind改变this的指向

Function.prototype上提供了call、apply和bind方法来强制改变this的指向,但是这个操作对于箭头函数是无效的(箭头函数中没有自己的this)

let ArrayLike = {0:'a',1:'b',2:'c',length:3};
[].forEach.call(ArrayLike,(item)=>{	// 基于call方法让类数组能够数组原型上的方法
	console.log(item);
})

面试题

例题1

let obj = {
    fn: (function () {
        return function () {
            console.log(this);
        }
    })()
};
obj.fn();                       //obj
let fn = obj.fn;
fn();                           //window

例题2

var fullName = 'language';
var obj = {
    fullName: 'javascript',
    prop: {
        getFullName: function () {
            return this.fullName;
        }
    }
};
console.log(obj.prop.getFullName());        //undefined
var test = obj.prop.getFullName;
console.log(test());                        //language

例题3

var name = 'window';
var Tom = {
    name: "Tom",
    show: function () {
        console.log(this.name);
    },
    wait: function () {
        var fun = this.show;
        fun();
    }
};
Tom.wait();                                 //window

例题4

window.val = 1;
var json = {
    val: 10,
    dbl: function () {
        this.val *= 2;
    }
}
json.dbl();
var dbl = json.dbl;
dbl();
json.dbl.call(window);
alert(window.val + json.val);               //24

例题5

(function () {
    var val = 1;
    var json = {
        val: 10,
        dbl: function () {
            val *= 2;
        }
    };
    json.dbl();
    alert(json.val + val);                  //12
})();

例题6

var num = 10;	// 60 65
var obj = {
    num: 20		// 30
};
obj.fn = (function (num) {	// 闭包中的 num 21 22 23
    this.num = num * 3;
    num++;
    return function (n) {
        this.num += n;
        num++;
        console.log(num);
    }
})(obj.num);
var fn = obj.fn;
fn(5);                          //22
obj.fn(10);                     //23
console.log(num, obj.num);      //65 30

手写call

/* * _call : 用于强制转换this的指向 * @params {object} context 执行主体 * @params {any} params 函数执行时传递的参数列表 * @return {any} result 函数执行的返回结果 */
Function.prototype._call = function(context,...params){
    context == null ? context = window : null;
    !(/^(function|object)$/i.test(typeof context)) ? context = Object(context) : null;
    
    let result,
        key = Symbol('key');
    context[key] = this;
    result = context[key](...params);
    delete context[key];
    return result;
}

点击这里复制本文地址 以上内容由权冠洲的博客整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!

支持Ctrl+Enter提交

联系我们| 本站介绍| 留言建议 | 交换友链 | 域名展示
本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除

权冠洲的博客 © All Rights Reserved.  Copyright quanguanzhou.top All Rights Reserved
苏公网安备 32030302000848号   苏ICP备20033101号-1

联系我们