美文网首页前端开发让前端飞前端开发笔记
前端面试高频问题 - 原型和原型链

前端面试高频问题 - 原型和原型链

作者: 番茄沙司a | 来源:发表于2018-09-04 00:32 被阅读19次

创建对象的几种方法

第一种方式:字面量对象

var o1 = {name:'o1'};
var o2 = new Object({name:'o2'});

理解字面量,默认原型链指向Object

第二种方式:通过显式构造函数

var m = function(name){
    this.name = name;
}
var o3 = new M('o3');

第三种方式:Object.create

var p = {name: 'p'};
var o4 = Object.create(p);

在控制台输入o1, o2, o3, o4

o1, o2 输出一个Object对象

o3是一个M对象

o4是个空对象

o1, o2, o3, o4 均有name属性

原型、构造函数、实例、原型链

  1. o1, o2, o3 为实例
  2. 构造函数:任何一个函数只要被new操作了,就可以被叫做构造函数
  3. 函数都有prototype属性,指的是原型对象(初始化空对象)
  4. 原型对象怎么区分是被哪一个构造函数引用:constructor
  5. 对象是一个实例

上面的例子中o3是实例,M是构造函数

//构造函数和原型对象的关系
M.prototype.constructor === M
true
//实例和原型对象之间的关系
o3.__proto__ === M.prototype
true

原型链:从一个实例对象向上找构造这个实例的相关联的对象,再往上找,有创造它的原型对象,一直类推,到Object.prototype终止(整个原型链的顶端),原型链通过prototype__proto__属性进行向上查找。

JavaScript object 猜想图

原型对象和原型链之间起的作用:构造函数中增加很多属性和方法。当有多个实例,共用一个方法,不能拷贝多次(若每个实例都要拷贝一份,会占内存,没有必要),所以有相同的方法要考虑存到共同的东西上,这个共同的东西就是原型对象。这就是js引擎支持的原型链的功能,任何一个实例对象通过它的原型找到它上面的原型对象,上面的实例和方法可以被共享。

var M = function(name){this.name = name;};
M.prototype.says = function() {
    console.log('say hi');
}
var o5 = new M('o5');

控制台输出:

o3.say()
say hi
o5.say()
say hi

注意:

  1. 函数才会有prototype

  2. 函数即是函数也是对象,也有__proto__属性

    例:写一个表达式说说原型是什么

    • M.__proto__ === Function.prototype 返回 true

      Object是个构造函数,原型为Function.prototype

    • Array 构造函数的原型:Array.prototype

instanceof 原理

原理:实例对象的__proto__属性和构造函数没什么关联,其实是引用的原型对象。判断实例对象的属性和构造函数的属性是不是同一个引用

原型对象上可能还会有原型链,用实例对象instanceof判断原型的构造函数,这条原型链上的函数返回都是 true

o3 instanceof M
true
//只要是原型链上都可以看作instanceof的构造函数
o3 instanceof Object
true

解释:

o3.__proto__=== M.prototype
true
M.prototype.__proto___=== Object.prototype
true
o3.__proto__.constructor === M
true
o3.__proto__.constructor === Object
false

new运算符

工作原理:

  1. 后面加上构造函数,一个新对象被创建,它继承自构造函数原型对象foo.prototype

  2. 构造函数foo被执行,执行的时候,相应的传参会被传入,同时上下文(this)会被指定为这个新实例。new foo 等同于 new foo(),只能用在不传递任何参数的情况。

  3. 如果构造函数返回了一个“对象”,那么这个对象会取代整个new出来的结果,如果构造函数没有任何返回对象,那么new出来的结果为步骤1创建的新对象。有返回对象,直接返回构造函数。

    实现一个new运算符效果:

var new2 = function(func){
    var o = Object.create(func.prorotype);
    //执行构造函数
    var k = func.call(o);
    if(typeof k === 'object'){
        return k;
    } else {
        return o;
    }
}

控制台输出:

o6 = new2(M)
o6 instanceof M
true
o6 instanceof Object
true
o6.__proto__.constructor === M
true
M.prototype.walk = function() {
    console.log('walk')
}
o6.walk()
walk
o3.walk()
walk

为什么o4直接拿不到name属性

Object.create方法创建的对象是用原型链连接的

o4.__proto__ === p
true

总结:原型链真的很重要,值得反复理解推敲。

相关文章

网友评论

    本文标题:前端面试高频问题 - 原型和原型链

    本文链接:https://www.haomeiwen.com/subject/joywwftx.html