JavaScript 原型链 OOP(二)

 
原型对象 `prototype`
-  原型对象的全部属性和方法,都能被实例对象共享;
 
JavaScript 经过构造函数生成新对象,所以构造函数能够视为对象的模板。实例对象的属性和方法,能够定义在构造函数内部。
 
function Cat (name, color) {
this.name = name;
this.color = color;
}

var cat1 = new Cat('小明', '白色');

cat1.name // '小明'
cat1.color // '白色'

 

构造函数缺点:

- 一个构造函数的多个实例之间,没法共享属性,从而形成对系统资源的浪费。

 

解决方法,就是 JavaScript 的 原型对象`prototype`,由于原型对象的全部属性和方法,都能被实例对象共享。
function Cat (name, color) {
this.name = name;
}
Cat.prototype.color ="白色";
}
var cat1 = new Cat('巧克力');
var cat2 = new Cat('布丁');
cat1.color //白色
cat2.color//白色
 JavaScript规定,每一个函数都有一个`prototype`属性,指向一个对象。
- 对于构造函数来讲,生成实例的时候,该属性会自动成为实例对象的原型。
- 实例对象自身就有某个属性或方法,它就不会再去原型对象寻找这个属性或方法。
function f() {}
typeof f.prototype // "object"

 

每一个 JS 对象都有 ` __proto__` 属性,这个属性能够访问到 原型(` [[prototype]]`) 内部属性。这个属性在如今来讲已经不推荐直接去使用它了。

 

  原型链

 - 任何对象,均可以充当其余对象的原型;原型对象也有本身的原型。
 - 对象到原型,再到原型的原型,一层层向上找到`Object.prototype` 造成原型链。

 

能够说 基本上全部对象都继承了`Object.prototype`的属性;而 `Object.prototype` 的原型是 `null`
经过 ` getPrototypeOf` 方法返回参数对象原型
Object.getPrototypeOf(Object.prototype) //null

 

 读取对象属性时,引擎会先在自身属性上查找,没有就查找原型,一级级向上查找,若是到`Object.prototype`仍是没有,则返回`undefined`。
**一级级向上,对性能有影响,寻找的层级越多,性能影响越大**
 
**原型链:**

 
- 实例 F1 经过`__proto__` 访问对应构造函数的原型 -> `FOO.prototype`
 
- 函数原型再经过`__proto__` 访问Object的原型 -> `Object.prototype`
 
- Object的原型的`__proto__` 指向 `null`
 
- 构造函数 `Foo.prototype` 经过`constructor`访问构造函数自己
 
- `Object.constructo` 指向 `Function`
 
- `Function.constructo` 指向 自己
 
- `Function.__proto__` 指向一个匿名函数
 
- 每一个构造函数经过 `prototype` 访问原型
**只有函数才拥有`prototype`属性,基本上全部函数都有这个属性**
let fun = Function.prototype.bind()
当声明一个函数时自动建立 `prototype` 属性,
这个属性的值是一个对象(也就是原型),且只有一个属性 `constructor`
 

 `constructor`

`prototype` 有一个属性 `constructor`,默认指向原型所在的构造函数
function Fn (){}
var f = new Fn ();
f.constructor == Fn //true
f.constructor == Function //false


//能够从实例对象新建另外一个实例
var b =new f.constructor();
b.constructor == Fn //true
`constructor `是一个公有且不可枚举的属性。一旦咱们改变了函数的 prototype ,那么新对象就没有这个属性了,若是修改了原型对象,通常会同时修改constructor属性,防止引用的时候出错。
function A(){}
console.log(A.prototype) // {constructor: ƒ}constructor: ƒ A()__proto__: Object
A.prototype="a"
console.log(A.prototype) //"a"

 

constructor做用:

- 让实例对象知道是什么函数构造了它,能够得知某个实例对象,是哪个构造函数产生的。
- 若是想给某些类库中的构造函数增长一些自定义的方法,就能够经过 xx.constructor.method 来扩展

 

 \_\_proto\_\_

基本上每一个对象都有的隐式原型属性,指向建立该对象的构造函数的原型,实际指向`[[prototype]]`, 内部属性,咱们并不能访问到,因此使用 _proto_ 来访问。
console.log({})
//__proto__: Objectconstructor: ƒ Object()hasOwnProperty: ....

 

当咱们使用 new 操做符时,生成的实例对象拥有了 `__proto__`属性。

function Foo() {}
// 这个函数是 Function 的实例对象
// function 就是一个语法糖
// 内部调用了 new Function(...)
const a =1;
const fn = new Function("console.log(a)") // Function 的this始终指向 全局对象,除非手动改变this指向
fn()//1

 

- 全部对象均可以经过原型链最终找到 Object.prototype ,虽然 Object.prototype 也是一个对象,可是这个对象却不是 Object 创造的,而是引擎本身建立了 `Object.prototype` 。
能够这样说,全部实例都是对象,可是对象不必定都是实例。

 

-首先引擎建立了 Object.prototype ,而后建立了 Function.prototype ,而且经过__proto__ 将二者联系了起来。

 

- Function.prototype 之后才有了 function Function() ,而后其余的构造函数都是 function Function() 生成的。

 

- 函数经过 `new Function()` 生成, 不是全部函数都是 `new Function() `产生的。 
 
总结:
> 1. Object 是全部对象的爸爸,全部对象均可以经过__proto__ 找到它
 
> 2. Function 是全部函数的爸爸,全部函数均可以经过__proto__ 找到它
 
> 3. Function.prototype 和 Object.prototype 是两个特殊的对象,他们由引擎来建立
 
> 4. 除了以上两个特殊对象,其余对象都是经过构造器 new 出来的
 
> 5. 函数的 prototype 是一个对象,也就是原型
 
对象的__proto__ 指向原型,__proto__将对象和原型链接起来组成了原型链



   JavaScript 对象继承 OOP (三)


html

相关文章
相关标签/搜索