原型链

原型

什么是原型

每个函数都有一个原型对象(prototype),它是一个属性也是一个指针,指向一个对象。
当所有对象有一共有的属性时,就可以用prototype添加,不用一个一个的重复添加。

Person.prototype.name = "Xiaoming";
Person.prototype.age = 18;
function Person(){
}
var person1 = new Person();

原型的属性

  • constructor:创建了构造函数后,系统默认其对象有constructor属性。这个属性指向原函数。
Person.prototype.constructor == Person;

相应的,在每一个使用构造函数新建的实例中,也存在一个指针,指向构造函数的原型对象。这个指针可以为[[prototype]]或__proto__。

  • isPrototypeOf:确定传入的对象的原型是否是当前的对象。
var result = Person.prototype.isprototypeOf(person1);           //true
  • getPrototypeOf:ES5新添加的属性,可以返回实例对象的原型。
var result = Object.getPrototypeOf(person1);                 //Person.prototype

原型中值的更改

虽然我们能用对象实例去访问对象原型中的值,但是不能使用实例去改变原型中已有的属性和值。

Person.prototype.name = "Xiaoming";
        Person.prototype.age = 18;
        function Person(){ 
        }
        var person1 = new Person();
        var person2 = new Person();

        person1.name = 'Xiaohua';
        console.log(person1.name);

当像这样使用实例强制改变原型中的值时,原型中的值会被覆盖,
这种情况被称为属性遮蔽 (property shadowing)
此时再访问 person1 . name,返回值为‘Xiaohua’;
原有的原型值没有并没有改变。
当delete person1.name时,再次访问person1 . name,返回为‘Xiaoming’;

原型的重写

关于创建原型实例和修改原型的问题。

  1. 当先创建实例,后添加属性值时:
function Person(){ 
        }
var person1 = new Person();
    Person.prototype.name = 'Xiaoming';
    console.log(person1.name);                        //'Xiaoming'

尽管原型赋值在后,但是由于实例与原型松散的连接,所以在寻找person1.name中后从实例找到原型中。所以可以随时给原型添加属性和方法。
2. 当改变重写原型对象时。

function Person(){ 
        }
var person1 = new Person();
Person.prototype = {
            name : 'Xiaoming',          //上面讲到当使用这种方法创建原型时,
            age : 18,                   //会改变原型constructor的指向
            job : 'student'
}
console.log(person1.name);           //因此现在找不到person1.name,返回undefined

原型链

Grand.prototype.lastName = 'Xiaoming';
function Grand(){
}
var grand = new Grand();
Father.prototype = grand;
function Father(){
    this.name = 'Xiaoqiang';
} 
var father = new Father();
son.prototype = father;
function Son(){
    this.hobbit = 'havana';
}
var son = new Son();

由上可以看出原型链的实现方法。
此时原型对象包含一个指向另一个原型的指针,则另一个原型中也包含着一个指向另一个构造函数的指针。当另一个原型又是另一个原型的实例,如此层层递进,就构成原型与实例的链条。
而原型链的终端则是Object.prototype。
简而言之,上面的代码中:Son继承了Father,Father继承了Grand,Grand继承了Object。

  • 虽然绝大多数对象都继承自Object.prototype,但是还是例外。
  • 我们可以构建出不继承自Object的对象
  • 使用Object.create(null)即可

谨慎定义

在原型链中定义方法时,不能使用对象字面量创建原型方法。

function Father(){
    this.name = 'Xiaoming';
} 
var father = new Father();
function Son(){
    this.hobbit = 'havana';
}
son.prototype = father;
//这时添加方法,会切断son和father之间的连接,原型链被切断了
son.prototype = {
    action : function(){
        return 'walk';
    }
}
var son = new Son();

原型链的问题

含有引用值的原型属性会被所有实例共享,这就造成了原型链的缺陷。

function Father(){
    this.TshirtColors = ['red','blue','yellow'];
} 
var father = new Father();
function Son(){
    this.hobbit = 'havana';
}
son.prototype = father;
var son1 = new Son();
var son2 = new Son();
son1.TshirtColors.push('black');
alert(son1.TshirtColors);   //'red','blue','yelllow','black'
alert(son2.TshirtColors);   //'red','blue','yelllow','black'
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值