JavaScript面向对象编程之prototype对象

来源:互联网 发布:微信打不开淘宝链接 编辑:程序博客网 时间:2024/05/21 19:30

1.同一个构造函数的对象实例之间,无法共享属性。

function Cat(name){        this.name=name;        this.eat=function(){console.log("eat");}}var cat1=new Cat('a');var cat2=new Cat('b');console.log(cat1.eat===cat2.eat);//false//每新建一个实例会新建一个eat方法。这既没有必要,又浪费系统资源,因为所有eat方法都是同样的行为,完全应该共享。

2.A对象继承B对象,B对象是A对象的原型对象,A对象是B对象的派生对象。

3.所有对象都有构造函数,所有函数都有prototype属性,所以所有对象都有自己的原型对象,只有null对象没有原型对象。

4.原型对象的所有属性和方法,都能被派生对象共享。

5.每个构造函数都有一个prototype属性,通过构造函数生成实例对象时,实例对象的原型对象是这个prototype属性。

function Cat(name){    this.name=name;}Cat.prototype.color='white';var cat1=new Cat('a');var cat2=new Cat('b');console.log(cat1.color);//whiteconsole.log(cat1.color==cat2.color);//true

实例对象没有color属性,就会去读原型对象的color属性,如果实例对象有color属性,就不会去读原型对象的color属性。

function Cat(name){        this.name=name;        this.eat=function(){console.log("eat");}    }    Cat.prototype.color='white';    var cat1=new Cat('a');    var cat2=new Cat('b');    cat1.color='black';    console.log(cat1.color);//black    console.log(cat1.color==cat2.color);//false

6.原型链
所有对象都可以追溯到Object.prototype,即Object构造函数的prototype属性,Object.prototype的原型是null对象,null对象没有原型对象。

7.原型链的作用是:读取对象的某个属性时,JavaScript引擎先寻找对象本身的属性,如果找不到,就去它的原型对象上找,如果还是找不到,就到原型的原型上找,直到Object.prototype还是找不到,就返回undefined

8.如果对象和原型有同名属性,优先读取对象上的属性,这叫覆盖。

9.如果某个函数的prototype属性指向一个数组,那么该函数可以当做数组的构造函数,因为它的实例对象都可以调用数组方法。

function My(){}My.prototype=new Array;var a=new My;a.push(1,2);console.log(a);//[1,2]console.log(a instanceof Array);//true//instanceof运算符用于判断一个对象是否是某个构造函数的实例

10.某个属性是原型链上哪个对象自身的属性

function getDefiningObject(obj,key){    if(obj&&!{}.hasOwnProperty.call(obj,key)){        obj=Object.getPrototypeOf(obj);    }    return obj;}

11.prototype对象有一个constructor属性,默认指向构造函数。能够分辨实例对象属于哪个构造函数。

function Func(){}var a=new Func();console.log(a.constructor);console.log(a.constructor===Func.prototype.constructor);console.log(a.hasOwnProperty('constructor'));//function Func(){}//true//false

有了constructor属性,就可以从实例新建另一个实例。

function Func(){}var a=new Func();var b=new a.constructor();console.log(a instanceof Func);

修改prototype对象的时候,导致constructor指向改变,导致instanceof失真。

//constructor指向改变function Super() {}function Sub() {}Sub.prototype= new Super();console.log(Sub.prototype.constructor);//Supervar sub=new Sub();console.log(sub.constructor);//Superconsole.log(sub instanceof Super);//trueconsole.log(sub instanceof Sub);//truefunction Super() {}function Sub() {}Sub.prototype= new Super();Sub.prototype.constructor=Sub;//校正console.log(Sub.prototype.constructor);//Subvar sub=new Sub();console.log(sub.constructor);//Subconsole.log(sub instanceof Super);//trueconsole.log(sub instanceof Sub);//true//instanceof失真function A() {}var a = new A();console.log(a instanceof A );//truefunction B() {}A.prototype = B.prototype;//修改了A.prototypeconsole.log(a instanceof A );//false,instanceof失真console.log(a.constructor);//function A(){}

修改原型对象时,一般要同时校正constructor属性的指向。
避免完全覆盖掉原来的prototype属性。

通过name属性,可以从实例得到构造函数的名称。

function func(){}var a=new func();console.log(a.constructor.name);

12.instanceof运算符
判断是否为该构造函数的实例。运算实质:检查右边构造函数的prototype对象是否在左边对象的原型链上。
instanceof运算符的另一个用处,是判断值的类型。instanceof运算符只能用于对象,不适用原始类型的值。

var a=[1,2,3];var obj={};console.log(a instanceof Array);//trueconsole.log(a instanceof Object);//trueconsole.log(obj instanceof Array);//falseconsole.log(obj instanceof Object);//trueconsole.log(null instanceof Object); // falseconsole.log(undefined instanceof Object); // falseundefinednull不是对象var string="hello";console.log(string instanceof String);//false,因为字符串不是对象

13.Object.getPrototypeOf():返回对象的原型

console.log(Object.getPrototypeOf({}));//Objectconsole.log(Object.getPrototypeOf({})===Object.prototype);//trueconsole.log(Object.prototype.isPrototypeOf({}));//true

14.Object.setPrototypeOf():为现有对象设置原型对象,返回一个新对象

var a={x:2};var b=Object.setPrototypeOf({y:1},a);console.log(b.x,b.y);//2 1

15.Object.create():从原型对象生成新的实例对象,可以代替new命令

var obj={x:1};var a=Object.create(obj);console.log(a.x);//1

老式浏览器不支持Object.create()

if(typeof Object.create !=='function'){    Object.create=function(o){        function F(){}        F.prototype=o;        return new F();    }}

下面三种生成新对象的方法是等价的:

var obj1=new Object();var obj2=Object.create({});var obj3=Object.create(Object.prototype);

创建一个不继承任何属性方法的对象:

var o=Object.create(null);//继承null对象,不继承Object.prototype

Object.create()可以传入第二个参数,为新创建的对象添加属性

var obj={x:1};var a=Object.create(obj,{    p1:{value:1,enumerable:true},    p2:{value:2,enumerable:true},});console.log(a.x,a.p1,a.p2);//1 1 2

15.Object.prototype.isPrototypeOf():判断是否在原型链上

var o1={};var o2=Object.create(o1);console.log(Object.prototype.isPrototypeOf(o1));//trueconsole.log(o1.isPrototypeOf(o2));//truevar str=new String('123');console.log(Object.prototype.isPrototypeOf(str));//trueconsole.log(Object.prototype.isPrototypeOf('123'));//false

16.Object.prototype.__proto__:可以改写原型对象

var o={};var a={};a.__proto__=o;console.log(o.isPrototypeOf(a));//true

根据语言标准,proto属性只有浏览器才需要部署,其他环境可以没有这个属性,而且前后的两根下划线,表示它本质是一个内部属性,不应该对使用者暴露。因此,应该尽量少用这个属性,而是用Object.getPrototypeof()(读取)和Object.setPrototypeOf()(设置),进行原型对象的读写操作。
17.获取原型对象的方法:推荐第三种
obj.__proto__
obj.constructor.prototype
Object.getPrototypeOf()

1 0
原创粉丝点击