您的位置:首页 > Web前端 > JavaScript

JavaScript的原型原型链的深刻理解及运用

2017-03-25 19:24 567 查看
*今天总结一下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();   //结果  laowan
4000
g
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();


好了,到这里就结束了,,如果有什么错误,欢迎留言指点。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: