(转)【javascript基础】原型与原型链
2014-01-28 17:43
357 查看
原文地址:http://www.cnblogs.com/allenxing/p/3527654.html
前言
原型是什么
理解原型对象
原型对象
isPrototypeOf
hasOwnProperty
属性查找
重写原型对象
原型动态性
原生对象的原型
小结
看来,是这的有这么一个属性,可以看出是一个对象,但是默认的是一个空的对象,既然是一个对象,那我们就可以给它添加属性和方法喽,试试看
View Code
我们使用了Object原型中的方法,我们再一次猜对了。现在我们把上面的图补充完整
现在就完整了,这就是这个例子的完整原型图形。我们以前说过,所有的应用类型都是继承Object,所有函数的默认原型都是Object的实例,因此默认原型都包含一个默认指针指向Object.prototype。这就是我们所说的原型链,继承就是通过原型链实现的,这就是所有的自定义类型都会继承toString()和valueOf()等默认方法的根本原因。Object是所有引用类型的父类,可以这么理解。
我们思考一下,上面的代码test.prorotype现在已经指向了一个新的对象,已经不是原来那个默认的原型对象了,原来的默认原型对象我们之前只是添加属性并没有重写它,所有他的内部属性还是存在了,现在我们重写了这个对象,即prototype指向了一个新的对象了,那他原来的属性constructor就没有了,如果我们以后会使用这个属性,那我们应该人为的设置,例如
我们一般的时候肯定是先设置原型在创建实例,这在任何情况下都是没有问题的。我们创建实例是在给原型添加属性之后,即使这样我们也可以在实例中使用这个属性,这就是原型的动态性。这是由于在原型中查找值的过程是一次搜索,所有你修改的属性可以立即在实例中得到体现。但是重写一个函数的原型就不是这样了,看例子
出现了错误,也就是我先创建了一个实例,在重写函数的原型对象这是不行的。原因是这样的,由于实例中的__proto__指针只是指向原型,而不是构造函数,上面的这段代码中,我们创建实例的时候,这个实例中的__proto__指向的是函数的默认原型对象,当我们重写了这个函数的原型对象时,虽然函数的prototype属性指向了新的对象,但是实例中的已经创建好了,它__proto__并没有改变,这个属性还是指向的是默认的原型对象,所有它的内部没有这个方法。但是如果在重写原型之后创建一个实例的话,这个新的实例的__proto__指向的就是新的原型对象了,像这样
我们扩展一个Array类型,增加一个函数contains(),判断数组中是否包含一个值
这就成了。
PS:给大家截一个图大家看看,不懂的可以在下面讨论下
前言
原型是什么
理解原型对象
原型对象
isPrototypeOf
hasOwnProperty
属性查找
重写原型对象
原型动态性
原生对象的原型
小结
前言
荒废了好几天,在宿舍闷了几天了,一直想着回家放松,什么也没搞,论文就让老师催吧。不过,闲的没事干的感觉真是不好,还是看看书,写写博客吧,今天和大家说说函数的原型。原型是什么
第一次看到这个的时候,没太理解这个概念,其实也就是一个概念呗,没啥神秘的。书上说每个函数都有一个prototype属性(原型属性),这个属性是一个指针,指向一个对象(原型对象),这个对象包含这个函数创建的实例的共享属性和方法。也就是说原型对象中的属性和方法是所有实例共享的,打住,那我们就先创建一个函数看看,原型是什么东东var test = function(){} console.log(test.prototype);//Object {}
看来,是这的有这么一个属性,可以看出是一个对象,但是默认的是一个空的对象,既然是一个对象,那我们就可以给它添加属性和方法喽,试试看
var test = function test(){} test.prototype.name = "hainan"; test.prototype.age = "25"; test.prototype.getName = function(){console.log(this.name);} var o1 = new test(); console.log(o1.toString());
View Code
我们使用了Object原型中的方法,我们再一次猜对了。现在我们把上面的图补充完整
现在就完整了,这就是这个例子的完整原型图形。我们以前说过,所有的应用类型都是继承Object,所有函数的默认原型都是Object的实例,因此默认原型都包含一个默认指针指向Object.prototype。这就是我们所说的原型链,继承就是通过原型链实现的,这就是所有的自定义类型都会继承toString()和valueOf()等默认方法的根本原因。Object是所有引用类型的父类,可以这么理解。
isPrototypeOf
使用方法a.isprototypeOf(b),判断对象a是否是实例b__proto__指向的原型对象,如果是返回true,否则返回false。看个例子var test = function test(){} test.prototype.name = "hainan"; test.prototype.age = "25"; test.prototype.getName = function(){console.log(this.name);} var o1 = new test(); console.log(test.prototype.isPrototypeOf(o1));//true
hasOwnProperty
这个方法是检测一个属性是否存在实例中,存在原型中会返回false,看例子var test = function test(){} test.prototype.name = "hainan"; test.prototype.age = "25"; test.prototype.getName = function(){console.log(this.name);} var o = new test(); console.log(o.hasOwnProperty("name"));//false o.name = "xing";//给实例添加属性 console.log(o.hasOwnProperty("name"));//true
属性查找
对象实例可以访问保存在原型中的值,但是不能重写原型中的值。每次要读取某一个属性时,都会执行一次搜索:首先在对象本身开始查找,如果查找到了就返回这个属性,如果没有找到,则继续搜索__proto__指向的原型对象,如果还没有找到,则继续搜索原型对象中__proto__指向的原型对象,这样一直迭代下去,这就是原型链的作用。看例子var test = function test(){} test.prototype.name = "hainan"; test.prototype.age = "25"; test.prototype.getName = function(){console.log(this.name);} var o = new test(); console.log(o.name);//hainan o.name = "xing";//给实例添加属性 console.log(o.name);//xing delete o.name;//删除实例的name属性 console.log(o.name);//hainan
重写原型对象
我们已经知道怎么给一个原型对象添加属性和方法,但是大家都会想到一个简单地方法来一起添加,就像这样var test = function test(){} test.prototype = { name : "hainan", age : "25", getName : function(){return this.name} }; var o = new test(); o.getName();//"hainan" console.log(o.constructor == test);//false
我们思考一下,上面的代码test.prorotype现在已经指向了一个新的对象,已经不是原来那个默认的原型对象了,原来的默认原型对象我们之前只是添加属性并没有重写它,所有他的内部属性还是存在了,现在我们重写了这个对象,即prototype指向了一个新的对象了,那他原来的属性constructor就没有了,如果我们以后会使用这个属性,那我们应该人为的设置,例如
var test = function test(){} test.prototype = { constructor : test, name : "hainan", age : "25", getName : function(){return this.name} }; var o = new test(); o.getName();//"hainan" console.log(o.constructor == test);//true
原型动态性
看个例子先var test = function test(){} var o = new test(); test.prototype.name = "hainan"; console.log(o.name);
我们一般的时候肯定是先设置原型在创建实例,这在任何情况下都是没有问题的。我们创建实例是在给原型添加属性之后,即使这样我们也可以在实例中使用这个属性,这就是原型的动态性。这是由于在原型中查找值的过程是一次搜索,所有你修改的属性可以立即在实例中得到体现。但是重写一个函数的原型就不是这样了,看例子
var test = function test(){} var o = new test(); o.getName();//TypeError: Object #<test> has no method 'getName' test.prototype = { constructor : test, name : "hainan", age : "25", getName : function(){return this.name} };
出现了错误,也就是我先创建了一个实例,在重写函数的原型对象这是不行的。原因是这样的,由于实例中的__proto__指针只是指向原型,而不是构造函数,上面的这段代码中,我们创建实例的时候,这个实例中的__proto__指向的是函数的默认原型对象,当我们重写了这个函数的原型对象时,虽然函数的prototype属性指向了新的对象,但是实例中的已经创建好了,它__proto__并没有改变,这个属性还是指向的是默认的原型对象,所有它的内部没有这个方法。但是如果在重写原型之后创建一个实例的话,这个新的实例的__proto__指向的就是新的原型对象了,像这样
var test = function test(){} test.prototype = { constructor : test, name : "hainan", age : "25", getName : function(){return this.name} }; var o = new test(); o.getName();//"hainan"
原生对象的原型
原生对象和我们自定义对象一样,都存在原型,原生对象的方法都存在原型中,这样我们创建一个新的对象实例时,这些对象就会拥有这些方法,当然我们可扩展原型对象,这样我们以后new出来的原型对象的实例就会共享这个方法或属性了。console.log(String.prototype.slice);//function
我们扩展一个Array类型,增加一个函数contains(),判断数组中是否包含一个值
Array.prototype.contains = function(){ var length = arguments.length; if(length != 1) return; for(var i=0;l=this.length,i<l;++i ){ if(arguments[0] === this[i]) return true; } return false; } var arr = [1,2,3]; console.log(arr.contains(1));//true console.log(arr.contains(4));//false
这就成了。
PS:给大家截一个图大家看看,不懂的可以在下面讨论下
小结
就先写到这吧,大家有不懂的可以在下面讨论吧,我不懂的话我再去问大神,大伙要是觉得写得乱的话推荐去看看《javascript高级程序设计》,那上面写得比较好。小伙伴们都要回家了吧,提前祝大家春节快乐,马上有钱,立马变土豪。相关文章推荐
- 【javascript基础】原型与原型链
- JavaScript基础之原型对象和原型链
- Javascript基础(三)原型和原型链
- JavaScript原型和原型链
- 你不知道的javascript之JS原型对象和原型链
- JavaScript原型继承之基础机制(转)
- JavaScript探秘:强大的原型和原型链
- 跟我学习javascript的prototype原型和原型链
- javascript面向对象基础 工厂与原型
- 深入理解JavaScript的原型和原型链
- 1.JavaScript深入之从原型到原型链
- JavaScript基础之继承与原型链
- JavaScript的原型与原型链
- JavaScript基础(12.面向对象及原型简介)
- 深入理解JavaScript系列 ----(5):强大的原型和原型链
- 【javascript基础】4、原型与原型链
- 深入理解JavaScript系列(5):强大的原型和原型链
- javascript基础修炼(1)——一道十面埋伏的原型链面试题
- java基础64 JavaScript中的Arrays数组对象和prototype原型属性(网页知识)
- 三张图搞懂JavaScript的原型对象和原型链