- 为什么要有原型的出现?
-
-
prototype
: 显式原型属性
-
-
所有实例对象都有一个特别的属性:
-
__proto__
: 隐式原型属性 -
讲原型的时候,我们应该先要记住以下几个要点,这几个要点是理解原型的关键:
1、所有的引用类型(数组、函数、对象)可以自由扩展属性(除null以外)。
2、所有的引用类型都有一个’_ _ proto_ _'属性(也叫隐式原型,它是一个普通的对象)。
3、所有的函数都有一个’prototype’属性(这也叫显式原型,它也是一个普通的对象)。
4、所有引用类型,它的实例化的对象的’_ _ proto_ _'属性指向它的构造函数的’prototype’属性。
5、当试图得到一个对象的属性时,如果这个对象本身不存在这个属性,那么就会去它的’_ _ proto_ _'属性(也就是它的构造函数的’prototype’属性)中去寻找。
-
显式原型与隐式原型的关系
-
函数的prototype: 定义函数时被自动赋值, 值默认为{}, 即用为原型对象
-
实例对象的__proto__: 在创建实例对象时被自动添加, 并赋值为构造函数的prototype值
-
原型对象即为当前实例对象的父对象
-
-
原型链
-
所有的实例对象都有__proto__属性, 它指向的就是原型对象
-
这样通过__proto__属性就形成了一个链的结构---->原型链
-
当查找对象内部的属性/方法时, js引擎自动沿着这个原型链查找
-
上面可以看出实例化对象ldh.__proto__指向star的原型对象,
而star的原型对象.__proto__指向Object的原型对象,
而object的原型对象.__proto__指向null
------------------------------------------------------------------------------------------------------------------------------------------------------------
//定义构造函数 function Fn() { // 内部语句: var Fn = new Function() this.prototype = {} }
// 1. 每个函数function都有一个prototype,即显式原型属性, 默认指向一个空的Object对象 console.log(Fn.prototype) // 2. 每个实例对象都有一个__proto__,可称为隐式原型 //创建实例对象 var fn = new Fn() // 内部语句: this.__proto__ = Fn.prototype console.log(fn.__proto__) // 3. 对象的隐式原型的值为其对应构造函数的显式原型的值 console.log(Fn.prototype===fn.__proto__) // true
原型链(所有函数的隐式原型都指向同一原型,都一样)
Function、Object、普通构造函数的原型链关系
图中有几个难点:
1.Function构造函数可以用Function.__proto__来访问Function.prototype. 这是因为Function构造函数的构造函数是他本身,作为实例化对象的角色来访问,可行。
2.任何函数都是函数,他都继承Function的所有属性和方法,而Function是内置的构造函数,也是对象,都是继承Object的所有属性和方法。
/* 1. 函数的显示原型指向的对象默认是空Object实例对象 */ console.log(Fn.prototype instanceof Object) // true console.log(Object.prototype instanceof Object) // false console.log(Function.prototype instanceof Object) // true /* 2. 所有函数都是Function的实例(包含Function) */ console.log(Function.__proto__===Function.prototype) /* 3. Object的原型对象的隐式原型是原型链尽头 */ console.log(Object.prototype.__proto__) // null
读取属性:
1. 读取对象的属性值时: 会自动到原型链中查找 2. 设置对象的属性值时: 不会查找原型链, 如果当前对象中没有此属性, 直接添加此属性并设置其值 3. 方法一般定义在原型中, 属性一般通过构造函数定义在对象本身上
function Fn() { } Fn.prototype.a = 'xxx' var fn1 = new Fn() console.log(fn1.a, fn1) var fn2 = new Fn() fn2.a = 'yyy' console.log(fn1.a, fn2.a, fn2)
运行: