初见原型链
什么是原型链?我们先不来解释定义,我们先来看看下面几个例子。
<script type="text/javascript">
function Student(){
this.job = "student";
this.doing = function(){alert("哈哈")};
}
var xiaoming = new Student();
xiaoming.doing();
console.log(xiaoming.toString());
console.log(Student);
console.log(xiaoming);
</script>
xiaoming对象调用了一个doing()方法,效果就是弹框并且上面有文字就是哈哈。试问为什么会弹框?方法谁给的?toString()方法哪来的?为什么xiaoming可以调用toString()方法?toString()方法是谁的?
首先xiaoming对象是有Student方法new出来的,所以在xiaoming的构造方法里有Student方法里的所有的属性和方法,所以可以调用到Student的doing方法。那么toString()方法是谁的?我可以负责任的告诉你是object来的?那么奇怪了,我代码里压根就没有object这几个字母,你跟我说object来的?接下来我们来引出这个对象prototype和__proto__
prototype/__proto__
prototype
prototype是函数的一个属性,它指向的是构造函数的原型,里面包含了函数的相关信息,所有函数都有prototype。我们来输出一下
我们可以看到第一个大括号里面其实现实的是构造函数。
constructor表示的是构造函数的一些信息,我们可以看到arguments,caller,length,name等信息
__proto__则表示该对象的原型对象,就是object
__proto__
当你通过函数去new一个对象,那么该对象会有个__proto__属性,该属性是指向被构造函数的prototype属性,也就是指向自己的原型对象。
我们可以通过输出日志来看看prototype和__proto__的值。
可以这么理解Student.prototype是Student的原型,Student.prototype是xiaoming的原型对象,xiaoming.__proto__指向的是Student.prototype,所以xiaoming.__proto__等同于Student.prototype。我们来整理一下它们的关系
prototype
Student---------------> Student.prototype
↑
xiaoming-----_proto_
构造函数的prototype指向谁,那么new出来的对象的__proto__就指向谁。
**************************************
原型链
以上介绍了prototype __proto__的概念,prototype表示原型,那么链的概念主要有__proto__来实现,组合起来就是原型链,下面来解释一下原型链的概念与应用
怎么体现呢?下面来一段demo
<script type="text/javascript">
function Student(name){
this.job = "student";
this.name=name;
this.doing = function(){alert("哈哈")};
}
Student.prototype.hobby = function(){
alert("aihao");
};
var xiaoming = new Student("xiaoming");
console.log("Student.prototype");
console.log( Student.prototype);
console.log("xiaoming");
console.log(xiaoming);
console.log("xiaoming.__proto__");
console.log( xiaoming.__proto__);
xiaoming.hobby();
</script>
结果:执行上述代码,会弹出内容是aihao的弹框
我们可以看到,我们没有在Student的构造方法里去添加hobby方法,而是通过prototype方式添加,通过日志可以看到hobby方法和constructor同级,所以在xiaoming的构造方法里没有hobby的方法,若要调用此方法需要通过__proto__去找。这就触发了链式的关系,流程如下xiaoming要调用hobby方法,但是自己在构造方法中找不到该方法,则会通过xiaoming.__proto__去查找hobby方法,若xiaoming.__proto__里还找不到则继往xiaoming.__proto__(Student.prototype)的__proto__去向上找,直到找到最顶还是找不到则没有。
正如之前提的一个问题,toString方法是哪来的?首先xiaoming的构造方法里没有toString方法,那么会往上找先找到xiaoming的原型对象-->xiaoming.__proto__,若还找不到toString方法,则会再网上找,也就是xiaoming.__proto__的原型对象的原型对象,也就是object,最后找到了toString方法,从而调用。
那么__proto__就引出了原型链的概念,其实原型链是一个动词,是一个操作。有很多个原型构成的链,当需要查找或调用一个函数的时候,先会在该对象的构造方法中去查找,若没有则会去查找该对象的原型__proto__,若还是没有则会继续向上找,一直到到object就算是找到头了。
原型链应用
效果如下 行走的小女孩
利用面向对象的思维,学一个方法,在方法里去构建dom对象,对通过prototype去添加公共方法,将对象添加到数组中,通过定时器让他走起来。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
* {
padding: 0;
margin: 0;
}
html,body {
height: 100%;
}
div.girl {
width: 79px;
height: 108px;
background: url(aisidier.png) 0 -216px no-repeat;
position: absolute;
}
div.end {
border: 2px solid #000;
position: absolute;
top: 0;
left: 1000px;
height: 100%;
}
</style>
</head>
<body>
<div class="end"></div>
<script type="text/javascript">
// 如何设计对象 女孩
function Girl() {
this.x = 0; // 水平距离
this.y = parseInt(Math.random()*(document.documentElement.clientHeight-108)); //竖直距离
this.speed = parseInt(Math.random()*10)+1;// 速度
this.step = 0; // 第几帧
this.isMove = true;
// 上DOM树
this.init();
// 绑定事件
this.bindEvent();
Girls.push(this);// 存放所有new出来的实例
}
// 方法定义在原型上
Girl.prototype.init = function() {
this.dom = document.createElement("div");
this.dom.className = "girl";
document.body.appendChild(this.dom);
}
Girl.prototype.update = function() {
// 判断自己的运动状态
if(!this.isMove) return;
var that = this;
//console.log(that.x);
that.x += that.speed;
that.step++;
if(that.step>7) {
that.step = 0;
}
if(that.x>1000) {
that.goDied();
}
that.dom.style.left = that.x + "px";
that.dom.style.top = that.y + "px";
that.dom.style.backgroundPosition = -that.step*79+"px -216px";
}
Girl.prototype.goDied = function() {
// 下树
document.body.removeChild(this.dom);
// 从数组中删除自己
for(var i=0; i<Girls.length; i++) {
if(Girls[i]== this) {
Girls.splice(i,1);
}
}
}
Girl.prototype.bindEvent = function() {
var that = this;
that.dom.onclick = function() {
that.isMove = !that.isMove;
}
}
var Girls = [];
// 让数组中的所有女孩运动
setInterval(function() {
for(var i=0; i<Girls.length; i++) {
Girls[i].update();
}
},20);
new Girl();
new Girl();
new Girl();
new Girl();
new Girl();
new Girl();
</script>
</body>
</html>
最后在附上一张小女孩的图片
原型链已讲完,接下来会来讲js对象的一些操作符,如有表达错的请谅解,并请提出指出,且修改错误,望能共同进步。