js 匿名函数 箭头函数

关于new

首先回顾一下new关键字

var ch = new Fa();  
等价于
var ch = {};  
ch.__prototype__ = Fa.prototype;  
Fa.call(ch);  

本质上call的第一个参数可以理解传入了一个this,改变了整个上下文

本文事例

运行环境 nodejs v7.7.2

拿一段观察者模式的代码来看

//js文件
function Event() {  
    this.handlers = {};
}

Event.prototype.on = function(type, cb) {  
    //exception handler, need to code
    if("undefined" == typeof this.handlers[type]) {
        this.handlers[type] = [];
    }

    this.handlers[type].push(cb);
}

Event.prototype.emit = function(type) {  
    //exception handler, need to code
    if(this.handlers[type]) {
        let funs = this.handlers[type];
        for(let idx in funs) {
            let fun = funs[idx];
            setTimeout(fun, 0);
        }
    }
}

let eve = new Event();  
eve.on("add", () => {  
    console.log("add");
});
eve.on("del", () => {  
    console.log("del");
});
eve.emit("del");  
eve.emit("add");  

如果上述的prototype属性赋值,将匿名函数修改成箭头函数,那么就会出问题
js 匿名函数 箭头函数.png

这是因为箭头函数中this是指向词法作用域,这里面是全局变量module的属性exports,而不是对象eve

可以使用一下代码验证

function Event() {  
    this.handlers = {};
}

Event.prototype.on = (type, cb) => {

//++
    console.log(this.wwww);


    //exception handler, need to code
    if("undefined" == typeof this.handlers[type]) {
        this.handlers[type] = [];
    }

    this.handlers[type].push(cb);
}

Event.prototype.emit = (type) => {  
    //exception handler, need to code
    if(this.handlers[type]) {
        let funs = this.handlers[type];
        for(let idx in funs) {
            let fun = funs[idx];
            setTimeout(fun, 0);
        }
    }
}

//++
this.wwww =  "wwww";  
console.log(this === exports);

let eve = new Event();  
eve.on("add", () => {  
    console.log("add");
});
eve.on("del", () => {  
    console.log("del");
});
eve.emit("del");  
eve.emit("add");  

延伸

如下js代码

this.wwww = "wwww";  
var a = function() {  
    console.log(this.wwww);
}
a();

function b() {  
    console.log(this.wwww);
}
b();

var c = () => console.log(this.wwww);  
c();  

使用nodejs命令执行如上代码的js文件,输出的是

undefined  
undefined  
wwww  

但是在终端里(或者chrome浏览器中),输出的是

wwww  
wwww  
wwww  

这是因为在终端里,this就是指向全局变量global,故而在对象Global上会添加上wwwa, b, c等等属性,运行时会取到调用者globalwwww属性

在js文件,this指向的是exports对象(属性),同时a,bc属性并列
如下图所示

js 匿名函数 箭头函数.png

也就是说c使用了箭头函数,内部this指向了词法作用域(措辞可能不准确,这里指变量exports),那么就可以找到属性wwww

可以使用如下js文件验证

function b() {  
    console.log(this === global);
    console.log(this.wwww);
}
b();  

参考

彻底理解js中this的指向,不必硬背