1.使用构造函数获取原型属性
//构造函数 function Box(name,age){ this.name = name;//实例属性 this.age = age; this.run = function(){//实例方法 return this.name+this.age+'运行中...'; } } var box1 = new Box(); var box2 = new Box(); console.log(box1.name); console.log(box1.run()); console.log(box1.run==box2.run); console.log(box1.prototype);//这个属性是一个对象,访问不到 console.log(box1.__proto__);//这个属性是一个指针指向prototype原型对象 console.log(box1.constructor);//构造属性,可以获取构造函数本身 console.log(box1.constructor==Box);//true console.log(Box.prototype);//使用构造函数名访问prototype
2.判断一个对象是否指向了该构造函数的原型对象,可以使用isPrototypeOf方法来测试
function Box(){}//声明一个构造函数 构造函数体内什么都没有,如果有,叫做实例属性,实例方法 Box.prototype.name = 'Lee'; Box.prototype.age = 100; Box.prototype.run = function(){ return this.name+this.age+'运行中....'; }; var box1 = new Box(); var box2 = new Box(); console.log(box1.run==box2.run);//true 方法的引用地址保持一致 //判断一个对象是否指向了该构造函数的原型对象,可以使用isPrototypeOf方法来测试 console.log(Box.prototype.isPrototypeOf(box1));//true
可以使用hasOwnProperty判断实例中是否存在指定的属性;关于in的使用 不管实例属性或原型属性是否存在,只要有就返回true,两边都没有,返回false。
综合使用hasOwnProperty和in可以判断出某属性是否仅存在于原型中。
使用delete可以删除实例中或原型中的属性。
function Box(){}//声明一个构造函数 构造函数体内什么都没有,如果有,叫做实例属性,实例方法 Box.prototype.name = 'Lee'; Box.prototype.age = 100; Box.prototype.run = function(){ return this.name+this.age+'运行中....'; }; var box1 = new Box(); var box2 = new Box(); console.log(box1.run==box2.run);//true 方法的引用地址保持一致 //判断一个对象是否指向了该构造函数的原型对象,可以使用isPrototypeOf方法来测试 console.log(Box.prototype.isPrototypeOf(box1));//true //原型模式的执行流程: //1.先查找构造函数实例里的属性或方法,如果有,立即返回 //2.如果构造函数实例里没有,则去他的原型对象里找,如果有,就返回 console.log(box1.name);//Lee 原型里的值 //判断实例中是否存在指定的属性 console.log(box1.hasOwnProperty('name'));//false name存在于原型中 box1.name = 'Jack';//实例属性,没有重写原型属性 //判断实例中是否存在指定的属性 console.log(box1.hasOwnProperty('name'));//true name在实例属性中能够找到 //关于in的使用 不管实例属性或原型属性是否存在,只要有就返回true,两边都没有,返回false console.log('name' in box1);//true 存在实例中或原型中 console.log(box1.name);//Jack 就近原则 console.log(box2.name);//Lee 原型里的值,没有被box1修改 delete box1.name;//删除实例中的属性 console.log(box1.name);//Lee 原型属性 //delete Box.prototype.name;//删除原型中的属性 //console.log('name' in box1);//false name在实例中或原型中都不存在 Box.prototype.name = 'kkk';//覆盖原型中的属性 console.log(box1.name);//kkk console.log(box1.hasOwnProperty('name'));//false name存在于原型中 //判断只有原型中存在属性 function isProperty(obj,property){ return !obj.hasOwnProperty(property)&&(property in obj); } console.log(isProperty(box1,'name'));//true name只在原型中 box1.name = 'Jack';//实例属性,没有重写原型属性 console.log(isProperty(box1,'name'));//false name不只存在于原型中,实例中也有
4.关于原型的重写
function Box(){}//声明一个构造函数 构造函数体内什么都没有,如果有,叫做实例属性,实例方法 Box.prototype.name = 'Lee'; Box.prototype.age = 100; Box.prototype.run = function(){ return this.name+this.age+'运行中....'; }; var box1 = new Box(); console.log(box1.prototype);//使用对象实例无法访问到prototype console.log(box1.__proto__);//使用对象实例访问prototype的指针 console.log(Box.prototype);//使用构造函数名访问prototype console.log(box1.constructor==Box);//true //重写了原型对象 Box.prototype={ age:20//这里不会保留之前原型的任何信息了 }; console.log(box1.name);//Lee console.log(box1.run());//正常打印 box1 = new Box(); console.log(box1.name);//undefined //console.log(box1.run());//报错 console.log(box1.age);//20
字面量创建的方式使用constructor属性不会指向实例,而会指向Object,构造函数创建的方式则相反
//为了让属性和方法更好地体现封装的效果,并且减少不必要的输入,原型的创建可以使用字面量的方式 function Box(){} Box.prototype={//使用字面量的方式 name:'Lee', age:100, run:function(){ return this.name+this.age+'运行中....'; } }; var box = new Box(); console.log(box instanceof Box);//true console.log(box instanceof Object);//true //使用构造函数创建原型对象和使用字面量创建原型对象的区别 //字面量创建的方式使用constructor属性不会指向实例,而会指向Object,构造函数创建的方式则相反 console.log(box.constructor==Box);//false console.log(box.constructor==Object);//true
6.如果想让字面量方式的constructor指向实例对象,可以加上constructor:Box
//如果想让字面量方式的constructor指向实例对象,可以加上constructor:Box function Box(){} Box.prototype={//使用字面量的方式 constructor:Box,//强制指向Box name:'Lee', age:100, run:function(){ return this.name+this.age+'运行中....'; } }; var box = new Box(); console.log(box instanceof Box);//true console.log(box instanceof Object);//true //使用构造函数创建原型对象和使用字面量创建原型对象的区别 //字面量创建的方式使用constructor属性不会指向实例,而会指向Object,构造函数创建的方式则相反 console.log(box.constructor==Box);//true console.log(box.constructor==Object);//false
7.ECMAScript内置的引用类型本身也使用了原型
//ECMAScript内置的引用类型本身也使用了原型 console.log(Array.prototype.sort);//查看sort是否是Array原型对象里的方法 console.log(String.prototype.substring); String.prototype.addstring = function(){ return this+',被添加了!';//this代表调用的字符串 } console.log('Lee'.addstring());
原型最大的优点就是共享,原型中的属性被很多实例共享。但是,如果属性包含引用类型,就存在问题。
//原型模式创建对象有自己的缺点,他省略了构造函数传参初始化过程,带来的缺点就是初始化的值都是一致的。 //最大的优点就是共享,原型中的属性被很多实例共享。但是,如果属性包含引用类型,就存在问题 function Box(){} Box.prototype={//使用字面量的方式 constructor:Box,//强制指向Box name:'Lee', age:100, family:['父亲','母亲','妹妹'],//添加了一个数组属性 run:function(){ return this.name+this.age+this.family; } }; var box1 = new Box(); box1.family.push('哥哥');//在第一个实例修改了引用剋行,保持了共享 console.log(box1.run()); var box2 = new Box(); console.log(box2.run());//共享了box1添加后的引用类型的原型
//为了解决构造传参和共享问题,可以使用组合构造函数+原型模式 function Box(name,age){//不共享的使用构造函数 this.name = name; this.age = age; this.family=['父亲','母亲','妹妹']; } Box.prototype={//共享的使用原型模式 constructor:Box,//强制指向Box run:function(){ return this.name+this.age+this.family; } }; var box1 = new Box(); box1.family.push('哥哥'); console.log(box1.run()); var box2 = new Box(); console.log(box2.run());//引用类型没有使用原型,所以没有共享
为了解决这一问题,可以将构造函数和原型封装在一起,称为动态原型模式。
//原型模式,不管你是否调用了原型中的共享方法,他都会初始化原型中的方法 //为了解决这一问题,可以将构造函数和原型封装在一起,称为动态原型模式 function Box(name,age){//不共享的使用构造函数 this.name = name; this.age = age; this.family=['父亲','母亲','妹妹']; if(typeof this.run!='function'){//判断run方法是否存在,仅在嗲一次调用时初始化 console.log('第一次初始化');//只会运行1次 Box.prototype.run = function(){ return this.name+this.age+this.family; }; } } var box1 = new Box(); box1.family.push('哥哥'); console.log(box1.run()); var box2 = new Box(); console.log(box2.run());//引用类型没有使用原型,所以没有共享 //使用动态原型模式要注意,不可以使用字面量方式重写原型
寄生构造函数=工厂模式+构造函数模式
//关于寄生构造函数=工厂模式+构造函数模式 function Box(name,age){ var obj= new Object(); obj.name = name; obj.age = age; obj.run = function(){ return this.name+this.age+'运行中...'; }; return obj; } var box1 = new Box('Lee',100); var box2 = new Box('Jack',200); console.log(box1.run()); console.log(box2.run()); //假如要创建一个具有额外方法的引用类型,比较适合使用寄生构造函数 function myString(string){ var str = new String(string); str.addstring = function(){ return this+',被添加了!'; } return str; } var box = new myString('Lee'); console.log(box.addstring());
这种创建方式叫做稳妥构造函数,与寄生构造函数类似。
//在一些安全的环境中,比如禁止使用this和new,即构造函数里不使用this,外部实例化构造函数时不适用new //这种创建方式叫做稳妥构造函数,与寄生构造函数类似 function Box(name,age){ var obj= new Object(); obj.run = function(){ return name+age+'运行中...'; }; return obj; } var box1 = Box('Lee',100); console.log(box1.run());