prototype原型看起来真不要太晕

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
  //给原型添加方法
  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

面试题

  1. 问打印结果分别是多少?
  function A () {

  }
  A.prototype.n = 1

  var b = new A()

  A.prototype = {
    n: 2,
    m: 3
  }

  var c = new A()
  console.log(b.n, b.m, c.n, c.m)	// 1 undefined 2 3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

空 白

停止的只会是自己,你得追逐世界

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值