原型
概念
在JavaScript中,函数是一个包含属性和方法的Function类型的对象。而原型(Prototype)就是Function类型对象的一个属性。
在函数定义时就包含了prototype属性,它的初始值是一个空对象。在JavaScript中并没有定义函数的原型类型,所以原型可以是任何类型。
原型是用于保存对象的共享属性和方法的,原型的属性和方法并不会影响函数本身的属性和方法。
// Function类型的属性->所有函数都具有的属性 console.log(Function.prototype);//[Function] // 定义函数 function fn() { console.log('this is function'); } //原型的默认值是空对象 console.log(fn.prototype);//fn {} // 函数包含构造函数 ——> 所有引用类型其实都是构造函数 console.log(Number.prototype); //[Number: 0] console.log(Object.prototype);//{} var result = Object.getOwnPropertyDescriptor(Object.prototype,'constructor'); console.log(result) //{ // value: [Function: Object], // writable: true, // enumerable: false, // configurable: true // }
获取原型
通过如下两种方式可以获取对象的原型,从而设置共享的属性和方法:
通过构造函数的prototype属性
通过Object对象的getPrototype(obj)方法。
function fn() { console.log('this is function'); } //使用访问对象的属性语法结构 console.log(fn.prototype);//fn {} console.log(fn['prototype']);//fn {} //Object类型提供getPrototypeOf()方法 console.log(Object.getPrototypeOf(fn));//[Function]
原型的属性和方法
通过如下两种方式可以设置原型的属性和方法:
原型的属性和方法单独进行定义。
构造函数.prototype.属性名 = 属性值 ; 构造函数.prototype.方法名 = function(){} ;
直接为原型定义一个新对象。
构造函数.prototype = { 属性名:属性值, 方法名:function(){} }
function fn() { console.log('this is function'); } // 新增属性或方法 fn.prototype.name = '猪猪侠'; console.log(fn.prototype);//fn { name: '猪猪侠' } // 使用defineProperty()方法 Object.defineProperty(fn.prototype,'age',{ value:18, enumerable:true//控制当前属性可被枚举(遍历) }); console.log(fn.prototype);//fn { name: '猪猪侠', age: 18 }
构造函数原型
// 定义构造函数 function Hero() { this.name = '猪猪侠'; this.sayMe = function () { console.log('我是猪猪侠') } } // 操作构造函数的Hero的原型 Hero.prototype.age = 19; // 利用构造函数方式创建对象 var hero = new Hero(); console.log(hero);//Hero { name: '猪猪侠', sayMe: [Function] // 为构造函数的原型新增的属性:构造函数创建的对象中依旧可以访问 console.log(hero.age);//19 // 访问对象中不存在的属性是结果为undefined,故对象hero中不存在age属性。 var result = Object.getOwnPropertyDescriptor(hero,'age'); console.log(result)//undefined
解析图如下:
自有属性与原型属性
自有属性:通过对象的引用添加的属性。其它对象可能无此属性;即使有,也是彼此独立的属性。
原型属性:从原型对象中继承来的属性,一旦属性对象中属性值改变,所有继承自该原型的对象属性均改变。
如下代码展示了自由属性和原型属性的用法:
// 定义构造函数 function Hero(name) { this.name = name this.sayMe = function () { console.log('我是:'+ name) } } // 通过构造函数Hero的prototype新增属性或方法 //通过原型所定义的属性称为:原型属性 Hero.prototype.age = 19;//此时age就是原型属性 /* 通过构造函数Hero创建对象时 *不仅具有构造函数的自有属性 *还具有构造函数的原型属性 */ // 构造函数方式创建对象hero var hero = new Hero('猪猪侠'); console.log(hero.name);//猪猪侠 console.log(hero.age);//19 var hero2 = new Hero('小菲菲'); console.log(hero2.name);//小菲菲 console.log(hero2.age);//19 /* // 为对象hero新增age属性 hero.age = 80; console.log(hero.age);//80 // hero对象的age属性被修改了 console.log(hero);//Hero { name: '猪猪侠', sayMe: [Function], age: 80 } console.log(hero2.age);//hero2 的age属性值还是19 没改变 ,所以对hero中age属性值的修改对hero2无效 */ // 通过对Hero的原型操作添加age属性 Hero.prototype.age = 30; // 通过对构造函数Hero的原型添加的age属性改变了hero和hero2的age属性值 console.log(hero.age);//30 console.log(hero2.age);//30
重写原型属性
通过构造函数或对象的自有属性可以重写原型的属性,如下代码示例:
// 定义构造函数 function Hero() { this.name = '猪猪侠'; } // 构造函数的原型尝试修改name值 Hero.prototype.name = '超人强'; // 构造函数创建对象 var hero = new Hero(); // 访问hero对象的name属性-- 得出结论:当自有属性与原型属性同名时,默认访问的是自有属性。 // 自有属性的优先级高于原型属性 console.log(hero.name);//猪猪侠 // 删除hero对象的属性 delete hero.name; // 重新访问hero对象的name属性 :得到的是原型属性,另外可以认为是自有属性的默认值。 console.log(hero.name);//超人强
检测自有或原型属性
使用hasOwnProperty()方法检测对象是否具有指定的自有属性。
使用in关键字检测对象及其原型链中是否具有指定属性。
如下代码示例:
// 定义构造函数 function Hero() { // this.name = '猪猪侠'; } // 原型属性添加name属性,hasOwnProperty(prop)方法判断,结果为false. Hero.prototype.name = '超人强'; // 构造函数方式创建对象 var hero = new Hero(); /* 1、使用hasOwnProperty(prop)方法 作用:判断当前属性是否为自有属性 参数: prop : 表示指定属性名称。 返回值: true :表示存在指定的自有属性 false :表示不存在指定的自有属性*/ console.log(hero.hasOwnProperty('name'))//true /* 2、使用in关键字检测对象的属性 作用:判断对象中是否存在指定属性(自有属性或原型属性) 返回值:布尔值 true :表示存在指定的属性。 false 表示不存在指定的属性。 */ console.log('name' in hero);//true
扩展属性或方法
通过原型可以为指定构造函数或对象扩展其属性或方法,如下代码示例:
// 1、定义构造函数 function Hero() {} // 通过构造函数的原型新增属性或方法 /*// 1、利用对象.属性或方法的方式新增属性或方法 Hero.prototype.name = '猪猪侠'; Hero.prototype.sayMe = function () { console.log('我是猪猪侠') }*/ // 2、将原型重新赋值给一个对象 Hero.prototype = { name:'猪猪侠', sayMe : function () { console.log('我是猪猪侠') } } //构造函数方式创建对象 var hero = new Hero(); console.log(hero.name)//猪猪侠 hero.sayMe();//我是猪猪侠 // 由结果得出结论两种方式都可通过构造函数的原型新增属性或方法
解析图: