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

*今天总结一下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();

好了,到这里就结束了,,如果有什么错误,欢迎留言指点。

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值