JavaScript 对象是动态的属性“包”(指其自己的属性)。JavaScript 对象有一个指向一个原型对象的链。当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。
// 创建了一个函数 也是构造函数 Foofunction Foo(){this.a = 1this.b = 2}// 构造函数实例化过程 通过 new 会创造属于自己的 this 对象,并在执行完之后返回它var foo = new Foo()// 在Foo函数的原型上定义属性// 尽量不要在 Foo 函数的原型上直接定义 Foo.prototype = {b: 3, c: 4,}这样会直接打破原型链Foo.prototype.b = 3;Foo.prototype.c = 4;// foo.[[Prototype]] 有属性 b 和 c (其实就是 foo.__proto__ 或者 foo.constructor.prototype)// foo.[[Prototype]].[[Prototype]] 是 Object.prototype// 最后 foo.[[Prototype]].[[Prototype]].[[Prototype]] 即 Object.prototype.__proto__ 是 null// 这就是原型链的末尾,即 null (也有一说 Object.prototype 就是原型链的末尾)// 综上,整个原型链如下:// {a: 1, b: 2} -> {b: 3, c: 4} -> Object.prototype -> nullconsole.log(foo.toString === Object.prototype.toString); // true -> 由此可证 Object.prototype 在 foo 的原型链上console.log(foo.a); // 1// -> a 是 foo 的自身属性吗?是的,该属性的值为 1console.log(foo.b); // 2// -> b 是 foo 的自身属性吗?是的,该属性的值为 2// 原型上也有一个'b'属性,但是它不会被访问到。// 这种情况被称为 "属性遮蔽 (property shadowing)"// 先访问自身有的,自身没有再去访问原型链上的console.log(foo.c); // 4// -> c 是 foo 的自身属性吗?不是,那看看它的原型上有没有// -> c 是 foo.[[Prototype]] 的属性吗?是的,该属性的值为 4console.log(foo.d); // undefined// -> d 是 foo 的自身属性吗?不是,那看看它的原型上有没有// -> d 是 foo.[[Prototype]] 的属性吗?不是,那看看它的原型上有没有// -> d 是 foo.[[Prototype]].[[Prototype]] 的属性吗?不是,那看看它的原型上有没有// -> foo.[[Prototype]].[[Prototype]].[[Prototype]] 为 null,停止搜索// 找不到 d 属性,返回 undefined
当继承的函数被调用时,this指向的时当前继承者的对象,而不是继承函数的函数所在的原型对象
var obj = {name: 'obj',say: function () {console.log(this.name);},}// 此时调用 obj.say -> this 指向的是 objobj.say() // obj// newObj 是一个继承 obj 的对象// 相当于 newObj.[[prototype]] === objvar newObj = Object.create(obj)// 创建属于 newObj 的自身属性 namenewObj.name = "newObj"/*** -> newObj.say 查找时先查找自身没有* -> 去原型链上查找 newObj.[[prototype]] 因为它继承于 obj ,所以有 say 函数可执行** -> 调用 newObj.say 时,'this' 指向了 newObj 即 newObj.name* -> 有因为 newObj 自身有 name 这个属性 , 所以输出 newObj*/newObj.say() // newObj
JavaScript 原型
在上面说过,在JavaScript中,函数是允许拥有属性的。
所有的函数都会有一个特别的属性prototype
function Foo() { }console.log(Foo.prototype);
我们打印出来后可以看到这么一个对象
{constructor: ƒ Foo(),__proto__: {constructor: ƒ Object(),hasOwnProperty: ƒ hasOwnProperty(),isPrototypeOf: ƒ isPrototypeOf(),propertyIsEnumerable: ƒ propertyIsEnumerable(),toLocaleString: ƒ toLocaleString(),toString: ƒ toString(),valueOf: ƒ valueOf()}}
现在我们来给 Foo的原型对象加点自己的私有私货
function Foo() { }Foo.prototype.lang = 'JavaScript'console.log(Foo.prototype);
可以看到输出后内容为
{lang: "JavaScript",constructor: ƒ Foo(),__proto__: {constructor: ƒ Object(),hasOwnProperty: ƒ hasOwnProperty(),isPrototypeOf: ƒ isPrototypeOf(),propertyIsEnumerable: ƒ propertyIsEnumerable(),toLocaleString: ƒ toLocaleString(),toString: ƒ toString(),valueOf: ƒ valueOf()}}
