《无所不能的JavaScript · prototype 原型链》

📢 大家好,我是 【战神刘玉栋】,有10多年的研发经验,致力于前后端技术栈的知识沉淀和传播。 💗
🌻 近期刚转战 CSDN,会严格把控文章质量,绝不滥竽充数,欢迎多多交流。👍

文章目录


写在前面的话

又回到前端系列了,之前写后端和其他内容去了,进度落下,赶紧补一下。
本篇文章介绍一下 JavaScript 里面的一些经典知识点,先以prototype原型链开篇。
让我们开始!


快速了解

【概念说明】
JavaScript中,每个对象都有一个原型prototype属性,它指向另一个对象。这个被指向的对象也有自己的原型,以此类推,最终形成了一个原型链。原型链的顶端是Object.prototype,它是所有对象的根原型。
当我们访问一个对象的属性时,如果该对象自身没有这个属性,JavaScript会沿着原型链向上查找,直到找到匹配的属性或者到达原型链的末端。

【用代码说话】
直接上一段示例代码:

function Person(name, age) {this.name = name;this.age = age;
}Person.prototype.sayHello = function() {console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
};const alice = new Person('Alice', 20);
alice.sayHello();  // 输出:Hello, my name is Alice and I am 20 years old.

浏览器运行该代码,F12控制台查看alice对象,如下图所示:
image.png
分析一下上图的这些内容:

  • alice 对象包含 age 和 name 两个属性和一个原型对象
  • 原型对象可以通过 alice.proto 访问,或 Person.prototype,两者是相等的
  • 原型对象的再上一次层指向 Object.prototype,再往上一层就是 null
  • 对,没有错,你看到了一个类似链式调用的东西,这是原型链

image.png

Tips:学习前端,特别是JavaScript,直接运行Demo,F12查看效果是一个快速学习方式。


知识介绍

prototype 与原型链

在 JavaScript 中,prototype 是用于实现继承和共享属性与方法的一种机制。每一个 JavaScript 对象(除了 null)在创建时都与另一个对象(称为其 “prototype”)相关联。这个 “prototype” 对象本身也有一个 “prototype”,这样一直到一个对象的 prototype 为 null 为止,这形成了一个链条,被称为 “原型链”(prototype chain)。


关于 prototype 继承

所有的 JavaScript 对象都会从一个 prototype(原型对象)中继承属性和方法:
Date 对象从 Date.prototype 继承。
Array 对象从 Array.prototype 继承。
Person 对象从 Person.prototype 继承。
所有 JavaScript 中的对象都是位于原型链顶端的 Object 的实例。
JavaScript 对象有一个指向一个原型对象的链。当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。
Date 对象、Array 对象、以及 Person 对象从 Object.prototype 继承。

console.log(alice.__proto__ === Person.prototype);  // 输出:true
console.log(Person.prototype.__proto__ === Object.prototype);  // 输出:true
console.log(Object.prototype.__proto__ === null);  // 输出:true

使用 prototype 添加属性

JavaScript 对象要添加新的属性或方法,很简单。
有点像 Java 的Map那边随意,直接追加即可,类似 alice.xxx = ‘1111’
但如果想追加的属性是和其他对象,继承和共享的,那就可以用到 prototype 方式。

Person.prototype.nationality = "English";
console.log(alice.__proto__.nationality);

使用 prototype 属性就可以给对象的构造函数添加新的属性和方法。


关键词 constructor
前面示例一定看到了原型对象上有一个 constructor 属性,这是何物?
其实就是和 Java 中的构造函数类似的概念,用下面代码可以看出来,原型的 constructor就是指向类本身。

alice.__proto__.constructor === Person  // true

结合前面说的内容, 整个概念是否绕来绕去,找了下面这张图,感觉能比较直观了看明白之间的调用关系。
image.png

几个概念复述一下:

  • prototype 是 JavaScript 中实现继承和共享属性与方法的基础。
  • 构造函数的 prototype 属性用于定义所有实例共享的方法和属性。
  • 每个对象都有一个 proto 属性,对象通过该属性引用其原型,形成原型链。
  • 每个函数在定义时会自动获得一个 prototype 属性,这个属性是一个对象,包含一个 constructor 属性指向函数本身。
  • 当访问对象的一个属性或方法时,JavaScript 会首先在对象本身查找。如果没有找到,它会沿着原型链向上查找,直到找到或到达链的末端(即 null)。

Tips:理解 prototype 和原型链是掌握 JavaScript 面向对象编程的关键。通过这种机制,可以实现代码的重用和更高效的内存使用。


原型链的性能和优化

原型链在JavaScript中的运作会带来一定的性能开销。在访问属性时,查找过程需要沿着原型链逐级查找,直到找到属性或者到达原型链末端。因此,过深的原型链结构可能导致性能下降。为了优化性能,可以合理设计对象的原型链,避免过于庞大和复杂的结构。

Tips:简单来说,就是不要太复杂,但一般前端设计也不应该很重,最多父子类的结构了,损耗可以忽略不计。


Java 和 JavaScript 面向对象

JavaScript 和 Java 都是面向对象编程语言,但它们在类和对象的实现和使用上有一些显著的差异。以下是对 JavaScript 中类和对象的介绍,并通过 Java 的概念进行对比说明。
类:
JavaScript ES6 引入类,使得类定义更加简洁和直观,但其底层依然基于原型链。
Java 中类是核心概念,定义了对象的属性和行为。
对象:
JavaScript 对象是键值对的集合,可以动态修改。
Java 对象是类的实例,属性和方法在类中定义。
继承:
JavaScript 通过 extends 关键字实现类的继承,使用 super 调用父类的构造函数和方法。
Java 通过 extends 关键字实现类的继承,使用 super 关键字调用父类的构造函数和方法。
总结:
尽管 JavaScript 和 Java 在语法和特性上有很多不同,但它们都支持面向对象编程的基本概念,如类、对象和继承。JavaScript 的类和对象模型更加灵活和动态,而 Java 的类和对象模型更为静态和严格。


用法拓展

创建对象的N种方式

对于 Java 后端程序猿而言,类与对象不是 Java 面向对象的概念吗,前端怎么也有?
其实 JavaScript 已经不是后端眼中随意简单的脚本语言了,Java 有的概念它也有,Java 能做的很多事情,它也能做。
我们有多种方式可以创建对象,根据不同的创建方式,JavaScript对象的原型链也会有所不同。

构造函数方式
使用构造函数方式创建对象的原型是构造函数的原型对象(prototype)。
这个前面章节都在介绍这种方式,示例代码再贴一下?

function Person(name, age) {this.name = name;this.age = age;
}Person.prototype.sayHello = function() {console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
};const alice = new Person('Alice', 20);
alice.sayHello();  // 输出:Hello, my name is Alice and I am 20 years old.console.log(alice.__proto__ === Person.prototype);  // 输出:true

字面量方式创建对象
使用字面量方式创建对象的原型是 Object.prototype,即所有字面量创建的对象都是 Object 的实例。

const lwObj = {name: '战神',age: 32,sayHello() {console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);}
};console.log(lwObj.__proto__ === Object.prototype);// 输出:true

Class 方式创建对象
在 ES6 之前,JavaScript 没有类的概念,开发者主要通过构造函数和原型链来实现面向对象编程。ES6 引入了类的语法,使得定义和继承类更加直观和类似于其他面向对象语言(如 Java)。
Class 方式创建的对象和构造函数方式创建的对象一样,其原型是Class构造函数的prototype属性所指向的对象。

Tips:这也是推荐方式,不过一般复杂的前端逻辑才会去专门设计和定义类。

class PersonClass {constructor(name, age) {this.name = name;this.age = age;}sayHello() {console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);}
}const hanMei = new PersonClass('HanMei', 25);
hanMei.sayHello();  // 输出:Hello, my name is HanMei and I am 25 years old.	console.log(hanMei.__proto__ === PersonClass.prototype);  // 输出:true

prototype 实现继承

直接看下面的代码,就是基于原型链的特性。

// 定义父类函数
function Company(){  this.boss = 'lw';  this.name = 'cjwmy';  this.show = function(){  return this.boss + ',' + this.name;  }  
}  // 定义子类函数
function Zysoft(){  this.soft = ['zyhip','zycomm'];  
}  // 绑定原型链
Zysoft.prototype = new Company();  
let one = new Zysoft();  
console.log(one.show());  //lw,cjwmy

扩展原有对象的方法 Demo

首先,我们要先了解一下类的概念,JavaScript 本身是一种面向对象的语言,它所涉及的元素根据其属性的不同都依附于某一个特定的类。我们所常见的类包括:数组变量(Array)、逻辑变量(Boolean)、日期变量(Date)、结构变量(Function)、数值变量(Number)、对象变量(Object)、字符串变量(String) 等,而相关的类的方法,也是程序员经常用到的(在这里要区分一下类的注意和属性发方法),例如数组的push方法、日期的get系列方法、字符串的split方法等等,但是在实际的编程过程中不知道有没有感觉到现有方法的不足?prototype 方法应运而生!

【最简单的例子,自己写add等方法,了解 prototype】
是不是很简单?这一节仅仅是告诉读者又这么一种方法,这种方法是这样运用的。

(1) Number.add(num):作用,数字相加
实现方法:Number.prototype.add = function(num){return(this+num);}
试验:alert((3).add(15)) -> 显示 18(2) Boolean.rev(): 作用,布尔变量取反
实现方法:Boolean.prototype.rev = function(){return(!this);}
试验:alert((true).rev()) -> 显示 false(3)测试demo
String.prototype.test = function(value) {alert(1)
};

【已有方法的实现和增强,初识 prototype】

(1) Array.push(new_element)
//作用:在数组末尾加入一个新的元素
Array.prototype.push = function(new_element){this[this.length]=new_element;return this.length;
}
//让我们进一步来增强他,让他可以一次增加多个元素!
Array.prototype.pushPro = function() {var currentLength = this.length;for (var i = 0; i < arguments.length; i++) {this[currentLength + i] = arguments[i];}return this.length;
}2)String.length
//作用:这实际上是 String 类的一个属性,但是由于 JavaScript 将全角、半角均视为是一个字符,
//在一些实际运用中可能会造成一定的问题,现在我们通过 prototype 来弥补这部不足。
String.prototype.cnLength = function(){var arr=this.match(/[^\x00-\xff]/ig);return this.length+(arr==null?0:arr.length);
}
alert("EaseWe空间Spaces".cnLength()) -> 显示 16

【新功能的实现,深入 prototype】
在实际编程中所用到的肯定不只是已有方法的增强,更多的实行的功能的要求。

(1) String.left()
//问题:用过 vb 的应该都知道left函数,从字符串左边取 n 个字符,但是不足是将全角、半角均视为是一个字符,造成在中英文混排的版面中不能截取等长的字符串
//作用:从字符串左边截取 n 个字符,并支持全角半角字符的区分
String.prototype.left = function(num,mode){if(!/\d+/.test(num))return(this);var str = this.substr(0,num);if(!mode) return str;var n = str.Tlength() - str.length;num = num - parseInt(n/2);return this.substr(0,num);
}
alert("EaseWe空间Spaces".left(8)) -> 显示 EaseWe空间
alert("EaseWe空间Spaces".left(8,true)) -> 显示 EaseWe空
//本方法用到了上面所提到的String.Tlength()方法,自定义方法之间也能组合出一些不错的新方法呀!(2) Date.DayDiff()
作用:计算出两个日期型变量的间隔时间(年、月、日、周)
Date.prototype.DayDiff = function(cDate,mode){try{cDate.getYear();}catch(e){return(0);}var base =60*60*24*1000;var result = Math.abs(this - cDate);switch(mode){case "y":result/=base*365;break;case "m":result/=base*365/12;break;case "w":result/=base*7;break;default:result/=base;break;}return(Math.floor(result));}
alert((new Date()).DayDiff((new Date(2002,0,1)))) -> 显示 329
alert((new Date()).DayDiff((new Date(2002,0,1)),"m")) -> 显示 10
//当然,也可以进一步扩充,得出响应的小时、分钟,甚至是秒。(3) Number.fact()
//作用:某一数字的阶乘
Number.prototype.fact=function(){var num = Math.floor(this);if(num<0)return NaN;if(num==0 || num==1)return 1;elsereturn (num*(num-1).fact());
}
alert((4).fact()) -> 显示 24
//这个方法主要是说明了递归的方法在 prototype 方法中也是可行的!(4) Array.indexof()
//下面是给js中的Array加的一个方法(本来js中Array是没有返回下标的方法的)
Array.prototype.indexof = function(value) {var a = this;for (var i = 0; i < a.length; i++) {if (a[i] == value)return i;}
}
var arr = ['1', '2', '3', '4', '5', '6', '7'];
alert(arr.indexof('3'));

prototype 基础测试 Demo

本章节,是博主早期针对 prototype 做的一些测试代码,可以跳过。

===== 第一例,prototype初使用--为类型增加额外的方法和属性  
Object.prototype.Property = 1;
Object.prototype.Method = function (){ alert(1);
}
var obj = new Object();
alert(obj.Property);
obj.Method();
结论:可以在类型上使用proptotype来为类型添加行为,这些行为只能在类型的实例上体现,并且在增加之前实例化的对象也享有这些变化。
规则1:JS中允许的内置类型有Array, Boolean, Date, Enumerator, Error, Function, Number, Object, RegExp, String;
规则2:直接用Object.Method()也可以调用(但一般不这么使用),因为Object是所有对象(包括函数对象)的基础,其他内置类型是不可以。===== 第二例,在实例对象上不能使用prototype,否则发生编译错误 
var obj = new Object();
obj.prototype.Property = 1; //Error
obj.prototype.Method = function() //Error
{alert(1);
}===== 第三例,直接给类型定义"静态"属性和方法,只能使用类型本身调用,对象无法调用,同Java的static关键字声明的类变量
Object.Property = 1;
Object.Method = function()
{alert(1);
}
alert(Object.Property);
Object.Method();    //正常调用
var obj = new Object();
alert(obj.Property);  //Error实例不能调用类型的静态属性或方法,否则发生对象未定义的错误。===== 第四例,演示通常在JavaScript中定义一个自定义类型的方法
function Aclass()
{
this.Property = 1;
this.Method = function()
{alert(1);
}
}
var obj = new Aclass();
alert(obj.Property);
obj.Method();===== 第五例,接第四例,可以在外部使用prototype为自定义的类型添加属性和方法。
Aclass.prototype.Property2 = 2;
Aclass.prototype.Method2 = function
{alert(2);
}
var obj = new Aclass();
alert(obj.Property2);
obj.Method2();===== 第六例,接第四例,在外部不能通过prototype改变自定义类型的属性或方法,不会报错但改变无效;
但如果属性本身就是通过prototype扩展的,则可以继续用prototype修改。
Aclass.prototype.Property = 2;
Aclass.prototype.Method = function
{alert(2);
}
var obj = new Aclass();
alert(obj.Property); //仍然弹出1
obj.Method();===== 第七例,接第四例,可以在对象上改变属性。(这个是肯定的)
var obj = new Aclass();
obj.Property = 2;
obj.Method = function()
{alert(2);
}
alert(obj.Property);
obj.Method();
也可以在对象上改变方法。(和普遍的面向对象的概念不同)===== 第八例,接第四例,可以在对象上增加属性或方法   
var obj = new Aclass();
obj.Property2 = 2;
obj.Method2 = function()
{alert(2);
}
alert(obj.Property2);
obj.Method2();===== 第九例,接第四例,这个例子说明了一个类型如何从另一个类型继承。  
function AClass2()
{this.Property2 = 2;this.Method2 = function(){alert(2);}
}
AClass2.prototype = new AClass();var obj = new AClass2();
alert(obj.Property);
obj.Method();
alert(obj.Property2);
obj.Method2();===== 第十例,接上例, 这个例子说明了子类如何重写父类的属性或方法。但不能改变自身的属性和方法。
AClass2.prototype = new AClass();()
AClass2.prototype.Property = 3;
AClass2.prototype.Method = function()
{alert(4);
}
var obj = new AClass2();
alert(obj.Property);
obj.Method();
可见JavaScript能够实现的面向对象的特征有:·公有属性(public field)·公有方法(public Method)·私有属性(private field)·私有方法(private field)·方法重载(method overload)·构造函数(constructor)·事件(event)·单一继承(single inherit)·子类重写父类的属性或方法(override)·静态属性或方法(static member)

总结陈词

本篇文章分享一下 JS 世界中prototype的用法,希望能帮助到大家。
后端程序猿如果想往全栈工程狮发展,那JavaScript必须和Java玩得一样明白,接下来系列文章,带你一起探索,无所不能的JavaScript
💗 后续会逐步分享企业实际开发中的实战经验,有需要交流的可以联系博主。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/43455.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OpenWrt入门 (1) - 登录及ssh命令接入wifi

本文参考自: [OpenWrt 维基]在 OpenWrt 上启用 Wi-Fi 接入点 --- [OpenWrt Wiki] Enabling a Wi-Fi access point on OpenWrt 需要详细了解的小伙伴请看原文 基本概念 OpenWrt是适用于嵌入式设备的一个Linux发行版。 相对原厂固件而言&#xff0c;OpenWrt不是一个单一、静态…

企业如何从无序管理走向精益生产管理?

先来看看企业生产管理无序的弊端有哪些&#xff1f; 数据统计不及时&#xff1a;纸质生产工单&#xff0c;数据难统计&#xff0c;各业务环节问题难定位&#xff0c;影响车间生产效率。生产过程不透明&#xff1a;生产过程数据难监控&#xff0c;生产派工管理混乱&#xff0c;…

【前端】面试八股文——meta标签

【前端】面试八股文——meta标签 在HTML文档中&#xff0c;meta标签是一个关键但常被忽视的元素。它位于文档的<head>部分&#xff0c;用于提供关于HTML文档的元数据&#xff08;metadata&#xff09;。这些元数据不会直接显示在页面上&#xff0c;但对搜索引擎优化&…

web前端开发——标签一

今天我来针对web前端开发讲解标签一 Html标签_标题&段落&换行 注释标签&#xff1a;Ctrl/ Ctrl/ &#xff0c;用户可能会获取到注释标签 注释的原则: •和代码逻辑一致 •尽量使用中文 •正能量 标题标签&#xff1a;<h1></h1> h1-h6 标题标签有6…

51单片机-第二节-数码管

一、数码管介绍&#xff1a; 1.什么是数码管&#xff1f; 多个LED组合成8字显示器。 2.一位数码管的引脚&#xff08;只有一个8&#xff09;&#xff1a; 数码管的引脚为1-10&#xff0c;其中公共极为3,8&#xff0c;其余八位分别对应一个二极管&#xff0c;如下图&#xff…

【大模型】大模型相关技术研究—微调

为什么要对大模型进行微调 1.成本效益&#xff1a; o 大模型的参数量非常大&#xff0c;训练成本非常高&#xff0c;每家公司都去从头训练一个自己的大模型&#xff0c;这个事情的性价比非常低。 2.Prompt Engineering 的局限性&#xff1a; o Prompt Engineering 是一种相…

视图库对接系列(GA-T 1400)十二、视图库对接系列(本级)人员数据推送

背景 人体和非机动车和机动车类似的,只是请求的参数不一样而已。人员数据推送 接入人员数据推送相对比较简单,我们只需要实现对应的接口就ok了。 具体如图: 有增删改查接口,目前的话 因为我们是做平台,我们只需要实现添加接口就可以了。 接口实现 service 层 /**** …

软件工程面向对象 超市管理系统 需求分析 系统设计 课程设计报告

1、引言 系统简述 超市管理系统的功能主要有前台管理和后台管理两个大块。其使用对象 有超市管理人员和超市销售人员两类。超市管理系统主要为了实现商品输 入、 输出管理数据的自动化&#xff0c; 提高商品统计信息的实时性&#xff0c; 减轻人工劳动强 度从而节省人力成本。实…

Go语言---异常处理error、panic、recover

异常处理 Go 语言引入了一个关于错误处理的标准模式,即 error 接口,它是 Go 语言内建的接口类型,该接口的定义如下: package errorsfunc New(text string) error {return &errorString{text} }// errorString is a trivial implementation of error. type errorString st…

springboot事故车辆与违章车辆跟踪系统-计算机毕业设计源码03863

springboot事故车辆与违章车辆跟踪系统 摘 要 科技进步的飞速发展引起人们日常生活的巨大变化&#xff0c;电子信息技术的飞速发展使得电子信息技术的各个领域的应用水平得到普及和应用。信息时代的到来已成为不可阻挡的时尚潮流&#xff0c;人类发展的历史正进入一个新时代。…

W外链怎么样,他们家的短网址免费的吗?

W外链作为短网址服务的一种&#xff0c;体现了短网址技术的现代发展趋势&#xff0c;它不仅提供了基础的网址缩短功能&#xff0c;还扩展了一系列高级特性和增值服务&#xff0c;以适应更广泛的市场需求。根据相关参考内容&#xff0c;W外链具有以下特点和优势&#xff1a; 短域…

2024程序员行业风口和面试宝典

国际研究机构Gartner会在每年10月份左右发布下一年度的战略发展趋势预测&#xff0c;并在次年3月左右发布和网络安全相关的趋势预测。绿盟科技通过将近3年的趋势预测进行分组对比分析后发现&#xff0c;除了众人皆知的AI技术应用外&#xff0c;数据模块化、身份优先安全、行业云…

01-图像基础-颜色空间

1.RGB颜色空间 RGB是一种常用的颜色空间&#xff0c;比如一幅720P的图像&#xff0c;所对应的像素点个数是1280*720&#xff0c;每一个像素点由三个分量构成&#xff0c;分别是R,G,B。 R代表红色分量&#xff0c;G代表绿色分量&#xff0c;B代表蓝色分量&#xff0c;以24位色来…

加密与安全_密钥体系的三个核心目标之不可否认性解决方案

文章目录 Pre概述不可否认性数字签名&#xff08;Digital Signature&#xff09;证书是什么证书使用流程 PKICA证书层级多级证书证书链是如何完成认证的&#xff1f; 其他疑问1. Alice能直接获取Bob的公钥&#xff0c;是否还需要证书&#xff1f;2. 为什么即使能直接获取公钥也…

理解机器学习中的潜在空间(Understanding Latent Space in Machine Learning)

1、什么是潜在空间&#xff1f; If I have to describe latent space in one sentence, it simply means a representation of compressed data. 如果我必须用一句话来描述潜在空间&#xff0c;它只是意味着压缩数据的表示。 想象一个像上面所示的手写数字&#xff08;0-9&…

vue学习day01-vue的概念、创建Vue实例、插值表达式、响应式、安装Vue开发者工具

1、vue的概念 Vue是一个用于构建用户界面的渐进式 框架 &#xff08;1&#xff09;构建用户界面&#xff1a;基于数据动态渲染页面 &#xff08;2&#xff09;渐进式&#xff1a;循序渐进的学习 &#xff08;3&#xff09;框架&#xff1a;一条完整的项目解决方案&#xff…

GenAl如何改变 DevOps 中的软件测试?

TestComplete 是一款自动化UI测试工具&#xff0c;这款工具目前在全球范围内被广泛应用于进行桌面、移动和Web应用的自动化测试。 TestComplete 集成了一种精心设计的自动化引擎&#xff0c;可以自动记录和回放用户的操作&#xff0c;方便用户进行UI&#xff08;用户界面&…

RTK_ROS_导航(2):卫星图查看

目录 1. 基于MapViz的卫星图查看 1. 基于MapViz的卫星图查看 安装 # 源码安装 mkdir -p RTK_VISION/src cd RTK_VISION/src git clone https://github.com/swri-robotics/mapviz.git --branchmelodic-eol sudo apt-get install ros-$ROS_DISTRO-mapviz ros-$ROS_DISTRO-mapviz-…

IP-GUARD如何禁止电脑自带摄像头

IP-GUARD可以通过设备管理模块禁止USB接口&#xff0c;所以USB外置摄像头很容易就可以禁止了。 但是笔记本自带摄像头无法禁止&#xff0c;配置客户端策略如下&#xff1a; device_control_unknown_mode1 device_control_unphysical_mode3

记一次 Qt installer framework安装程序过程中 安装驱动依赖

在installscript.qs 文件中该函数添加exe 依赖程序放置位置