JavaScript学习之路<十二> JS面向对象程序设计--原型深入

时间:2022-11-16 19:40:57
sdf

//ECMA5新特性 Object.getPrototypeOf(): 根据实例对象获得原型对象

function Person(){}

Person.prototype.name = 'z3';
Person.prototype.age = 20;
Person.prototype.sayName = function(){alert('我是原型对象方法!');};

var p1 = new Person();
//alert(p1.name);//z3

var prototypeObj = Object.getPrototypeOf(p1);
//alert(prototypeObj == Person.prototype);//true

//每次代码读取一个对象属性的时候:首先会进行一次搜索:搜索实例对象里name的属性,看看有没有,如果没有
//再去p2的实例所对应的原型对象里去搜索name属性,如果有就返回,没有返回undefined
var p2= new Person();
p2.name = 'w5';//实例对象的name
//alert(p2.name);//w5 但是我就想获得原型对象的属性 delete p2.name即可

//判断一个对象的属性是属于原型属性还是属于实例属性
var p3 = new Person();
//alert(p3.name);//z3
//alert(p3.hasOwnProperty('name'));//false

//in 操作符: for-in
//判断属性是否存在于实例对象和原型对象中
var p1 = new Person();
alert('name' in p1);//true
var p2 = new Person();
p2.name = 'w3';
//alert('name' in p2);//true

//就是判断一个属性是否存在原型中】
//在原型对象中 是否存在这个属性 第一个参数:当前对象 第二个参数:要判断的属性
/* function hasPrototypeProperty(object,name){
return !object.hasOwnProperty(name) && name in object;
}

var p3 = new Person();
alert(hasPrototypeProperty('p3','name'));//true */

//ECMA5新特性 Object.keys();拿到当前对象所有属性,返回一个数组
var p4 = new Person();
p4.name = 'z3';
p4.age = 20;
var attr = Object.keys(p4);
alert(attr);//name,age
var attr2 = Object.keys(Person.prototype);
alert(attr2);//name,age,sayName

//ECMA5新特性 constructor属性:该属性是不能被枚举的
//Object.getOwnPropertyNames 枚举对象所有属性:不管该内部属性能否被枚举
var attr3 = Object.getOwnPropertyNames(Person.prototype);
alert(attr3);//constructor,name,age,sayName


2、原型对象的另外一个作用就是扩展对象中的属性和方法-----模拟Array中each循环方法

<script type="text/javascript" charset="utf-8">

//Array数组 each方法

//ECMA5 forEach方法 循环遍历数组 只适合遍历一维数组

/* var arr = [1,2,3,[4,[5]]];
arr.forEach(function(item,index,array){
alert(item);
}); */

//自己实现一个Array each方法 能遍历多维数组
var arr = [1,2,3,[4,[5,[6]]]];

Array.prototype.each = function(fn){

try{

//1、遍历数组的每一项
//计数器 记录当前遍历的元素 位置
this.i || (this.i=0);

//2、什么时候去走each核心方法
//当数组的长度大于0的时候 && 传递的参数必须是函数
if(this.length > 0 && fn.constructor == Function){
//循环遍历数组的每一项
while(this.i < this.length){
//获取数组的每一项
var e = this[this.i];
//当前元素是数组
if(e && e.constructor == Array){
//直接做递归操作
e.each(fn);
}else{
//如果不是数组,那就是单个元素
//目的是为了把数组的当前元素传递给fn函数并让函数执行
fn.apply(e,[e]);//fn.call(e,e);
}
this.i++;
}
this.i = null;//释放内存 垃圾回收机制回收
}

} catch(ex){
//do sth.
}
return this;
};

arr.each(function(item){
alert(item);
});

</script>

//简单原型

//简单原型
function Person(){}

Person.prototype = {
//constructor: Person, //必须得表示原型对象的构造器
name: 'z3',
age: 20,
job: '程序员',
say: function(){
alert('我是原型函数');
}
};

//ECMA5给原型对象重新设置构造器的方法 Object.defineProperty();
//3个参数, 参数1:重设构造器的对象 参数2:设置什么属性 参数3:options配置项
Object.defineProperty(Person.prototype,'constructor',{
enumerable: false,
value: Person
});

var p1 = new Person();
//alert(p1.name);
//p1.say();

alert(Person.prototype.constructor);//function Object{native code}

for(attr in p1){
alert(attr); //name age job say
}

//原型的动态性

//原型的动态性

function Person(){

}

var p1 = new Person();

Person.prototype.say = function(){alert('我是方法');};

p1.say();//我是方法

//但是下面的方式会报错
var p2 = new Person();
Person.prototype = {
constructor: Person,
say: function(){alert('我是方法');}
};
p2.say();//error

//原型弊端

//原型的概念:原型对象里的所有属性和方法 被所有构造函数实例化出来的对象所共享

function Person(){
}

Person.prototype = {
constructor: Person,
name: 'z3',
age: 20,
job: '程序员',
friends: ['lisi','wangwu'],
say: function(){alert('我的名字');}
};

var p1 = new Person();
var p2 = new Person();

p1.friends.push('zhaoliu');

alert(p1.friends);//lisi,wangwu,zhaoliu
alert(p2.friends);//lisi,wangwu,zhaoliu

//原型里的属性和方法 被所有对象所共享:static

//组合模式

//组合使用原型和构造函数式(定义一个类 开发时常用的方式)

function Person(name,age,friends,job){
this.name = name;
this.age = age;
this.friends = friends;
this.job = job;
}

Person.prototype = {
constructor: Person,
sayName: function(){
alert(this.name);
}
};

var p1 = new Person('z3',20,['王五','赵六'],'技术总监');
var p2 = new Person('z4',25,['王五','赵七'],'boss');

alert(p1.friends);//王五,赵六
alert(p2.friends);//王五,赵七

//两种模式

<script type="text/javascript" charset="utf-8">

//动态原型模式: 让你的代码都封装到一起

function Person(name,age,friends,job){
this.name = name;
this.age = age;
this.friends = friends;
this.job = job;

//动态原型模式
if(typeof this.sayName != 'function'){
Person.prototype.sayName = function(){
alert(this.name);
};
}
}

//稳妥构造函数式: durable object(稳妥对象) 非常安全的环境中
//1、没有公共属性 2、不能使用this对象

function Person(name,age,job){
//创建一个要返回的对象
var obj = new Object();
//可以定义一些私有的变量和函数
var name = name;
var sex = 'm';
var saySex = function(){};
//添加一个对外的方法
obj.sayName = function(){
alert(name);
};
return obj;
}

var p1 = new Person('z3');
p1.sayName();//z3
</script>

4、三种继承方式
 <script type="text/javascript" charset="utf-8">

//js中实现继承:采用原型链的概念

//构造函数 原型对象 实例对象

//构造函数.prototype = 原型对象
//原型对象.constructor = 构造函数的(模板)
//原型对象.isPrototypeOf(实例对象) 判断实例对象的原型是不是当前对象
//构造函数 实例对象 (类和实例)

//父类的构造函数
function Sup(name){
this.name = name;
}

//父类的原型对象
Sup.prototype = {
constructor: Sup,
sayName: function(){alert(this.name);}
};

//子类构造函数
function Sub(age){
this.age = age;
}

//如果我们让子类的原型对象等于父类的实例,结果会怎样?(实现了js的继承)
//1、显然此时的原型对象将包含一个指向另一个原型的指针
//sup的实例对象和sup的原型对象有一个关系
//2、相应的另一个原型中也包含着一个指向另一个构造函数的指针
//子类的原型对象的构造器变成了父类的构造器
Sub.prototype = new Sup('z3');
alert(Sub.prototype.constructor);//function Sup(){native code}

var sub1 = new Sub();
alert(sub1.name);//z3
sub1.sayName();//z3 */



//原型继承
//原型继承的特点:即继承了父类的模板,又继承了父类的原型对象
/* //父类
function Person(name,age){
this.name = name;
this.age = age;
}

//父类的原型对象属性
Person.prototype.id = 10;

//子类
function Boy(sex){
this.sex = sex;
}

Boy.prototype = new Person('z3');

var b = new Boy();
alert(b.name);//z3
alert(b.id);//10



//类继承 只继承模板,不继承原型对象

//父类
function Person(name,age){
this.name = name;
this.age = age;
}

//父类的原型对象属性
Person.prototype.id = 10;

//子类
function Boy(name,age,sex){
//call apply
Person.call(this,name,age);
this.sex = sex;
}

var b = new Boy('z3',20,'m');
alert(b.name);//z3
alert(b.age);//20
alert(b.id);//undefined 父类的原型对象并没有继承


//原型继承+借用构造函数继承 = 混合继承

//父类
function Person(name,age){
this.name = name;
this.age = age;
}

//父类的原型对象属性
Person.prototype.id = 10;
Person.prototype.sayName = function(){alert(this.name);};

//子类
function Boy(name,age,sex){
//call apply
Person.call(this,name,age);//1、借用构造函数继承
this.sex = sex;
}

//2、原型继承
//只剩下父类的实例和父类的原型对象的关系了
Boy.prototype = new Person();//继承父类的原型对象

var b = new Boy('z3',20,'m');
alert(b.name);//z3
alert(b.sex);//m
b.sayName();//z3




</script>