箭头函数,除了帮助我们简写之外,最大的好处就是this不再被绑定在调用者,而是继承与环境对象,在哪个环境定义,this就是指的哪个环境对象。
在编写构造函数或者函数时,this的指向经常会变化,导致this.属性无法在各个函数体面使用
案例代码:
function Counter() { console.log('我是构造体'+this); this.number = 0; //返回一个 ID(数字),可以将这个ID传递给 clearTimeout() 来取消执行。 this.timer = window.setTimeout(function () { this.number++; //此时的this的意思是window,window是没有number属性的 console.log(this.number); },1000) } var b = new Counter(); console.log(b.number); 结果 0 NaN
为了解决this指向问题,我们可以使用bind来改变,不能使用call,apply
function Counter() { this.number = 0; var fn = function () { this.number++ console.log(this.number); } // 不能用call、applay,这两种方法都是立即执行,并且不会循环执行 // var timer = window.setTimeout(fn.call(this),3000) //var timer = window.setInterval(fn.apply(this),3000) var timer = window.setInterval(fn.bind(this),3000) } var b = new Counter(); console.log(b.number);
从上可以看出,想改变this的指向非常困难
有了箭头函数之后,一切都变得简单,不在绑定this的指向了
function Counter() { this.number = 0; var timer = setInterval(() => { console.log(this); this.number++; console.log(this.number); },2000) } var b = new Counter();
原理分析:
普通函数,this的概念是:this是JavaScript的一个关键字,他是指函数执行过程中,自动生成的一个内部对象,是指当前的对象,只在当前函数内部使用。(this对象是在运行时基于函数的执行环境绑定的:在全局函数中,this指向的是window;当函数被作为某个对象的方法调用时,this就等于那个对象)。
函数中this对象的取值,是在函数被调用执行的时候确定的。此时会创建执行上下文环境。
对于箭头函数,它没有自己的this,不能用作构造函数。
箭头函数中的this对象是定义时所在的对象,不是调用时所在的对象。
案例1
var testObject = { name:'123', sayHi:function () { console.log(this); // return function () { // console.log(this); // } //箭头函数的this,不再是谁调用就是谁,而是指当前环境的this是谁, //一般是指父级,因为箭头函数没有this对象,都是从父级继承过来的 return ()=>{ console.log(this); } } } var hh = testObject.sayHi(); window.hh();
案例2
function foo() { setTimeout(function() { console.log('setTimeout普通函数的this='+this); console.log("id: ",this.id); }, 100); } function fooa() { setTimeout(()=>{ console.log('setTimeout箭头函数的this='+this); console.log("id: ",this.id); }, 100); } var id=21; //两个函数的结果都是一样的:window,21 //因为可以理解为都是由window调用的window.foo() 和 window.fooa() foo(); //this指向window对象, 21 fooa(); //this指向window对象, 21 ========================================= //setTimeout(普通函数体)的this指向的调用时对象,那么这个对象如果不改变的话永远都是window. foo.call({id:42}); //this指向window对象, 21 //setTimeout(箭头函数体)本身没有this,定义时对象,也就是哪个对象调用了,this就是哪个对象的 fooa.call({id:42}); //this指向object对象, 42
案例3-返回值是函数的,函数体里面的this指向的是window,和普通函数里面的this一样
const test = { name: 'test object', createAnonFunction: function() { return function() { //function 当做了普通函数,this的指向是window console.log(this.name); console.log(arguments); }; }, createArrowFunction: function() { return () => { //箭头函数本身没有this对象,this是在定义是去找,本身没有的话,就会去父级寻找 //当test对象去调用方法createArrowFunction,this就获得了test对象 console.log(this.name); console.log(arguments); }; } }; //结果 JavaScript 代码: > const anon = test.createAnonFunction('hello', 'world'); > const arrow = test.createArrowFunction('hello', 'world'); > anon(); undefined {} > arrow(); test object { '0': 'hello', '1': 'world' }
案例4-函数作为参数的时候,函数体里面的this指向的是window,和普通函数里面的this一样
Array.prototype.myFind = function (index,callback) { //this是对象数组 console.log(this) for (var i = 0; i < this.length; i++) { if(i === index){ callback(this[i]) } } } var arr = ['hello', 'WORLD', 'Whatever']; arr.myFind(1,function (item) { //this是window console.log(this); console.log(item); })
特殊的案例