以前在学习原型(prototype)的时候,一直对原型的理解不是很清晰,只是知道每一个对象都有一个原型,而后在js中万物又皆对象。在这里谈一下本身对于js原型的简单理解吧。数组
原型能够实现属性和方法的共享。函数
原型链理解:性能
假设有一个对象o,其有本身的属性a和b:学习
{a:1,b:2};this
而后o的原型o.[[prototype]]又有本身的属性b和c:prototype
{b:3,c:4};对象
最后,o.[[prototype]].[[prototype]]为null。这就是原型链的末尾,即null,根据定义,null没有[[prototype]]继承
综上,整个原型链以下:ip
{a:1,b:2} ---> {b:3,c:4} ---> null;原型链
console.log(o.a); // 1 a为o的自身属性
console.log(o.b); // 2 b为o的自身属性 可是o.[[prototype]]上面还有个b属性,可是它不会被访问到,这种状况称之为属性遮蔽(property shadowing)
console.log(o.c); // 4 c不是o的自身属性,那看看o.[[prototype]]上面有没有,在o.[[prototype]]上找到了c属性,那么c的值为4
console.log(o.d); // undefined 如今o上面找,没有d属性;再到o.[[prototype]]上面找,也没有;最后到o.[[prototype]].[[prototype]]上面找,
o.[[prototype]].[[prototyoe]]为null,中止寻找,返回undefined。
建立一个对象它本身的属性的方法就是设置这个对象的属性。惟一例外的获取和设置的行为规则就是当有一个 getter或者一个setter 被设置成继承的属性的时候。
继承方法:
JavaScript 并无其余基于类的语言所定义的“方法”。在 JavaScript 里,任何函数均可以添加到对象上做为对象的属性。函数的继承与其余的属性继承没有差异,包括上面的“属性遮蔽”(这种状况至关于其余语言的方法重写)。
当继承的函数被调用时,this 指向的是当前继承的对象,而不是继承的函数所在的原型对象。
var o = {
n:1,
m:function(){
return this.n + 1;
}
};
console.log(o.m()); // 2 当调用m方法时,this指向o;
var p = Object.create(o);
p.n = 10;
console.log(p.m()); // 11 调用m方法时,this指向当前调用它的p;
Object.create()建立一个新对象,新对象的原型就是调用时传入的第一个参数;
因此上面原型链为:
p ---> o ---> Obejct.prototype ---> null;
o继承了Object上面全部的属性和方法;因此对象所具备的属性和方法,o均可以使用;
对象具备hasOwnProperty()属性; 注意:hasOwnProperty() 判断的只是本身是否具备该属性或者方法 继承过来的属性和方法不算自身的;
hasOwnProperty 是 JavaScript 中惟一一个只涉及对象自身属性而不会遍历原型链的方法。
console.log(o.hasOwnProperty('m')); // true; o对象有本身的m方法
console.log(p.hasOwnProperty('m')); // false; p对象没有本身的m方法 它是继承自o的
var arr = [1,'str',true,o];
数组都继承自Array.prototype(indexOf,forEach等方法都是从它继承而来);
原型链以下:
arr ---> Array.prototype ---> Object.prototype ---> null;
function a(b){
return b;
}
函数都继承自Function.prototype(call,bind等方法都是继承而来);
原型链以下:
a ---> Function.prototype ---> Object.prototype ---> null;
使用构造器建立函数:
在js中,构造器其实就是一个简答的函数,当使用new操做符来操做这个函数时,它就能够被称为构造函数(构造方法);
function Person(){
this.eyes = [];
this.hands = [];
}
Person.prototype.addEyes= function(e){
this.eyes.push(e);
}
var p = new Person();
p是生成的对象,它自身有属性'eyes' 和 'hands',在p被实例化的时候,它的原型指向Person.prototype;
在用原型继承编写复杂代码前理解原型继承模型十分重要。同时,还要清楚代码中原型链的长度,并在必要时结束原型链,以免可能存在的性能问题。此外,除非为了兼容新 JavaScript 特性,不然,永远不要扩展原生的对象原型。