prototype原型
- 我们所创建的每一个函数,解析器都会向函数中添加一个属性prototype。它默认指向一个Object空对象(即称为:
原型对象
)
prototype与constructor
- 原型对象中有一个属性
constructor
, 它指向函数对象
// 此处有一个Type对象,Type的prototype -->> Type的prototype(即Type的原型对象)
// 同时Type的原型对象一个 constructor -->> Type,找到Type
console.log(Date.prototype.constructor===Date) // ture
function Fun () {//alt + shift +r(重命名rename)
}
console.log(Fun.prototype.constructor===Fun) // ture
显式原型与隐式原型
- 每个函数function都有一个
prototype
,即显式原型(属性)- 每个实例对象都有一个
__proto__
,可称为隐式原型(属性)- 原型就是一个对象,和其他对象没有任何区别,可以通过构造函数来获取原型对象。 和其他对象一样我们可以添加修改删除原型中的属性,也可以修改原型对象的引用。
- 构造函数. prototype
- 指向该构造函数的原型对象,我们可以通过
__proto__
来访问该属性- 对象的隐式原型的值为其对应构造函数的显式原型的值
//定义一个构造函数
function MyClass(){
}
var mc = new MyClass();
var mc2 = new MyClass();
console.log(MyClass.prototype);
console.log(mc.__proto__);
console.log(mc2.__proto__);
console.log(mc2.__proto__ == MyClass.prototype); // true
内存结构
显示原型与隐式原型同时保存相同的地址值
//定义构造函数
function Fn() { // 内部语句: this.prototype = {}
}
//创建实例对象
var fn = new Fn() // 内部语句: this.__proto__ = Fn.prototype
console.log(fn.__proto__)
console.log(Fn.prototype===fn.__proto__) // true
// 所有的函数都是Function的实例对象
console.log(Fn.__proto__ == Function.prototype); // true
//给原型添加方法
Fn.prototype.test = function () {
console.log('test()')
}
//通过实例调用原型的方法
fn.test()
内存结构图示:
总结:
函数的
prototype
属性: 在定义函数时自动添加的, 默认值是一个空Object对象
- 对象的
__proto__
属性: 创建对象时自动添加的, 默认值为构造函数的prototype属性值程序员能直接操作显式原型, 但不能直接操作隐式原型(ES6之前)
- 原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,我们可以将对象中共有的内容,统一设置到原型对象中。
- 当我们访问对象的一个属性或方法时,它会先在对象自身中寻找,如果有则直接使用,如果没有则会去原型对象中寻找,如果找到则直接使用
//定义一个构造函数
function MyClass(){
}
//向MyClass的原型中添加属性a
MyClass.prototype.a = 123;
//向MyClass的原型中添加一个方法
MyClass.prototype.sayHello = function(){
console.log("hello");
};
var mc = new MyClass();
var mc2 = new MyClass();
var mc3 = new MyClass();
//向mc中添加a属性
mc.a = "我是mc中的a";
console.log(mc.a);
console.log(mc2.a);
mc3.sayHello();
- 因此以后我们创建构造函数时,可以将这些对象共有的属性和方法,统一添加到构造函数的原型对象中,这样不用分别为每一个对象添加,也不会影响到全局作用域,就可以使每个对象都具有这些属性和方法了。
每一个对象都有原型,包括原型对象也有原型。特殊的是 Object的原型对象没有原型。
检查对象
in
使用
in
检查对象中是否含有某个属性时,如果对象中没有但是原型中有,也会返回true
/*
* 创建一个构造函数
*/
function MyClass(){
}
//向MyClass的原型中添加一个name属性
MyClass.prototype.name = "我是原型中的名字";
var mc = new MyClass();
mc.age = 18;
console.log("name" in mc);
hasOwnProperty()
可以使用对象的
hasOwnProperty()
来检查对象自身中是否含有该属性,使用该方法只有当对象自身中含有属性时,才会返回true
/*
* 创建一个构造函数
*/
function MyClass(){
}
//向MyClass的原型中添加一个name属性
MyClass.prototype.name = "我是原型中的名字";
var mc = new MyClass();
mc.age = 18;
//检查是否有age属性
console.log(mc.hasOwnProperty("age"));
//检查是否有name属性
console.log(mc.hasOwnProperty("name"));
原型链
基于我们上边所说的,每个对象都有原型对象
- 原型对象也是对象,所以它也有原型,当我们使用一个对象的属性或方法时,会现在自身中寻找
- 自身中如果有,则直接使用
- 如果没有则去原型对象中寻找,如果原型对象中有,则使用
- 如果没有则去原型的原型中寻找,直到找到
Object
对象的原型- Object对象的原型没有原型,如果在
Object
原型中依然没有找到,则返回undefined
/*
* 创建一个构造函数
*/
function MyClass(){
}
//向MyClass的原型中添加一个name属性
MyClass.prototype.name = "我是原型中的名字";
var mc = new MyClass();
mc.age = 18;
console.log(mc.__proto__.hasOwnProperty("hasOwnProperty"));
//获取原型的原型
console.log(mc.__proto__.__proto__.hasOwnProperty("hasOwnProperty"));
//这里已经找到头,到object
console.log(mc.__proto__.__proto__.__proto__);
上图可以看出,如果找不到可以到原型的原型去寻找,找到object以后,则不存在原型
- 所有函数都是Function的实例(包含Function)
console.log(Function.__proto__===Function.prototype) // true
- Object的原型对象是原型链尽头
console.log(Object.prototype.__proto__) // null
面试题
- 问打印结果分别是多少?
function A () { |