大家好我是小盛,今天来谈谈对原型的看法(大佬勿喷)
在js中每个对象拥有一个原型对象,对象以其原型为模板、从原型继承方法和属性。原型对象也可能拥有原型,并从中继承方法和属性,一层一层、以此类推。这种关系常被称为原型链 (prototype chain),它解释了为何一个对象会拥有定义在其他对象中的属性和方法。
准确地说,这些属性和方法定义在Object的构造器函数(constructor functions)之上的prototype
属性上,而非对象实例本身。在javascript中,函数可以有属性。 每个函数都有一个特殊的属性叫作原型(prototype)
function doSomething(){}
console.log( doSomething.prototype );
var doSomething = function(){};
console.log( doSomething.prototype );
正如上面所看到的, doSomething
函数有一个默认的原型属性,它在控制台上面呈现了出来. 运行这段代码之后,控制台上面应该出现了像这样的一个对象.
{
constructor: ƒ doSomething(),
__proto__: {
constructor: ƒ Object(),
hasOwnProperty: ƒ hasOwnProperty(),
isPrototypeOf: ƒ isPrototypeOf(),
propertyIsEnumerable: ƒ propertyIsEnumerable(),
toLocaleString: ƒ toLocaleString(),
toString: ƒ toString(),
valueOf: ƒ valueOf()
}
}
现在,我们可以添加一些属性到 doSomething 的原型上面,如下所示.
function doSomething(){}
doSomething.prototype.foo = "bar";
console.log( doSomething.prototype );
结果:
{
foo: "bar",
constructor: ƒ doSomething(),
__proto__: {
constructor: ƒ Object(),
hasOwnProperty: ƒ hasOwnProperty(),
isPrototypeOf: ƒ isPrototypeOf(),
propertyIsEnumerable: ƒ propertyIsEnumerable(),
toLocaleString: ƒ toLocaleString(),
toString: ƒ toString(),
valueOf: ƒ valueOf()
}
}
然后,我们可以使用 new 运算符来在现在的这个原型基础之上,创建一个 doSomething
的实例。正确使用 new 运算符的方法就是在正常调用函数时,在函数名的前面加上一个 new
前缀. 通过这种方法,在调用函数前加一个 new
,它就会返回一个这个函数的实例化对象. 然后,就可以在这个对象上面添加一些属性.
最后原型链上面的所有的 __proto__
都被找完了, 浏览器所有已经声明了的 __proto__
上都不存在这个属性,然后就得出结论,这个属性是 undefined
.
理解原型对象
写一个构造函数
function Person(first, last, age, gender, interests) {
// 属性与方法定义
};
然后创建一个对象实例:
var person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);
在这个列表中,你可以看到定义在 person1
的原型对象、即 Person()
构造器中的成员—— name
、age
、gender
、interests
、bio
、greeting
。同时也有一些其他成员—— watch
、valueOf
等等——这些成员定义在 Person()
构造器的原型对象、即 Object
之上。
调用 person1
的“实际定义在 Object
上”的方法
这个方法仅仅返回了被调用对象的值。在这个例子中发生了如下过程:
浏览器首先检查,person1
对象是否具有可用的 valueOf()
方法。
-
如果没有,则浏览器检查
person1
对象的原型对象(即Person
构造函数的prototype属性所指向的对象)是否具有可用的valueof()
方法。 -
如果也没有,则浏览器检查
Person()
构造函数的prototype属性所指向的对象的原型对象(即Object
构造函数的prototype属性所指向的对象)是否具有可用的valueOf()
方法。这里有这个方法,于是该方法被调用。
prototype属性:继承成员被定义的地方
继承的属性和方法是定义在 prototype
属性之上的(你可以称之为子命名空间 (sub namespace) )——那些以 Object.prototype.
开头的属性,而非仅仅以 Object.
开头的属性。prototype
属性的值是一个对象,我们希望被原型链下游的对象继承的属性和方法,都被储存在其中。
constructor属性
每个实例对象都从原型中继承了一个constructor属性,该属性指向了用于构造此实例对象的构造函数
以上就是我个人的理解了,当然也借鉴了官方文档大佬勿喷,谢谢!此文仅为自己学习使用