今天有同学问了这么一道题,倒是有点意思,如下:
function Person(name) { this.getName = function () { return name; } this.setName = function (name) { name = name; } } var person1 = new Person("wayne"); console.log(person1.getName()); // wayne var person2 = new Person("hedy"); console.log(person2.getName()); // hedy console.log(person1.getName()); // wayne
很简单,就是为什么最后的结果是这样的。 最后一个结果为什么不是hedy。
于是,我给他举了下面这样的一个例子:
function Person(obj) { this.getName = function () { return obj.name; } this.setName = function (obj) { name = obj.name; } } var obj = { name: "wayne" }; var person1 = new Person(obj); console.log(person1.getName()); // wayne obj.name = "hedy"; var person2 = new Person(obj); console.log(person2.getName()); // hedy console.log(person1.getName()); // hedy
到这里,他还是不太明白,所以,我可以给他解释一下了。
在new的过程中,实际上也是在调用函数,且调用函数时就会创建一个新的函数作用域,对于第一个程序,实际上涉及到了闭包的概念,因为构造函数内部的name还在引用这个构造函数,所以形成了闭包,即使在new之后,这个构造函数中的name依然会保存,而在getName()的过程中,就去寻找这个name; 而再new另外一个Person的时候,实际上又进入了一个新的函数作用域,这个函数作用域同样又保存了新的name,所以第一个程序也就不难理解了。
而第二个程序,因为我创建了一个对象,在对象传入函数的过程中,实际上是传递的引用,即这个对象始终都在堆中的同一个内存里,所以说修改了对象之后,getName()得到的值就始终一样了 。
接着,他又问我,第一个程序中在person1.getName()之后,这里已经将getName()调用了,那么构造函数中的name不是应该释放了吗?为什么最后调用还是可以找到呢? 我又写了下面的这个函数:
function Person(name) { this.getName = function () { return name; } this.setName = function (name) { name = name; } } var person1 = new Person("wayne"); alert(person1.getName()); // wayne var person2 = new Person("hedy"); alert(person2.getName()); // hedy person1.getName = null;
这样,getName函数就不会对Person构造函数进行引用了,这时,实际上Person中的name就会被释放了。
看似简单的一道题,实际上涉及到了构造函数的本质、基本数据类型和引用类型在传参的区别、作用域、闭包等等概念,还是非常不错的。