原型链与原型,面向对象,继承

48 阅读4分钟
function Test(){}
let test=new Test()

在这一过程中,这个新对象的内部的__proto__属性被赋值为构造函数的prototype属性

test.__proto__===Test.prototype

对象的constructor性指向构造函数

test.constructor==Test//这里的test.constructor相当于Test.prototype.constructor

instanceof操作符是用来确认对象类型的,(用来检测某个对象是不是另一个构建函数的实例)

test instanceof Test

构造函数与普通函数的区别? 它们唯一不同的就是调用方式的不同。任何函数只要使用new操作符调用就是构造函数,否则就是普通函数 为什么会有原型链?它主要解决了什么问题?

function Person(name,age){
  this.name=name
  this.age=age
  this.sayName=function(){
   console.log(this.name)
  }
}
const person1=new Person('11',11)
const person2=new Person('22',22)

在创建实例时,这里的this.sayName相当于

 this.sayName=new Function("console.log(this.name)")

这里新创建的Function的机制是一样的,可以有优化

function Person(name,age){
  this.name=name
  this.age=age
  this.sayName=sayName
}
function sayName(){
console.log(this.name)
}
const person1=new Person('11',11)
const person2=new Person('22',22)

但这样不好的是会有大量的全局作用域的函数.针对这种情况。原型链可以解决这个问题 每个函数都会创建一个prototype属性,这个属性是一个对象。它包含应该由特定引用类型的实例共享的属性和方法。实际上,这个对象 就是 通过调用构造函数创建的对象 的原型

理解原型的本质: 每个函数都会一个prototype属性,指向原型对象。[Person.prototype是个对象] 每个原型对象自动获得一个constructor属性,指向构造函数 Person.prototype.constructor==Person 创建构造函数创建的实例的内部属性__proto__指针就会被赋值为构造函数的原型对象 即person.proto===Person.protytpe 关键点:实例与构造函数之间没有关系,但与构造函数原型之间有直接的联系

这个参数constructor主要是针对原型对象来说的 Person.prototype?[是的]

有些实现没有对外暴露__proto__方法,但可以通过函数isPrototypeOf来检查两个对象之间的关系

Person.prototype.isPrototypeOf(person1)

或者通过Object.getPrototypeOf()来返回对应的原型对象

 Object.getPrototypeOf(person1)===Person.prototype  //返回为true

原型链之间的这种关系可以通过Object.create()来联接

  let bird={name:1}
  let perosn=Object.create(bird)
  Object.getPrototypeOf(person)===bird //true

hasOwnProperty()可以用来确定某个属性是在实例上还是在对应的原型对象上

person.hasOwnProperty('name')

in操作符 in操作符会在可以通过对象访问指定属性时,返回true.无论该属性是在实例上还是在原型上

console.log('name' in person1) //因此可以in 和 hasOwnProperty()结合着来使用

原型最大的问题在于它的共享特性(特别是对于引用值 类型来说)(也有其他问题,比如弱化了向构造函数传递初始化参数的能力,会导致所有实例取到相同的值)

function Person(){
}
Person.prototype={
 name:['one','two']
}
const person1=new Person()
const person2=new Person()
person1.name.push("three")
//这样person2的name值也发生了变化

因此就出现了继承 原型链与继承的关系 可以用instanceof操作符(如果一个实例的原型链中出现过相应的构造函数,则返回true)

 person instanceof Person
//手动实现instanceof
let myInstanceof = (target,origin) => {
     while(target) {
         if(target.__proto__===origin.prototype) {
            return true
         }
         target = target.__proto__
     }
     return false
 }
 let a = [1,2,3]
 console.log(myInstanceof(a,Array));  // true
 console.log(myInstanceof(a,Object));  // true
function Person(name){
 this.name=name
}
const p=new Person("one")
1.new创建了一个对象,这个对象的原型链,指向了构造函数的原型
p.__proto__==Person.prtototype

2.Person有个原型,原型上有个construcotr,是Person自己
Person.prototype.construcotr==Person

手写一个new函数 1创建了一个对象 2这个对象的原型指向了Function的prototype 3该对象调用了Function的方法 4根据一些特定情况进行返回 a如果构造函数明确返回一个对象,则返回这个对象、 b如果这个构造函数没有返回值或者返回一个非对象类型,则new最后返回创建的这个对象

 function newFunc(Person,..res){
     if(typeof Person!=='function'){
       throw new Error("eror")
     }
     var obj=Object.create(Person.prototype)
     var result=Person.call(obj,rest)
     return result&& typeof result=='object' ?result:obj
}

怎样实现Oject.create()

function inherit(p){
 if(p==null)t throw new Error('error')
 if(Object.create) return Object.create(p)
 if(typeof p!='object' && typepof p!='function') return new Error('error')
 function F(){}
 F.prototype=p
 return new F()
}

原型继承的例子及缺点

function Person(){
this.name=[]
}
Person.prototype.getName=function(){return this.name}
function Child(){}
Child.prototype=new Person()
Child. .constructor=Child
//1child不能传参
//2如果parent有引用类型的属性,一修改,都会受影响

组合寄生继承

function Parent(name){
 this.name=name
}
Parent.prototyp.getName=function(){}
function Child(name){
 Parent.call(thsi,name)//这里是执行了Parent()方法
}
Child.prototype=Object.create(Parent.prototype)
//Child.prototype=new Parent()

Child.prototype.constructor=Child

组合寄生与class的区别 class继承会继承静态属性 子类中,必须在constructor中调用super.因为子类自己的this对象,必须先通过父类的构造函数来完成