19原型
原型
原型是什么
在 Javascript中,函数是一个包含属性和方法的Function类型的对象。而原型( Prototype)就是Function类型对象的一个属性。
在函数定义时就包含了 prototype属性,它的初始值是一个空对象。在 Javascript中井没有定义函数的原型类型,所以原型可以是任何类型。
原型是用于保存对象的共享属性和方法的,原型的属性和方法并不会影响函数本身的属性和方法。
原型的默认值是空对象,所有引用类型都是构造函数,所有函数都具有prototype
属性。
1 | // Function 类型的属性 -> 所有函数都具有的属性 |
获取原型
获取原型的方式有两种
使用访问对象的属性语法结构
1 | function fn() { |
Object类提供的getPrototype()方法
1 | function fn() { |
第二种方式中,在nodejs环境中会打印[Function]
而在浏览器会打印ƒ () { [native code] }
新增属性和方法
使用对象新增方式。
1 | function fn() { |
使用defineProperty()方法
1 | function fn() { |
构造函数的原型
1 | // 定义构造函数 |
以上代码经测试可以发现,为构造函数原型新添加的属性,在其对象中虽可访问但通过getOwnPropertyDescriptor
方法是得不到的。
原型属性
自有属性与原型属性
- 自有属性:通过对象的引用添加的属性。其它对象可能无此属性;即使有,也是彼此独立的属性。
- 原型属性:从原型对象中继承来的属性,一旦原型对象中属性值改变,所有继承自该原型的对象属性均改变。
通过构造函数Hero创建对象时不仅具有构造函数的自有属性,也具有构造函数的原型属性。
通过对象是无法修改原型的值,修改原型的值,必须修改构造函数的原型。
1 | // 定义一个构造函数 |
自有属性与原型属性的优先级
自有属性的优先级高于原型属性,也就是说当原型属性与自有属性同时存在时,那么优先打印出的是自有属性。但自有属性不会覆盖原型属性,当删除自有属性时,再次访问该属性,那么会输出原型属性。
1 | // 定义构造函数 |
检测自有属性与原型属性
检测自有属性有两种方式,分别为object.hasOwnProperty(prop)
与in
关键字。但这两种方式是有区别的。
object.hasOwnProperty(prop)
方式参数
示指定属性的名称,字符串类型
返回值
true
表示存在指定属性是自有属性
false
表示不存在指定的自有属性
示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19function Hero() {
this.name = "张无忌"; // 自有属性
}
Hero.prototype.age = 18;
var hero = new Hero();
/**
* object.hasOwnProperty()
* 作用 - 判断当前属性是否为自有属性
* 参数
* prop - 表示指定属性的名称
* 返回值
* true - 表示存在指定属性是自有属性
* false - 表示不存在指定的自有属性
*/
console.log(hero.hasOwnProperty("name")); //true
console.log(hero.hasOwnProperty("age")); // false
console.log(hero.hasOwnProperty("sex")); // false
in
关键字返回值
true
表示存在指定属性
false
表示不存在指定属性
示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16function Hero() {
this.name = "张无忌"; // 自有属性
}
Hero.prototype.age = 18;
var hero = new Hero();
/**
* 使用in关键字检测对象的属性
* 作用 - 判断对象中是否存在指定属性(自有属性或原型属性)
* * 返回值
* true - 表示存在指定属性
* false - 表示不存在指定属性
*/
console.log("name" in hero); //true
console.log("age" in hero); //true
console.log("sex" in hero); // false
扩展属性和方法
利用对象.属性或方法的方式新增属性或方法
1
2
3
4
5
6
7
8
9function Hero() {}
// 1. 利用对象.属性或方法的方式新增属性或方法
Hero.prototype.name = "张无忌";
Hero.prototype.sayMe = function () {
console.log("this is function");
};
var hero = new Hero();
console.log(hero.name); // 张无忌
hero.sayMe(); // this is function直接将原型重新赋值为一个新对象
1
2
3
4
5
6
7
8
9
10
11function Hero() {}
// 2. 直接将原型重新赋值为一个新对象
Hero.prototype = {
name: "张无忌",
sayMe: function () {
console.log("this is function");
},
};
var hero = new Hero();
console.log(hero.name); // 张无忌
hero.sayMe(); // this is function二者区别
第一种是相当于在原有的基础上扩充,而第二种会直接将内存指向改为一个新对象,如果原来新增过属性或方法,则全会丢失。
隐式原型与显式原型
将函数的原型称为显式原型
将对象的原型成为隐式原型
所有对象都具有原型,但对象的原型(__proto__)并非是函数的原型(prototype)。对象的原型不能用于真实开发工作,仅用于逻辑测试
1 | // 定义构造函数 |
isPrototypeOf()方法
isPrototypeOf() 判断指定对象是否是另一个对象的原型。
1 | // 通过初始化器定义对象 |
扩展内建对象
直接通过Object原型新增
1
2
3
4
5
6
7
8
9Object.prototype.sayMe = function () {
console.log("this is function");
};
// 通过Object构造函数创建对象
var obj = new Object();
obj.sayMe();通过
defineProperty
方法新增1
2
3
4
5
6
7Object.defineProperty(Object.prototype, "sayMe", {
value: function () {
console.log("this is sayMe");
},
});
var obj = new Object();
obj.sayMe();