【JavaScript学习笔记】Part 4-JS原型

原型

1. [[Prototype]]

JS中的对象有一个特殊的[[Prototype]]内置属性,实际上就是对于其他对象的引用

var myObject = {
    
    
    a:2
}
console.log(myObject.a)  //打印2

对于默认的[[Get]]操作来说,如果无法再对象本身找到需要的属性,就会继续访问对象的[[Prototype]]链。

var anotherObject = {
    
    
    a:2
}
var myObject = Object.create(anotherObject)
console.log(myObject.a)

Object.create创建一个对象并把这个对象的[[Prototype]]关联到指定的对象。

在myObject中找不到a,就会沿着[[Prototype]]链找下去,直到找到匹配的属性名或找完整条链。

所有普通的[[Prototype]]链最终都会指向内置的Object.prototype

2.“类”

2.1 “构造”

function foo(){
    
    
    
}
console.log(foo.prototype) // {}

这个就是原型,每当通过new foo()创建的每个对象最终都会被[[Prototype]]链接到这个对象。

function foo(){
    
    

}

var a = new foo()
console.log(Object.getPrototypeOf(a) === foo.prototype) //true

这样两个对象就通过[[prototype]]关联起来了,没有用到我们常见的类。

new会劫持所有普通函数并用构造对象的形式来调用它。

function foo(){
    
    
    console.log('????????????')
}

var a = new foo()  //??????????
 
console.log(a)    //{}

foo只是一个普通的函数,但当使用new调用时,就会构造一个对象并赋值给a,所以new无论如何都会构造一个对象,这是一个构造函数调用,但foo本身并不是构造函数。

因此在js中,所谓的“构造函数”,实际上指的是带new的函数调用将两个对象关联起来。

看一下这段代码:

function foo(name){
    
    
    this.name = name
}
foo.prototype.myname = function(){
    
    
    return this.name
}
var a = new foo('a')
var b = new foo('b')

console.log(a.myname())
console.log(b.myname())

在这里,创建a和b的时候并不是将foo.prototype对象复制到这两个对象中,而是将其内部的[[Prototype]]关联foo.prototype上,当a和b中无法找到myname时候,就会通过委托foo.prototype上找到。

因此再看这段代码:

function foo(){
    
    
    
}
foo.prototype.constructor === foo  //true
var a = new foo()
a.constructor === foo  //true

实际上就是其a.constructor引用被委托给foo.prototype,在a上找不到的时候就会去到它所关联的foo.prototype上找,而由于foo.prototype.constructor是一个默认属性,默认指向foo的,所以最后一个判断为真,so这里并不是真正的“构造函数”(不要被constructor骗了)。

但如果我们手动foo.prototype创建要给新的对象会发生什么?

stedafunction foo(){
    
    }

foo.prototype = {
    
    }

var a = new foo()
console.log(a.constructor === foo)   //false
console.log(a.constructor === Object)  //true

由于我们给foo.prototype指定了一个新的对象,它已经没有.constructor属性了(默认自带的才有),而由于a会沿着原型链来查找,到了foo.prototype仍然没找到,那就只能再往上一层(Object.prototype)里面找了,这里有.constructor,而且是指向Object它自己。

因此这里进一步说明了a并不是简单地由new foo()通过constructor构造而来,而是通过js独特的机制原型链而进行两个对象之间的关联。

2.2 “继承”

在js中,”继承“是把一个对象的prototype与另一个对象的prototype关联起来,有两种方法:

  • Bar.prototype = Object.create(foo.prototype)   //ES6之前的方法
    
  • Object.setPrototypeOf(Bar.prototype,foo.prototype)  //ES6的方法
    

2.3 “反射”

在java中,检查一个实例的继承祖先被称为反射,而在JS中,查找对象的委托关联也是类似"反射"这样的机制:

function Foo(){
    
    

}
Foo.prototype.blah = {
    
    }
var a = new Foo()

a instanceof Foo //在a的整条原型链中是否有Foo.prototype指向的对象
Foo.prototype.isPrototypeOf(a)  //在a的整条原型链中是否出现过Foo.prototype

第一种方法只能处理对象和函数之间的关系,无法判断两个对象之间是否通过原型链关联。

在ES5和ES6标准下,都有方法可以直接访问内部的原型属性:

Object.getPrototypeOf(a) === Foo.prototype  //ES5
a.__proto__ === Foo.prototype 	//ES6

联。

在ES5和ES6标准下,都有方法可以直接访问内部的原型属性:

Object.getPrototypeOf(a) === Foo.prototype  //ES5
a.__proto__ === Foo.prototype 	//ES6

猜你喜欢

转载自blog.csdn.net/weixin_40764047/article/details/111599280