*今天总结一下JavaScript的prototype原型和*____proto____原型链,了解这俩对我们深刻理解 js ,封装常用小技巧很有帮助。
ES5中js本身是没有类的,在ES5中js类就是函数function,而function本身也是对象。
一、js中的继承是通过原型链 __proto__来实现的,对象与对象以及原型prototype(也是对象)就是通过__proto__原型链来来链接的,具体过程我们来上代码说明。
function obj (name){
this.name=name,
this.age="23"
this.fun=function(){
return this.name
};
obj.prototype.city="china";
};
obj.prototype.fun1=function(){
return this.age;
};
var obj1= new obj("laowang");
var obj2= nwe obj("hello");
这一段代码格式应该很常见,不过有个问题,var obj1 =new obj(“laowang”)是在全局作用域中的,如果页面这种写法比较多 ,很容易勿让污染全局。
可以写成这样:
(function(){
var obj1 = new obj("laowang");
//这样也能正常运行,而且不被污染全局环境
})()
回到正题, 当我们执行 执行下列代码时:
obj1.name; //结果 laowang
obj1.city; //结果 China
obj1.fun(); //结果 laowang
obj1.fun2(); //结果 23
我们会看到 obj1 拥有了obj 的属性和方法,也拥有了obj原型的方法。
分析:obj目前有name 和age 私有属性和fun的私有方法,我们在obj原型上添加了 city属性,和fun1方法
obj.prototype.city="china";
obj.prototype.fun1=function(){
return this.age;
};
而我们用new创建的构造函数,并赋给对象obj1,这个过程js为我们做了类似:(此处代码仅说明道理)
var obj1= (function(){
var o={}; //创建一个新对象
o.__proto__=obj.prototype; //将新对象的原型链指向obj的原型
obj.call(o,"hello") //执行obj函数,将o对象指针指向obj函数,及o拥有了obj原型的属性和方法(引用)
return o;
})()
//我们可以尝试一下,
obj1.__proto__===obj.prototype
// 结果true (__proto__非标准IE不支持,标准Object.getPrototypeOf()方法)
说明obj1的原型链指向obj的原型
__proto__
方法非获取实例原型的标准方法,标准方法请使用Object.getPrototypeOf()
来获取实例原型
obj1.name===obj2.name //结果 true 说明obj1和obj2共同引用obj的属性name
需要说明一点,用new构造的函数,是没有原型的 例如:
obj1.prototype //结果 underfind 证实了我们的猜想
二、上面的说完了,但是还有个问题,如果我想创建一个函数myObj;让该函数拥有obj原型的方法和属性该怎么办。
1.首先你可能会这样做:
var myObj = function (){};
myObj.prototype=obj.prototype;
myObj.city //结果 underfind
这是因为 myObj的原型中的__proto__指向了obj的原型。myObj并没有实现继承obj的原型方法和属性, 并且还会带来一个问题是,当你修改myObj原型中的属性(city)或方法( fun1)时,obj1和obj2中 属性(city)和方法(fun1)也会跟着改变。
2.或者你有这样改了:
myObj.__proto__=obj.prototye
但是带来的问题是 __proto__
是不标准的,在ie和火狐上有时会报错。
3.正确的写法应该这样写:
Object.creat=function (aa) {
var o = function(){}; //创建新函数
o.prototype=aa; //让该函数的原型等于obj的原型
return new o(); //返回一个o的构造函数
}
myObj.prototype=Object.creat(obj.prototye);
// 让函数的原型等与Objet.creat对象,
此时myObj的原型对象就拥有了obj的原型方法和属性,并且当myObj的原型属性和方法改变是 ,不会影戏obj原型的属性和方法
但是此时还有几个问题:
1. myObj.prototype.constructor 返回的是实例obj,本身constructor是原型中指向自己的实例的,而此时,myObj.prototype.constructor和obj.prototype.constructor都指向实例obj;
2. myObj.city 结果会是 underfind; 我们只能通过访问 myObj的原型去访问city属性;
3. 如果第二个问题解决了,我们会发现myObj.fun1(); 结果是underfind;
好下来咱们一个一个解决
第一个问题:我们可以这样
myobj.prototype.constructor=myObj; //让myObj的原型constructor指向myObj本身。
第二个问题:我们可以这样:
var ob= new myobj(); //在用 new 创建一个新实例。
第三个问题:我们可以这样:
var myObj = function () {
obj.call(this); //解决ob.fun1() underfind
};
好了问题基本解决了,最后我放上所有代码
function obj (name){
this.name=name,
this.age="23"
this.fun=function(){
return this.name
};
obj.prototype.city="china";
};
obj.prototype.fun1=function(){
return this.age;
};
var obj1= new obj("laowang");
var obj2= new obj("hello");
// new构造函数内的操作(代码仅说明)
// obj1=(function(){
// var o={};
// o.__proto__=obj.prototype;
// obj.call(o,"hello")
// return o;
// })();
var myObj = function () {
obj.call(this); //解决ob.fun1() underfind
};
Object.create=function(aa){
var o = function(){};
o.prototype=aa;
return new o();
}
myObj.prototype=Object.create(obj.prototype);
// 纠正myObj原型的constructor的指向
myobj.prototype.constructor=myObj;
// 解决用ob.city直接访问
var ob= new myobj();
好了,到这里就结束了,,如果有什么错误,欢迎留言指点。