原型和原型链-JavaScript

news/2024/7/19 14:33:28 标签: javascript, js

原型和原型链

原型:每个对象都有原型对象。
原型链:原型对象也可能拥有原型,一层接着一层,并从其中继承方法和属性。

此外:

1⃣️:每个 实例对象 都有 __proto__ 来访问原型对象。
2⃣️:每个 构造函数 都有 prototype 来访问原型对象。
3⃣️:并且该 实例对象__proto__ == 该 构造函数prototype
4⃣️:查找属性时,实例对象 会依次查找继承的原型对象属性。
5⃣️:大部分 js 对象都是位于原型链顶端的 Object 的实例。

听着比较抽象:

javascript">        function a(){

        }
        let b = new a();

这里的 a 就代表 构造函数
这里的 b 就代表 实例对象

原型对象

javascript">        let ad = {
            name: "hello world"
        };
        ad.toString();

想象一下,我们并没有为对象 ad 设置 toString() 方法,那么它从哪里获取该方法并调用它的呢?

调用对象 ad 的 __proto__ 方法:

javascript">		console.log(ad.__proto__);

输出:

javascript">	{
		constructor: ƒ Object()
		hasOwnProperty: ƒ hasOwnProperty()
		isPrototypeOf: ƒ isPrototypeOf()
		propertyIsEnumerable: ƒ propertyIsEnumerable()
		toLocaleString: ƒ toLocaleString()
		toString: ƒ toString()
		valueOf: ƒ valueOf()
		__defineGetter__: ƒ __defineGetter__()
		__defineSetter__: ƒ __defineSetter__()
		__lookupGetter__: ƒ __lookupGetter__()
		__lookupSetter__: ƒ __lookupSetter__()
		get __proto__: ƒ __proto__()
		set __proto__: ƒ __proto__()
	}

可以看到对象 ad 的原型对象中包含了 toString() 方法。

首先,浏览器将在当前对象中查找 toString() 方法。如果找不到,它将调用ad .__ proto__方法来检查是否包含该方法。如果没有,就继续调用ad .__ proto__ .__ proto__方法搜索,依此类推,直到查询的 .__ proto__为空为止。

属性查找

创建构造函数 aa,并为其原型对象设置 age=20。

javascript">        function aa(){
            this.name = "anny"
        }
        aa.prototype.age = 20;
        let bb = new aa();
        console.log(bb.name);
        console.log(bb.age);

输出:

javascript">anny
20

首先,浏览器查找实例对象 bb 中是否含有 name 属性,有,则显示出来。接着查找实例对象 bb 中是否含有 age 属性,没有,则调用 bb.__proto__ 查找是否含有 age 属性,有,age=20,显示出来。

打印看一下 bb 原型对象的结构(console.log(bb.__proto__)):

javascript">	{
		age: 20
		constructor: ƒ aa()
		__proto__: Object
	}

属性遮蔽

为构造函数 aa 设置 age = 23,

javascript">        function aa(){
            this.age = 23
        }
        aa.prototype.age = 20;
        let bb = new aa();
        console.log(bb.age);

输出:

javascript">23

可以发现原型age的值未展示出来,当在自身属性查找到该属性后,就不会再去原型对象中搜索了,这种情况称之为“属性遮蔽”。

prototype 和 proto

实例对象的 __proto__ 总是指向构造函数的 prototype

bb.__proto__ == aa.prototype

javascript">onsole.log(bb.__proto__ == aa.prototype)

输出:

javascript">true

当前使用的是通过实例对象来自动寻找构造函数中不存在且搜索继承原型对象中的属性。

如果是构造函数呢。

构造函数查找原型对象

为构造函数创建 name 属性,原型对象设置属性 age。

javascript">       function aa(){
            this.name = "anny";
        }
        aa.prototype.age = 20;
        console.log(aa.name);
        console.log(aa.age);

输出:

javascript">aa
undefined

为什么 aa.name 没有输出 “anny”?

直接调用构造函数的 name 属性,会返回 构造函数的 函数名称。

另外:

aa.prototype.constructor.name == aa.name

其中:

aa.prototype.constructor 返回的是该构造函数

javascript">ƒ aa(){
            this.name = "anny";

        }

那如果非要获取 aa 函数中的 name 属性呢:

通过 new 创建函数 aa 的实例对象 bb,直接访问即可,赋值当然也是如此,bb.name = “XXXX” 。

javascript">        let bb = new aa();
        console.log(bb.name);

输出:anny

为什么 aa.age 没有输出 20 呢?

不是说当前对象中没有该 属性,就自动通过 .__proto__ 去寻找吗?

实例对象确实会这么做,但构造函数却不会自动调用其 prototype 方法往上层寻找。

如果想要实现自动寻找原型对象中的属性,就通过 new 创建实例对象来实现。

除了使用 实例对象 的 .__proto__ 方法,也可以使用 Object.getPrototypeOf() 来查找原型对象。

javascript">console.log(Object.getPrototypeOf(bb))

或:

javascript">console.log(Object.getPrototypeOf(new aa()))

注意前后的关系,传入的参数为构造函数的实例对象。

总结:

创建构造函数 aa 和实例对象 bb:

javascript">        function aa(){
            this.name = "anny";
        }
        let bb = new aa();

创建原型对象属性(使用prototype):

javascript">		aa.prototype.age = 20;
javascript">		aa.prototype.speak = function(){
            alert("hello world");
        }

查找原型对象(两种方法指向同一原型对象且相等):

javascript">
console.log(aa.prototype);
------------or-------------
console.log(bb.__proto__);

查找属性值:

javascript">
console.log(bb.name);
console.log(bb.age);
bb.speak();
-----------or--------------
console.log(aa.prototype.age)
aa.prototype.speak()


http://www.niftyadmin.cn/n/965423.html

相关文章

VMWare Tools Centos 安装

在VMWare中安装了CentOS系统的电脑方法/步骤 1首先启动CentOS系统,进入到桌面,如下图所示: CentOS虚拟机中安装VMWare Tools单击VMWare的【虚拟机】菜单,选择【安装VMWare Tools】命令,如下图所以: CentOS虚…

Spark的代码模块

scheduler:负责整体的Spark应用、任务调度的代码。 broadcast:Broadcast(广播变量)的实现代码 deploy:含有Spark部署与启动运行的代码。 common:不是一个文件夹,而是代表Spark通用的类和逻辑实现…

fuser和卸载资源方法

[rootweb2-server yum.repos.d]# umount /mnt/cdrom/ -f //强制卸载也不行umount2: 设备或资源忙umount: /mnt/cdrom: device is busy.(In some cases useful info about processes that usethe device is found by lsof(8) or fuser(1))umount2: 设备或资源忙附fuser命令详…

-----------什么是图?------------

图,现在终于接触到了最短路径,等问题了. 在我们刚刚开始的时候就讲了好几种关系,例如"多对多" 什么是图(Graph) 表示多对多的关系 包含 一组顶点:通常用V(Vertex)表示顶点集合. 一组边:通常用E(Edge)表示边的集合 边时顶点对:(v,w)∈E,其中的v,w∈V 有向边<v,w>…

html css print打印,打印样式

html css print打印&#xff0c;打印样式 文章目录html css print打印&#xff0c;打印样式1&#xff1a;去除默认页眉页脚2&#xff1a;分页3&#xff1a;自定义页眉页脚4&#xff1a;单独设置打印样式默认打印效果如上&#xff0c;分别表示日期&#xff0c;html标题&#xff…

linux(centos6.5)系统中忘记mysql root的密码的解决方法

1)首先编辑mysql的主配置文件 vim /etc/my.cnf2&#xff09;在[mysqld]字段下加入skip-grant# Try number of CPUs*2 for thread_concurrencythread_concurrency 8&#xff08;放在这条语句后面&#xff0c;&#xff09;skip-grant3)重启mysql服务。/etc/init.d/mysqld rest…

mysql 用一个表的一列,去更新另一表的一列

2019独角兽企业重金招聘Python工程师标准>>> mysql 用一个表的一列&#xff0c;去更新另一表的一列 设有表t1&#xff1a;idname1null2null3null表t2&#xff1a;idname1 aa2 bb3 cc现要将t2的name列赋值到t1的name列中&#xff0c;以id作为对应行&#xff1a;…

win 7远程桌面连接不上

我有同事想要连接某台win7 的桌面&#xff0c;可是连接不上&#xff0c;这时候怎么检查呢&#xff1f;检查防火墙Administrator用户是默认可以远程的&#xff0c;在“系统属性----》远程”&#xff0c;确保已经打开了远程。最重要的&#xff0c;我就是用这个解决的。转载于:ht…