原型和原型链(前端高频面试题)

·构造函数

构造函数和普通函数本质上没什么区别,只不过使用了new关键字创建对象的函数,
被叫做了构造函数。构造函数的首字母一般是大写,用以区分普通函数。
function Person(name, age) {
   	this.name = name;
   	this.age = age;
    this.species = '人类';
    this.say = function () {
        console.log("Hello");
    }
}

let per1 = new Person('xiaoming', 20);

·原型对象

在js中,每一个函数类型的数据,都有一个叫做prototype的属性,这个属性指向的是一个对象,就是所谓的原型对象。
对于原型对象来说,它有个constructor属性,指向它的构造函数。
这个原型对象的作用是用来存放实例对象的公有属性和公有方法。

放在构造函数里,那每创建一个实例,就会重复创建一次相同的属性和方法,显得有些浪费。
这时候,如果把这些公有的属性和方法放在原型对象里共享就会好很多。
function Person(name, age) {
    this.name = name;
    this.age = age;
}

Person.prototype.species = '人类';
Person.prototype.say = function () {
    console.log("Hello");
}

let per1 = new Person('xiaoming', 20);
let per2 = new Person('xiaohong', 19);

console.log(per1.species); // 人类 
console.log(per2.species); // 人类

per1.say(); // Hello
per2.say(); // Hello

这里的species属性和say方法不是实例对象自己的,为什么可以直接用点运算符访问?这是因为在js中,
对象如果在自己的这里找不到对应的属性或者方法,就会查看构造函数的原型对象,如果上面有这个属性或方法,
就会返回属性值或调用方法。所以有时候,我们会用per1.constructor查看对象的构造函数:
console.log(per1.constructor); // Person()
这个constructor是原型对象的属性,在这里能被实例对象使用,原因就是上面所说的。
如果原型对象上也没有找到想要的属性,就要用到原型链了。

·原型链

1.显示原型

显示原型就是利用prototype属性查找原型,只是这个是函数类型数据的属性。

2.隐式原型

隐式原型是利用_proto_属性查找原型,这个属性指向当前对象的构造函数的原型对象,这个属性是对象类型数据的睡醒,所以可以在实例对象上面使用:
console.log(per1.__proto__ === Person.prototype); // true
console.log(per2.__proto__ === Person.prototype); // true
根据上面,就可以得出construtor、prototype和_proto_之间的关系了:

   Person()->.prototype->Person.prototype
   Person.prototype->.constructor->Person()
   Person() -> new -> per1
   per1 -> ._proto_ -> Person.prototype

3.原型链

既然这个是对象类型的属性,而原型对象也是对象,那么原型对象就也有这个属性,但是原型对象的_proto_指向哪里?
既然原型对象也是对象,那我们只要找到对象的构造函数就能知道_proto_的指向了。而js中,
对象的构造函数就是Object(),所以对象的原型对象,就是Object.prototype。既然原型对象也是对象,那原型对象
的原型对象,也就是Object.prototype。既然原型对象也是对象,那原型对象的原型对象,就也是Object.prototype。
不过Object.prototype这个比较特殊,它没有上一层的原型对象,或者说是它的_proto_指向的是null。

到这里就可以回答前面那个问题了,如果某个对象查找属性,自己和原型对象上都没有,那就会继续往原型对象的原型对象上去找,
这个例子里就是Object.prototype,这里就是查找的终点站了,在这里找不到,那没有更上一层了(null里面啥也没有),直接返回undefined。

可以看出,整个查找过程都是顺着_proto_属性,一步一步往上查找,形成了像链条一样的结构,这个结构,
就是原型链。所以原型链也叫做隐式原型链。

正是因为这个原因,我们在创建对象、数组、函数等数据的时候,都自带一些属性和方法,这些属性和方法是在他们的原型上面保存着,所以它们自创建起就可以直接使用那些属性和方法。

·函数也是一种对象

函数在js中,也算是一种特殊的对象,所以,可以想到的是,函数是不是也有一个_proto_属性?答案是肯定的,然后按照上面的思路,先来找找函数对象的构造函数。

在js中,所有函数都可以看做是Function()的实例,而Person()和Object()都是函数,所以它们的构造函数就是Function()。
Function()本身也是函数,所以Function()也是自己的实例,听起来既怪异又合理,但是就是这么回事。
console.log(Person.constructor === Function); // true
console.log(Object.constructor === Function); // true
console.log(Function.constructor === Function); // true

既然知道了函数的构造函数,那么函数的_proto_指向我们也就知道了,就是Function.prototype。
console.log(Person.__proto__ === Function.prototype); // true
console.log(Object.__proto__ === Function.prototype); // true
console.log(Function.__proto__ === Function.prototype); // true

·总结

1.构造函数是使用了new关键字的函数,用来创建对象,所有函数都是Function()的实例。

2.原型对象是用来存放实例对象的公有属性和公有方法的一个公共对象,所有原型对象都是Object()的实例。

3.原型链又叫隐式原型链,是由_proto_属性串联起来,原型链的尽头是Object.prototype。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值