浅谈原型和原型链

理解原型和原型链

本文会采用 概念 + 习题 来帮助理解

概念

理解原型之前,我们先来说说 构造函数使用构造函数创建对象

构造函数和创建实例

举个例子:

定义了一个普通的Person函数,此时它还是一个普通的函数

function Person(name,age) {
    this.name = name,
    this.age = age,
    this.sayName = function(){
        console.log(this.name)
    }
}

这个时候我做这个操作

var p1 = new Person('zhangsan',18);

此时这个Person函数不是普通的函数了,而变成了一个构造函数。并且实例化了一个对象 p1

实例化后的对象p1内部就会有构造函数的属性以及方法了。
在这里插入图片描述

这里直接提出一个问题,为什么new了一下Person 函数之后,就会创建了一个对象,并且这个对象还存有构造函数Person的属性和方法呢。

这里就不得不提到new操作之后会执行那些步骤 :

1.创建了一个对象

var obj = new Object();

2.将新对象的__proto__指向构造函数的prototype

obj.__proto__ = Person.prototype

3.将构造函数中的this指向

Person.call(obj)

这里就是为什么构造函数中使用 this.name = name 这样,创建不同的对象,this总是指向那个创建的被创建的对象。

4.执行构造函数中的代码

5.若构造函数返回一个对象,则返回改对象,否则返回新对象

理解创建对象的过程之后,我们来说一个构造函数的弊端。

举个例子:

//使用刚才的代码示例
function Person(name,age) {
    this.name = name,
    this.age = age,
    this.sayName = function(){
        console.log(this.name)
    }
}
//创建两个对象
var p1 = new Person('zhangsan',18)
var p2 = new Person('lisi',20)
//判断两个对象的Function是不是同一个
console.log(p1.sayName == p2.sayName)//false

看上面的例子,说明构造函数中定义的方法在创建每一个实例的时候都会被创建一次,所以为什么两个方法同名却不相等。所以为了优化这种弊端,我们不得不把属性和方法分开定义。

这个时候直接上原型。

原型与原型链

我们刚才说了构造函数如果定义方法,会产生一定的弊端,那么我们将用原型来解决这一弊端

那么原型是什么呢?

每个函数都会创建一个 prototype属性,这个属性是一个对象,包含应该由特定引用类型的实例共享的属性和

方法。实际上,这个对象就是通过调用构造函数创建的对象的原型。使用原型对象的好处是,在它上面定义的

属性和方法可以被对象实例共享。原来在构造函数中直接赋给对象实例的值,可以直接赋值给它们的原型。

我个人简单来说 :

原型就是构造函数的另一个储存空间,实例化对象的对象属性继承自构造函数,方法则继承原型。

构造函数.prototype 就是 原型对象

举个例子:

function Person(name,age) {
   this.name = name
   this.age = age
}
Person.prototype.sayName = function() {
     console.log('我是原型上的方法输出对象的名字:' + this.name)
}
var person1 = new Person('张三',18)
var person2 = new Person('李四',28)
console.log(person.name)
console.log(person.age)
console.log(person1.sayName == person2.sayName)//true 解决了构造函数的弊端。
person.sayName()

上面的例子,在Person构造函数定义方法,在Person原型定义了一个方法sayName

输出了对象的name age 属性 和 调用了sayName方法

这里可能有人会疑问 可以输出 姓名和年龄 是因为在构造函数定义了,而sayName方法不是定义在构造函数的怎么调用的呢

原型链

这里我就引出三个属性 __proto__ constructor prototype

我画个图让你理解一下这三个属性的关系
在这里插入图片描述

可以知道

__proto__ 就是对象中一个可以指向Person.prototype的属性指针

constructor 是对象中一个可以指向构造函数的属性

prototype 就是一个构造函数.prototype就是一个原型

看了图之后我们也就知道为什么 person对象可以调用不是构造函数定义的方法sayName

person会类似于链式作用域查找一样,找到它所要调用的方法,这种链式查找可以理解为原型链,图中只是原型链上的一小部分

看了上面的概念或许还不是很理解原型和原型链的概念,下面直接做习题来加深理解吧。

习题

示例一:

function Fn() {
    this.x = 100;
    this.y = 200;
    this.getX = function () {
        console.log(this.x);
    }
}
Fn.prototype.getX = function () {
    console.log(this.x);
};
Fn.prototype.x = 20
Fn.prototype.getY = function () {
    console.log(this.y);
};
let f1 = new Fn();
let f2 = new Fn();

console.log(f1.getX === f2.getX);
console.log(f1.getY === f2.getY);
console.log(f1.__proto__.getY === Fn.prototype.getY);
console.log(f1.__proto__.getX === f2.getX);
console.log(f1.getX === Fn.prototype.getX);
console.log(f1.constructor);
console.log(Fn.prototype.__proto__.constructor);
f1.getX();
f1.__proto__.getX();
f2.getY();
Fn.prototype.getY();

解释:

console.log(f1.getX === f2.getX); 1
console.log(f1.getY === f2.getY); 2

1 : f1f2 是两个不同的对象,所以创建这两个对象就相当于创建了两个不同构造函数的方法getX 构造函数创建的弊端,创建每一个对象,都会给每一个对象创建一个

1false

2 : 上面的概念说了,原型中的方法是公用的,所以不必创建的一个对象就就再创建一个方法

2true

console.log(f1.__proto__.getY === Fn.prototype.getY); 3
console.log(f1.__proto__.getX === f2.getX); 4
console.log(f1.getX === Fn.prototype.getX); 5
console.log(f1.constructor); 6
console.log(Fn.prototype.__proto__.constructor); 7

3 : f1.__proto__ 就是指向 Fn的原型对象 获取Fn.prototype 中的方法 getY 所以为 true

4 : f1.__proto__ 就是指向 Fn的原型对象 获取Fn.prototype 中的方法 getX

f2.getX 中的方法getX 是从构造函数实例出来的,所以两个不相同 为 false

5 : 跟 4的情况类似 false

6 : f1的构造函数就是 Fn

7 : Fn.prototype.__proto__ 这里就是指向 Fn原型的原型 就是 Object.prototype 其实就相当于问 Object.prototype 的构造函数 Object

f1.getX(); 8
f1.__proto__.getX(); 9
f2.getY(); 10 
Fn.prototype.getY(); 11

8 : 就是调用实例化对象里面的getX 答案为100

10 : 这里实例化对象中没有getY ,只能找原型上面的getYthis调用问题,谁调用指向谁,所以答案为200

9 : f1.__proto__ 相当于 Fn.prototype 调用 ,this指向问题 原型上有x 所以为 20

11 : Fn.prototype.getY() this指向问题 ,原型上没有y则输出 undefined

总结:
1.先理解好创建构造函数的new过程
2.理清楚构造函数定义方法和原型构造函数的区别
3.三个属性 __proto__ constructor prototype关系
4.可以自己画图来理解
以上如有错误欢迎指正,一起学习 LOVE&&PEACE

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值