JavaScript面向对象编程之prototype对象

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);//white
console.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);//Super
var sub=new Sub();
console.log(sub.constructor);//Super
console.log(sub instanceof Super);//true
console.log(sub instanceof Sub);//true

function Super() {}
function Sub() {}
Sub.prototype= new Super();
Sub.prototype.constructor=Sub;//校正
console.log(Sub.prototype.constructor);//Sub
var sub=new Sub();
console.log(sub.constructor);//Sub
console.log(sub instanceof Super);//true
console.log(sub instanceof Sub);//true

//instanceof失真
function A() {}
var a = new A();
console.log(a instanceof A );//true
function B() {}
A.prototype = B.prototype;//修改了A.prototype
console.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);//true
console.log(a instanceof Object);//true
console.log(obj instanceof Array);//false
console.log(obj instanceof Object);//true
console.log(null instanceof Object); // false
console.log(undefined instanceof Object); // falseundefinednull不是对象
var string="hello";
console.log(string instanceof String);//false,因为字符串不是对象

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

console.log(Object.getPrototypeOf({}));//Object
console.log(Object.getPrototypeOf({})===Object.prototype);//true
console.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));//true
console.log(o1.isPrototypeOf(o2));//true
var str=new String('123');
console.log(Object.prototype.isPrototypeOf(str));//true
console.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()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值