作者:[email protected],转载请注明作者
在继续分析代码之前,需要先讲一下node.js中的this是什么。因为不讲这个的话,后面的内容进行不下去。在以前版本的node.js中,全局this是个空对象,在node8的repl中,全局this和global是相等的。
> this === global
true
>
但是,如果使用node8执行js文件,全局this是个空对象。
console.log(this)
let result = this === global
console.log(result)
执行结果:
{}
false
好,这个很操蛋的事实还是要接受的。node.js中的this和浏览器中的this又是不一样的。忘掉在浏览器中的经验吧,只要记得this只能随着函数走就行了。为了不影响三观,后面的js语句都只能在文件中写好,然后再用node去执行它。
在C++/java中,this永远都是和某个对象相关的,this生存在类作用域中,隐式存在着。但是在node.js中,它的行为很是诡异。
一、在普通函数中的this,实际上是在引用global,如果你不相信,就执行一下下面的代码。记得先保存文件,然后再执行文件。
function fn(){
this.num = 10;
}
fn();
console.log(this); {}
console.log(this.num); undefined
console.log(global.num); 10
二、this作用域是和函数紧密相关的。来看段稍微长一点的代码。
var name = "like global...";
function one() {
var name = "in func one...";
var other = "somewhat...";
function two() {
var name = "in func two...";
console.log({name: name, other: other});
}
two();
console.log({name: name, other: other});
}
one();
console.log({name: name});
console.log({other: other});
这段代码是执行不了的,语法报错。执行环境node8,其它的环境也许能通过。在console.log({other:other})引用了函数one作用域里的other。都是不合法的。
那什么情况是合法的,只有引用作用域内的才合法。
var name = "like global...";
function one() {
var name = "in func one...";
var other = "somewhat...";
function two() {
var name = "in func two...";
console.log({name: name,other:other });
}
two();
console.log({name: name, other: other});
}
one();
console.log({name: name});
代码证明,同名变量可以在不同作用域存在,不同作用域引用同名变量得到的值不同。也就是存在作用域同名变量覆盖的情况。
三、“构造函数”的this指向的是它自己,而不是global。
function Person(name,age) {
this.name = name;
this.age = age;
}
let p1 = new Person("lilei", 50);
let p2 = new Person("hanmeimei",45);
console.log(p1);
console.log(p2);
console.log(global.name);
console.log(global.age);
四、this魔幻走位,上面看的例子都还好理解,下面来一个让人觉得很诡异的例子。
let Person = {
name : "sam",
age : 18,
foo: function() {
console.log(this.name + ",how old are you?", this.age);
}
};
let Pet = {
name : "dog",
age : 3,
foo : Person.foo
};
Pet.foo();
输出结果为
dog,how old are you? 3
惊喜不惊喜,意外不意外?name和age前不加this是执行不了的,因为作用域问题。但是加上以后呢,为什么输出的和java/c++中的完全不一样。原因就是this是随着执行上下文发生改变的。ecma5提供了一个bind方法,bind可以指定一个this参数,以确保函数在执行的时候,里面的this永远是bind时的那个this,而不会随着调用上下文发生变化。
最后总结一下:
1.在js中,创建一个作用域的唯一方法就是使用function关键字。for循环,case之类的都不行。这和c++/java是不一样的。
2.var声明的变量在整个当前域都是有效的,�而且它会覆盖外部同名变量。
3.this和arguments是随着代码调用位置的变化而变化的。每个嵌套层次切换时都发生变化。