这样理解原型与原型链比较简单
栏目: JavaScript · 发布时间: 7年前
内容简介:在JavaScript中,有两个原型,分别是注:在ECMA-262第5版中管这个 _prototype 属性:
原型
在JavaScript中,有两个原型,分别是 prototype 和 _ proto_
注:在ECMA-262第5版中管这个 _ proto_ 叫 [[Prototype]]
prototype 属性:
这是一个 显式原型 属性,只有 函数 才拥有该属性。
_ proto_ 属性:
这是每个 对象 都有的 隐式原型 属性,指向了创建该对象的构造函数的原型。
什么是函数?什么是对象?
创建函数有两种方式:
①、通过 function 关键字定义
②、通过 new Function
其中函数又可以分为普通函数和构造函数,两者唯一的区别就是调用的方式不同,语法上没有差异
function normalFn(){} // 普通函数(函数名首字母小写)
function StructFn(){} // 构造函数(函数名首字母大写)
创建对象的方式多种多样,其中传统方法是通过构造函数来创建对象,使用 new 关键字即可创建
let obj = new StructFn() // obj就是一个对象
在JS中,万物都是对象,函数也属于对象,只不过函数相对于对象有着更为精确的定义
原型初探
为了证明 prototype属性 是函数独有,而__proto__是每个对象都有的,我们可以测试以下代码:
function a(){}
console.log(a.prototype); // {constructor: ƒ}
console.log(a.__proto__); // ƒ () { [native code] }
let obj = new Object()
console.log(obj.prototype) // undefined
console.log(obj.__proto__) // {constructor: ƒ, __defineGetter__: ƒ, …}
可以看到对象的 显式原型(prototype) 为undefined
*注意:
undefined和 null 同属于对象,但是它们都没有原型,为什么? 在JavaScript中,目前只有两个只有一个值的数据类型,那就是 undefined 和 null*
由于这两种数据类型有且只有一个值,并且没有方法,所以自然而然就没有原型了。
有的同学会问,那NaN呢?NaN是属于Number数据类型的,属于对象,只有_ proto_ 属性
console.log(undefined.__proto__); // 报错:Uncaught TypeError: Cannot read property '__proto__' of undefined
console.log(null.__proto__); // 报错:Uncaught TypeError: Cannot read property '__proto__' of null
console.log(NaN.__proto__) ; // Number {0, constructor: ƒ, toExponential: ƒ, …}
构造函数创建对象,其中发生什么?
1.创建了一个新对象 2.将新创建的对象的隐式原型指向其构造函数的显式原型。 3.将this指向这个新对象 4.返回新对象
注意看第二条:将新创建的对象的隐式原型指向其构造函数的显式原型
也就是说 对象.__prototype === 构造函数.prototype
function fn(){}
let obj = new fn();
console.log(obj.__proto__ === fn.prototype); // true
那么这样,我们在为构造函数添加原型方法时,就可以通过两种方法取访问了
fn.prototype.more = function(){console.log('fn-prototype-more')}
// 1、通过构造函数的显式原型
fn.prototype.more()
// 2、通过对象的隐式原型
obj.__proto__.more()
原型链
原型链:实例与原型之间的链接
先来看一个例子:
function Abc(){}
Abc.prototype.fn = function(){console.log("Abc-prototype-fn")};
let obj = new Abc()
obj.fn() // Abc-prototype-fn
从上面的代码我们可以看到。构造函数 Abc 和对象实例 obj 都没有fn这个方法,之所以对象obj能够访问到Abc的原型方法,是通过原型链来寻找,借用了 _ proto_ 这个属性
所以以下的代码也是等价的
obj.fn() // Abc-prototype-fn obj.__proto__.fn() // Abc-prototype-fn
再来看一个复杂的例子:
function Abc(){
this.fn = function(){console.log("Abc-fn")};
}
Abc.prototype.fn = function(){console.log("Abc-prototype-fn")};
Object.prototype.fn = function(){console.log("Object-fn")};
let obj = new Abc()
obj.fn = function(){console.log("obj-fn")};
obj.fn()
这里有4个重名的fn函数,分别是:
①、实例对象obj的方法
②、构造函数Abc的方法
③、构造函数Abc原型上的方法
④、Obecjt对象原型上的方法
为了表示方法的寻找过程,我画了一幅很丑陋的图,大家不要介意哈!
在寻找某个方法或者属性的时候,会先从自身对象寻找;
如果没有,则会去构造函数寻找;注意这里还没用到原型链;
紧接着,会到构造函数的原型上寻找,此时就是对象Abc通过 _ proto_ 属性进行寻找
接下来,会到Object对象的原型寻找,Object对象是所有对象之父,可以说所有的对象都继承了Object,此时构造函数通过_ proto_ 属性找到了Object的prototype
最后的最后,由于Object._ proto_ 指向了null,这也就是原型链的末端
第一道原型链是 obj._ proto_ ,访问到了Abc的prototype
console.log(obj.__proto__ === Abc.prototype) // true
第二道原型链是 obj . __proto__ . __proto__ ,访问到了Object的prototype
console.log(obj.__proto__.__proto__ === Object.prototype) //true
第三道原型链是 obj . __proto__ . __proto__ . __proto__ 访问到了Object的prototype . __proto__,,最后指向了null
console.log(obj.__proto__.__proto__.__proto__ === null) //true
这样我们就可以看到了整个原型链的流程了
以上所述就是小编给大家介绍的《这样理解原型与原型链比较简单》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 理解原型其实是理解原型链
- 深入理解JS原型与原型链
- 轻松理解JavaScript原型到原型链
- 如何理解JavaScript的原型和原型链?
- 从instanceof身上深入理解原型/原型链
- JavaScript 中原型与原型链的简单理解
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Head First Rails
David Griffiths / O'Reilly Media / 2008-12-30 / USD 49.99
Figure its about time that you hop on the Ruby on Rails bandwagon? You've heard that it'll increase your productivity exponentially, and allow you to created full fledged web applications with minimal......一起来看看 《Head First Rails》 这本书的介绍吧!