js的原型&原型链&闭包,在很多人看来是区分JS程序员水平的关键知识点,当然对这句话我不是十分赞同。但是掌握这几个核心知识点总是没错滴!
直接上代码:
<script type="text/javascript">
//全部为函数对象类型(function)
function f1(){}
var f2 = function(){}
var f3 = new Function()
//全部都是普通对象类型(object)
var o1 = {}
var o2 = new Object()
var o3 = new f1()
console.info(
typeof f1,
typeof f2,
typeof f3,
typeof o1,
typeof o2,
typeof o3
)
//function function function object object object
var obj = new f1();
f1.prototype.name = 'banyoukang';
console.info(obj.__proto__.name)//banyoukang
console.info(f1.prototype)// f1 { name="banyoukang"}
console.info(obj.__proto__)//f1 { name="banyoukang"}
</script>
你可以自己试试这段代码,并想一下其输出结果,为什么?下面让我们掰扯掰扯这段代码:
-
关于JavaScript对象
在JavaScript中,一切都是对象,但是和Java不同的是:这些对象是分类型的。主要分为function(函数对象)和object(普通对象)。//全部为函数对象类型(function) function f1(){} var f2 = function(){} var f3 = new Function() //全部都是普通对象类型(object) var o1 = {} var o2 = new Object() var o3 = new f1()
<1>在这里,f1应该是我们开发中最常用法,f2用的应该也挺多,只是多了一个引用罢了。但是,f3这种写法倒是不多见的,其实f1,f2在创建的时候,JS会自动通过new Function()的方式来构建这些对象,所以都是f1,f2,f3本质上并没有什么区别。注:(
var f3 = new Function('var temp = 100; this.temp = 200; return temp + this.temp;');
alert(f3())
//弹出300,()将会执行引号中的内容,类似于eval函数)
<2>关于o1和o2我们都可以理解(对象字面量、使用new表达式来创建对象),但是o3虽然是f1函数new出来的,但是和f1缺不是一个类型的,看打印结果可以发现,一个是函数对象一个是普通对象。
-
关于原型和原型链
在JavaScript中,每一个对象都有一些属性,包括prototype和__proto__,其中prototype就是原型对象(prototype其实就是函数的一个属性),其作用就是保存对象的一些属性和方法(你可以通过f1.prototype.show = function(){} 给f1的prototype赋值一个方法),但是prototype对于对象本身是隐藏起来的,因为它是原型对象prototype的属性而不是对象本身的属性(你可以通过f1.prototype.show()来调用,但是不能通过f1.show()来调用)。关于__proto__,这才是原型链真正起作用的地方,它在普通对象和函数对象中都存在, 它的作用就是保存父类的prototype对象,JS在通过new 表达式创建一个对象的时候,通常会把父类的prototype赋值给新对象的__proto__属性,这样,就形成了一代代传承...
function f2(){}
f2.prototype.name='banyoukang';
var test = new f2();
console.info(test.name)//banyoukang
注:可以通过test.__proto__来查看原型链
_proto_保存着父类的prototype的属性,当查找一个属性的时候,先看看自己有没有这个属性,如果没有就顺着原型链往上依次查找(注:不会查找自身的prototype属性)。
3.总结
<1>prototype就是对象的一个属性,这个属性也是一个对象(类似Java类中把其他类的对象定义成一个成员变量),专门用于储存准备传递到子类的方法和属性。
<2>__proto__就是prototype中属性和方法的实际传递者,当你new一个对象的时候,会把父类的prototype赋值给新对象的__proto__属性,这样你在子类的__proto__属性中就可以拿到父类传给你的属性和方法。
<3>不同的对象的原型链是截然不同的,比如父类和子类:
function f1(){}
var test = new f1()
f1的原型链:f1->Function.prototype->Object.prototype->null
test的原型链:test->f1.prototype->Object.prototype->null
从上面的实例我们可以看到:对象的prototype属性是为子类服务的,是子类创建的核心,决定了子类的数据类型
这篇博文是自己试验加上阅读其他大神的博客总结出来的,如果您阅读的过程中发现其中存在问题或者有指教的地方,欢迎拍砖,共同进步!