资讯专栏INFORMATION COLUMN

js中的prototype、__proto__、constructor

fizz / 2889人阅读

摘要:一旦原型对象被赋予属性和方法那么由相应的构造函数创建的实例会继承上的属性和方法为什么只有函数才有属性规范就这么定的。其它的构造器的都是一个对象。

哪些对象有原型?
所有的对象在默认情况下都有一个原型,因为原型本身也是对象,所以每个原型自身又有一个原型(只有一种例外,默认的对象原型在原型链的顶端)

prototype属性
prototype是每个函数对象都具有的属性,被称为原型对象,而__proto__属性才是每个对象才有的属性。一旦原型对象被赋予属性和方法,那么由相应的构造函数创建的实例会继承prototype上的属性和方法

为什么只有函数才有prototype属性?ES规范就这么定的。
当你创建函数时,JS会为这个函数自动添加prototype属性, 值是一个有 constructor 属性的对象,不是空对象。而一旦你把这个函数当作构造函数(constructor)调用(即通过new关键字调用),那么JS就会帮你创建该构造函数的实例,实例继承构造函数prototype的所有属性和方法(实例通过设置自己的__proto__指向承构造函数的prototype来实现这种继承)

constructor属性和prototype属性
每个函数都有prototype属性,而这个prototype的constructor属性会指向这个函数。

proto
对象__proto__属性的值就是它所对应的原型对象

var one = {x: 1};
var two = new Object();
one.__proto__ === Object.prototype // true
two.__proto__ === Object.prototype // true
one.toString === one.__proto__.toString // true

下面我们来看个例子来帮助理解这三个属性

function Person(name){
this.name = name;
}
var p1 = new Person("louis");
console.log(Person.prototype);//Person原型 {constructor: Person(name),__proto__: Object}
console.log(p1.prototype);//undefined
console.log(Person.__proto__);//空函数, function(){}
console.log(p1.__proto__ == Person.prototype);//true

我们发现, Person.prototype(原型) 默认拥有两个属性:
constructor 属性, 指向构造器, 即Person本身
proto 属性, 指向一个空的Object 对象
而p1作为非函数对象, 自然就没有 prototype 属性

下面来看看__proto__属性:

p1.__proto__ 属性 指向的是 构造器(Person) 的原型, 即 Person.prototype.
这里我们发现: 原型链查询时, 正是通过这个属性(__proto__) 链接到构造器的原型, 从而实现查询的层层深入.
Person.__proto__ 属性 指向的是一个空函数( function(){} ),

console.log(Person.__proto__ === Function.prototype);//true

Person 是构造器也是函数(function), Person的__proto__ 属性自然就指向 函数(function)的原型, 即 Function.prototype.

这说明 所有的构造器都继承于Function.prototype

既然所有的构造器都来自于Function.prototype, 那么Function.prototype 到底是什么呢?
我们借用 typeof 运算符来看看它的类型.

console.log(typeof Function.prototype) // "function"

实际上, Function.prototype也是唯一一个typeof XXX.prototype为 “function”的prototype。其它的构造器的prototype都是一个对象。如下:

console.log(typeof Number.prototype)   // object
console.log(typeof Boolean.prototype)  // object
console.log(typeof String.prototype)   // object
console.log(typeof Object.prototype)   // object
console.log(typeof Array.prototype)    // object
console.log(typeof RegExp.prototype)   // object
console.log(typeof Error.prototype)    // object
console.log(typeof Date.prototype)     // object

既然Function.prototype 的类型是函数, 那么它会拥有 proto 属性吗, Function.prototype.__proto__ 会指向哪里呢? 会指向对象的原型吗? 请看下方:

console.log(Function.prototype.__proto__ === Object.prototype) // true

透过上方代码, 且我们了解到: Function.prototype 的类型是函数, 也就意味着一个函数拥有 proto 属性, 并且该属性指向了对象(Object)构造器的原型. 这意味着啥?

根据我们在前面了解到的: proto 是对象的内部属性, 它指向构造器的原型.

这意味着 Function.prototype 函数 拥有了一个对象的内部属性, 并且该属性还恰好指向对象构造器的原型. 它是一个对象吗? 是的, 它一定是对象. 它必须是.实际上, JavaScript的世界观里, 函数也是对象, 函数是一等公民.

这说明所有的构造器既是函数也是一个普通JS对象,可以给构造器添加/删除属性等。同时它也继承了Object.prototype上的所有方法:toString、valueOf、hasOwnProperty等。

Object.prototype
函数的 proto 属性指向 Function.prototype, 如: Person.__proto__ —> Function.prototype

Function.prototype 函数的 proto 属性指向 Object.prototype, 如: Function.prototype.__proto__ —> Object.prototype.

那么Object.prototype.__proto__ 指向什么呢?

console.log(Object.prototype.__proto__ === null);//true

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/96325.html

相关文章

  • js内功修炼之九阳神功--原型链

    摘要:写在前面如果说是一本武学典籍,那么原型链就是九阳神功。那么,如何修炼好中的九阳神功呢真正的功法大成的技术是从底层上去理解,那种工程师和码农的区别就在于对底层的理解,当你写完一行代码,或者你遇见一个解决的速度取决于你对底层的理解。 写在前面 如果说JavaScript是一本武学典籍,那么原型链就是九阳神功。在金庸的武侠小说里面,对九阳神功是这样描述的:练成「九阳神功」后,会易筋洗髓;生出...

    苏丹 评论0 收藏0
  • js内功修炼之九阳神功--原型链

    摘要:写在前面如果说是一本武学典籍,那么原型链就是九阳神功。那么,如何修炼好中的九阳神功呢真正的功法大成的技术是从底层上去理解,那种工程师和码农的区别就在于对底层的理解,当你写完一行代码,或者你遇见一个解决的速度取决于你对底层的理解。 写在前面 如果说JavaScript是一本武学典籍,那么原型链就是九阳神功。在金庸的武侠小说里面,对九阳神功是这样描述的:练成「九阳神功」后,会易筋洗髓;生出...

    Profeel 评论0 收藏0
  • js内功修炼之九阳神功--原型链

    摘要:写在前面如果说是一本武学典籍,那么原型链就是九阳神功。那么,如何修炼好中的九阳神功呢真正的功法大成的技术是从底层上去理解,那种工程师和码农的区别就在于对底层的理解,当你写完一行代码,或者你遇见一个解决的速度取决于你对底层的理解。 写在前面 如果说JavaScript是一本武学典籍,那么原型链就是九阳神功。在金庸的武侠小说里面,对九阳神功是这样描述的:练成「九阳神功」后,会易筋洗髓;生出...

    morgan 评论0 收藏0
  • JS创建对象模式及其对象原型链探究(三):构造函数模式

    摘要:创建对象与工厂模式的区别没有显示地创建对象直接将方法和属性付给了对象没有语句构造函数应该始终以一个大写字母开头。创建构造函数的实例,必须使用操作符。 构造函数模式 ECMAScript中的构造函数可用来创建特定类型的对象,像Object和Array这样的原生构造函数。也可以创建自定义的构造函数,从而定义自定义对象类型的属性和方法。 1.创建对象 function Person(name...

    Martin91 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<