JS基础-原型和原型链【三座大山之一】

420 阅读3分钟
  • JS基础-原型和原型链【三座大山之一】
  • JS基础-作用域和闭包【三座大山之二,待更新。。。】
  • JS基础-异步【三座大山之三,待更新。。。】

1. 创建对象的几种方法

1.1 方式一:字面量

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

1.2 方式二:构造函数

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

1.3 方式三:Object.create

var P = {name: 'o3'}
var o3 = Object.create(P)

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

2.1 原型

  • 原型也是一个对象,通过原型可以实现对象的属性继承
  • prototype就是调用构造函数所创建的那个实例对象的原型(proto)。
  • 对象有"[[prototype]]"属性,函数对象有"prototype"属性,原型对象有"constructor"属性。

2.2 构造函数

  • 用 new 关键字来调用的函数,称为构造函数。构造函数首字母一般大写

2.3 实例

  • 只要是对象就是一个实例
  • 实例是类的具象化产品, 而对象是一个具有多种属性的内容结构。
  • 实例都是对象,而对象不全是实例。

2.4 原型链

  • 实例对象与原型之间的连接,叫做原型链。proto( 隐式连接 )

2.5 原型关系图示

2.6 代码讲解

var M = function(){this.name = 'o2'}
var o2 = new M();
console.log(o2) // M {name: "o2"}
console.log(M.prototype) // {constructor: ƒ}
console.log(M.prototype.constructor === M) // true

2.7 prototype和__proto__的区别

  • 构造函数(函数)才有propotype 的,对象没有 propotype
  • 只有实例对象有 __proto__的,函数既是函数又是对象
var M = function(){this.name = 'o2'}
var o2 = new M();
M.__proto__ === Function.prototype // true

3. instanceof 的原理

3.1 instanceof 运算符

  • 用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。

判断函数FuncA是否是实例objA的构造函数的方法:

  1. instanceof: objA instanceof FuncA === true
  • 原理:obj.proto [_proto_加n个]=== FuncA.prototype
  • 缺陷:这个方法不够准确,因为只要在同一条原型链上都会返回true
  • eg: obj._proto_._proto_ ===FuncA.prototype._proto_===Object.prototype
  1. constructor obj._proto_.constructor === FuncA 一定准确

3.1 原理图示

  • 是判断 实例对象.proto 和 构造函数.prototype是不是一个引用(即引用同一个地址)
var M = function(){this.name = 'o2'}
var o2 = new M();
o2 instanceof  M // true
o2 instanceof Object // true


o2.__proto__ === M.prototype // true
M.__proto__  === Object.prototype // false
M.prototype.__proto__  === Object.prototype // true
o2.__proto__.constructor === M // true

o2.__proto__.constructor === Object // false

3.3 请实现一个instanceof,让以下代码可正常运行

  • 考察instanceof的判断原理,instanceof主要的实现原理就是只要右边变量的 prototype 在左边变量的原型链上即可。
  • 因此,instanceof 在查找的过程中会遍历左边变量的原型链,直到找到右边变量的 prototype,如果查找失败,则会返回 false。
/**
  自定义instanceof 
*/
function instanceOf(left, right) {
  let proto = left.__proto__
  while(proto){
    if(proto === right.prototype){
       return true
    }
    proto = proto.__proto__
  }  
  return false
}

class A{}
class B extends A {}
class C{}

const b = new B()
// 输出 true
console.log(instanceOf(b,B))
// 输出 true
console.log(instanceOf(b,A))
// 输出 false
console.log(instanceOf(b,C))

new 运算符

  • new构造函数的原理:
    1. 生成一个空对象(Object.create)
    2. 将空对象的__proto__指向构造函数的prototype
    var o=Object.create(func.prototype)
    
    1. 执行构造函数,this上下文指向空对象
    var k=func.call(o)
    
    1. 若构造函数返回的是对象,那么这个对象将取代原来的空对象;反之,返回之前的空对象
    if(typeof k==='object'){
    	return k;
    }else{
    	return o;
    }
    
  • 完整代码
      	var new2 = function(func) {
      		var o = Object.create(func.prototype);
      		var k = func.call(o);
      		if (typeof k==='object') {
      			return k;
      		} else {
      			return o;
      		}
      	}