这两天看了很早前的一个原型和闭包系列,来自于深入理解Javascript中的原型和闭包系列,对里面十几篇文章做了一些记录,当然里面也有我的一些理解,但基本都是从该系列中提取的一些认为比较重要的点。
一切(引用类型)都是对象,JS引用类型包括数组、对象、null、函数、new Number(10),他们都是对象。判断一个变量是否为对象十分简单,值类型的判断用typeof,而引用类型的判断可以用instanceof。[其中值类型包括undefined,number,string,boolean]
1
2var fn = new Function();
console.log(fn instanceof Object); //true对象——若干属性的集合,对象里面的一切都是属性,只有属性,没有方法。方法如何表示?方法也是一种属性,它的属性表示为键值对的形式。
1 | var obj = { |
- 对象都是通过函数创建的。
1 | function Test() { |
- 每个函数都有一个属性叫做protopyte。
1 | function Fn() { } |
- 每个对象都有一个proto属性,指向创建该对象的函数的prototype。
1 | var obj = {}; |


从控制台输出可以看出obj.__proto__和Object.prototype的属性一样,即obj.__proto__ === Object.prototype。 上面可以看出两者属性是一样的,也就是结果为true。由控制台输出信息可以看出obj.__proto__的结果是一个对象,那么Object.prototype自然而然也是一个对象,由于每个对象都有一个__proto__属性,那么Object.prototype的__proto__指向哪? 其中obj是由Object创建的,所以它的__proto__指向Object.prototype。而Object.prototype确实是一个特例,它的proto`指向的是null,控制台输出可以告诉你答案。
1
2function Foo() {...}
var f1 = new Foo();
f1 –> f1.__proto__ <=> Foo.prototype(.__proto__) <=> Function.prototype(.__proto__) <=> Object.prototype;
其中f1 instanceof Function的结果为false,对象是由函数创建的,f1是函数创建的一个对象,并不等同于Function。
instanceof表示的就是一种继承关系,或者原型链的结构。
- Javascript中的继承是通过原型链来体现的。
1 | function Foo() {} |

f1由函数Foo创建得来的对象,控制台输出f1.a的值为10,是因为f1.a是f1的基本属性,f1.b是怎么得来的?从Foo.prototype得来,由于f1.__proto__指向Foo.prototype,所以f1.b的值为200。访问一个对象的属性时,先在基本属性中查找,如果没有,在沿着proto这条链向上找,这就是原型链。 实际开发应用如何区分一个属性到底是基本属性还是从原型中得到的[特别在for…in…循环中需要注意]?这里需要用到hasOwnProperty。1
2
3
4
5
6
7
8
9var item;
for(item in f1) {
console.log(item); // a b
}
for(item in f1) {
if(f1.hasOwnProperty(item)) {
console.log(item); // a
}
}
f1 –> f1.__proto__ <=> Foo.prototype(.__proto__) <=> Function.prototype(.__proto__) <=> Object.prototype;
对象f1的hasOwnProperty()方法由Object.prototype继承得来,可以看上述的指向,说明Function.prototype中同样继承来自Object原型中的hasOwnProperty()方法。
- 执行上下文
1 | // 情况1 |
针对情况3,在一句一句执行js代码之前,浏览器已经做了一些“准备工作”,其中就包括对变量的声明,但不包括赋值,所以情况3实际的执行代码步骤应该是这样:var a; console.log(a); a = 10;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// 函数表达式和函数声明
// 情况1[函数声明]
console.log(f1); // function f1() {...}
function f1() {...}
// 情况2[函数表达式]
console.log(f2); // undefined
var f2 = function() {...};
/*
* 总结:
* 1. 变量、函数表达式——变量声明,默认赋值为undefined
* 2. this——赋值
* 3. 函数声明——赋值
*/
- this [http://www.cnblogs.com/wangfupeng1988/p/3988422.html]
- 作用域。JavaScript没有块级作用域。
1 | var i = 2; |

1
2
3
4
5
6
7
8
9// 要到创建这个函数的那个作用域中取值——是“创建”,而不是“调用”
/*
* 在A作用域中使用的变量x,却没有在A作用域中声明(即在其他作用域中声明的),对于A作用域来说,x就是一个自由变量。比如上图中的a就是一个自由变量。
* 第一步,现在当前作用域查找a,如果有则获取并结束。如果没有则继续;
* 第二步,如果当前作用域是全局作用域,则证明a未定义,结束;否则继续;
* 第三步,(不是全局作用域,那就是函数作用域)将创建该函数的作用域作为当前作用域;
* 第四步,跳转到第一步。
* 根据上面的例子可以这样理解[作者应该估计也是这么理解的]:根据函数fn创建了对象x,调用x(),fn函数体里面可以直接看到的就是输出到控制台的内容是什么?执行函数fn的结果是返回bar,即控制台输出的a+b的值。那么函数bar()中的a的值,从当前作用域出发,最终发现不管是bar作用域还是fn作用域都没有定义,最终找到了自由变量a,所以a的值为10。那么b的值,并不存在自由变量b,所以b的值可以到创建函数bar的fn作用域获取,也就是作者提到的第三步,得到b的值为20,所以后面即使给b赋值为200,其实也没用,所以最终结果为30。如果将fn作用域中的b定义拿掉,那最终结果就有210,这里不解释了。注意:后面虽然重新定义了b的值为200,但不影响作用域中b的值,本身两者作用域都不同,也就是这两个变量半毛钱关系没有,只是两个命名的名字一样而已。
*/
1 | // “自由变量”到“作用链”情况2 |