【趣味JavaScript】5年前端开发都没有搞懂toString和valueOf这两个方法!

news2024/11/23 19:48:09

🚀 个人主页 极客小俊
✍🏻 作者简介:web开发者、设计师、技术分享博主
🐋 希望大家多多支持一下, 我们一起进步!😄
🏅 如果文章对你有帮助的话,欢迎评论 💬点赞👍🏻 收藏 📂加关注

摘要
我觉得你大概率还是没搞明白toString和valueOf这两个方法到底有什么用! 很多人都没有说清楚! 我看不见得吧!

前言

很多人见过toStringvalueOf这两个方法,但就是不清楚这两个方法用来干嘛的,如何运行的,今天就给大家详细介绍一下,但是在说之前,我们必须要对数据类型转换、面向对象、原型和原型链等知识点先需要回顾复习一下, 这样有助于更好的理解这两个方法!

数据类型转换

首先稍稍有点JS基础的朋友肯定是知道,在JS中数据类型转换是分为强制转换隐式转换 两种方式!

强制类型转换 也称为显性类型转换,意思就是你能看到的一种数据类型转换的情况

隐式类型转换 也称为自动类型转换,意思就是你可能无法感知的情况下数据类型就被转换了

强制数据类型转换

先来看看什么是强制类型转换

我们需要将值显式地转换为我们期望的数据类型!

这里我可以调用数据类型当中的toString()方法来完成对其他数据类型转换为String类型的操作

也就说对要被转换的数据类型调用toString()方法即可!

举个栗子

//定义一个数值类型的变量
var num=100;
//转换前
console.log('转换[前]为:'+typeof num+'类型');
//开始转换
num=num.toString();
//转换后
console.log('转换[后]为:'+typeof num+'类型');

如图

这个案例很简单,快速的把一个数值类型强制转换为字符串类型 这没什么说的!

隐式数据类型转换

隐式数据类型转换又称为: 自动类型转换就是不需要人为强制进行数据的转换,而是JS会自动的将某种类型转换为需要的类型,所以该转换操作用户是感觉不到的,因此又称为 隐式类型转换

但其实内部还是和强制类型转换一样,也是通过隐性的调用String()、Number()、Boolean()函数来进行转换 ,不同的则是这种操作是由JS自己自动完成的!

所以从转换规则上说 隐式数据类型转换强制数据类型转换是一样的!

举个梨子

很多人不知道,其实alert方法会自动将任何要进行弹出打印的数据,都转换为字符串以进行显示, 很多人并不知道这一特点!

怎么你还不信?那么我们来测试测试看看!

举个栗子

你用alert打印数值、布尔值、还是字符串可能看不怎么出来,我们来打印一个函数试试看就知道了!

function test(){
    return 1+1;
}

alert(test);

你看看打印结果是什么就明白了!

这里居然把函数体打印出来了,并且是以字符串的形式, 并且就测试以下代码看看,效果是不是一样的

function test(){
    return 1+1;
}

console.log(test.toString());  //强制转换为字符串
console.log(String(test));     //强制转换为字符串
console.log(test+"");		   //快捷隐式转换为字符串

如图

看到了吧,这很好的证明了隐式类型转换,其实和强制类型转换的规则上其实是差不多的!

并且JS在算术运算表达式中,也会自动将运算数据进行number类型转换

举个简单的栗子:

alert("6"/ "2"); 输出结果为3

这里就是左右两边String类型的数据被自动转换number类型,然后再进行算术运算得出结果!

JS面向对象

关于面向对象这一块我以前也有说过,这里也简单提一嘴,

对于JS面向对象而言,你可以把任何一样东西都看成对象,然后找出对象属性方法,通过这种对象方式的模块化来管理整个对象当中的数据,这就是面向对象编程 这个道理如果你学过C++、Java、PHP等语言其实大致上都是触类旁通的!

所以面向对象也是一种模块化编程的一种方式,而在我们给别人使用这个对象的时候,只需要让别人实例化这个对象,然后就可以访问对象中的属性和对象中的方法了

我们在平常的项目开发中使用最频繁的也是自定义的对象!

例如

var obj={
    _getUser:function (){
        console.log('获取用户信息逻辑');
    },
    _ViewOrder:function () {
        console.log('查看订单');
    }
}
console.log(obj);

初探toString与valueOf方法

上面说了那么多,又跟toString与valueOf这两个方法有什么关系呢?

我们来看个梨子:

var obj={"user":"张三"};

console.log(String(obj));
console.log(obj+"");

以上会返回一个为[object Object]的结果!

如图

尤其刚刚接触js的朋友这时候一定会想,咦…这是个什么玩意东西呢?? 嘿嘿嘿

toString()方法

首先上面的代码中,我进行了把一个对象强制和隐式转换为字符串的行为,对吧!

可是呢,从JS设计的角度是不允许这样给对象进行处理的!

在此类运算的情况下,对象会被自动转换为原始值,然后对这些原始值进行运算,并得到运算结果(也是一个原始值)

于是呢对象字符串的转换,当我们对期望一个字符串的对象执行操作时,这时候就非常关键啦,嘿嘿

js将尝试寻找toStringvalueOf 方法,你也先别管这两个方法从哪里来的,我们先来看一下它的运行原理!

分析

  1. 当一个对象被转换到字符串时候,首先隐式调用了toString()方法,如果尝试能够返回出基本数据类型也就是(字符串、数值、布尔值)等等,则可以调用String()函数继续转换该值,最终返回出字符串
  2. 如果toString()方法 返回出来的不是基本数据类型, 也就是说如果它返回出来的依然是一个对象,那么则再继续调用valueOf()方法 如果返回出来的是基本数据类型的值,然后则可以继续用String()函数转换该值

怎么样,是不是听着有些神叨叨、鬼道道、神批唠叨的感觉还没明白? 没关系 我们看下面的案例来理解!

其实呀很简单,你先记住, 对于字符串转换,会默认调用toString方法

并且默认情况下toString 方法会返回一个字符串[object Object]

刚刚上面我们不是看到了对象转字符串会返回出一个[object Object]的东西嘛,其实我们自己也能去定义它

例如

var obj={
    "user":"张三",
    "toString":function () {
        console.log('1.执行了toString()方法');
        return '[object Object]';
    }
}


console.log(String(obj));  //强制把对象转换为字符串
console.log(""+obj);	   //隐式把对象转换为字符串

如图

这就很明显确定了一件重要的事情,我们在给对象做字符串转换的时候,会默认调用这个toString方法

只是说这里我们重写了它一下, 并且如果尝试能够返回出基本数据类型也就是(字符串、数值、布尔值)等等,则可以继续调用String()函数继续转换该值,最终返回出我们想要的结果对吧!

那么看下面的代码: 我就给它返回一个其他的基本数据类型看看,

var obj={
    "user":"张三",
    "toString":function () {
        console.log('1.执行了toString()方法');
        return 100;  //从toString()方法中返回一个基本数据类型出去!
    }
}
console.log(String(obj));
console.log(""+obj);

如图

这里对象被进行转换了两次,一次显示,一次隐式,但不管是显示还是隐式的转换,其实都一样

所以说,作为toString()方法就是在进行对象被进行字符串转换的时候,被自动调用,然后返回一个基本数据类型出来! 并且toString()方法必须要返回基本数据类型,才能够被String()函数继续进行字符串的转换, 至于要返回什么基本数据出来,这里由我们自己决定!

valueOf()方法

valueOf其实默认情况下返回的就是对象自身

那么问题来了,如果说toString()方法 返回出来的不是基本数据类型, 也就是说如果它返回出来的是一个对象, 会怎么样呢?

现在我告诉你,则会继续调用valueOf()方法 如果返回基本数据类型的值,

按照我们上面代码的意思,则又可以继续用String()函数转换该值!

所以此时此刻,你可以把这个valueOf()方法加上去看看了!

代码如下

var obj={
    "user":"张三",
    "toString":function () {
        console.log('1.执行了toString()方法');
        return {};
    },

    "valueOf":function (){
        console.log('2.执行了valueOf()方法');
        return '执行结束';
    }
}

console.log(String(obj));

代码分析

此时,我为了让valueOf方法执行,在toString方法中故意返回一个对象, 那么valueOf方法自然会自动执行,最后返回出一个基本数据类型(标量类型)出来!

并且在这里我们也很好的知道了toString和valueOf两个方法执行的先后顺序!

总之你先记住: 对于字符串转换,优先调用 toString方法、然后再调用valueOf方法

如图

toString与valueOf方法的顺序问题

对于字符串转换,顺序很简单,也就是先执行toString再执行valueOf 这个上面已经说过了!

但是如果只是对于数学运算,那么则优先调用 valueOf 方法, 除非这个方法它不存在的情况下, 或者说是valueOf方法返回的也是一个对象类型,则调用toString方法

例如

var obj={
    "user":"张三",
    "toString":function () {
       console.log('1.执行了toString()方法');
        return {};
    },

    "valueOf":function (){
        console.log('2.执行了valueOf()方法');
        return " OK啦";
    }
}

console.log(String(obj));
console.log("------------------------------------------");
console.log(100+obj);

结果如图

在对象进行算术运算的,时候valueOf方法会先执行,如果返回的是一个对象,那么再执行toString方法,让它去返回一个可正常被运算的基本数据类型!

var obj={
    "user":"张三",
    "toString":function () {
       console.log('1.执行了toString()方法');
        return 500;
    },

    "valueOf":function (){
        console.log('2.执行了valueOf()方法');
        return {};
    }
}
console.log(100+obj);

结果如图

注意:如果toString方法和vlaueOf方法都返回对象类型,那么就可能会报错了

也就是说,如果都不能返回一个基本数据类型的值,

那么浏览器可能会抛出一个错误信息Uncaught TypeError: Cannot convert object to primitive value 意思是: 未捕获的TypeError:无法将对象转换为字符串值

所以说很多新手朋友刚刚遇到的就是这个对象字符串时候出现的这些问题,不知道如何解决!

小结

对象字符串中的:toString()与valueOf() 这两个方法 调用的顺序是先调用toString,不满足需求才会调用valueOf(),这里的需求是指toString方法必须返回基本的数据类型,也就是字符、数值、布尔值、undefined、null这些数据类型,也只有返回出这些数据类型之后String()函数才能正常执行字符串的转换

如果返回一个对象,就会判定使用valueOf()方法来继续处理,而valueOf()方法返回的值也必须是那些基本数据类型,如果还是返回出一个对象数据类型,则最终会判定无法进行转换!

总之: toString()方法已经返回了一个基本数据类型,就不会再调用valueOf()方法了,除非当toString()方法返回一个对象的时候,才会再次调用valueOf()方法 或者是对象进行了算术运算、对象转数值之类的操作,才会优先调用valueOf方法!

这里还说一点,这不光是对象转字符串,会启动这两个方法对象转数值,也会 大家可以自己去试试看执行顺序

以上我觉得就是对toString与valueOf方法最基本的认知, 下面我来详细说一下,这两个方法存在于什么地方!

toString与valueOf来自于哪里?

有些人肯定会问,这两个方法来自于哪里呢?别着急,我们先来复习复习什么是原型对象

原型对象prototype

还记得我以前讲过的原型对象吗? 不记得也没关系,我们来看回忆回忆!

当我们创建一个构造函数 或者 是一个普通函数的时候, 浏览器中的JS解析器都会向函数中添加一个属性名为prototype, 它就指向构造函数原型对象

例如

function 函数名() {
   //this.prototype={}  相当于这样子
}

你也可以理解为在 JS构造函数或者普通函数都有一个特殊的隐藏属性 prototype,

这个prototype属性对应着一个对象, 而这个对象就是我们所谓的原型对象,并且这个原型对象是对应于相应的构造函数所创建的!

如图

从上图中可以看出,每一个构造函数/普通函数其实都对应着自己的一个原型对象

并且可以使用构造函数.prototype来进行访问, 现在想起来了吧!

原型链中的toString与valueOf

接下来我们再来说说原型链,因为这里就是寻找toString与valueOf方法的关键了!

原型链还记得吧! 以前我也说过,如果有不明白的,一定要翻看前面的文章哦! 嘿嘿嘿…

图片官网地址: http://www.mollypages.org/tutorials/js.mp

如图

这么大一张图,估计肯定吧你看得脑壳疼、精神萎靡不振、感觉身体被掏空的样子了吧,嘿嘿嘿!

关于原型链之前的文章中我说的很清楚,还没有明白的朋友赶紧去看看!

这里我主要说一下toString和valueOf这两个方法存在于哪里!

注意到图中的Object.prototype了吗?这两个方法就存在于Object原型对象当中

你不信?让我们使用Chrome浏览器调试工具来看看吧, 你完全可以使用以下代码进行查看!

console.log(Object.prototype);

如图

所以toString()与valueOf() 这两个方法 默认情况下存在于Object()原型对象当中!

那么现在我们回过头 又来看看最开始我们在做数据类型转换时,强制转换调用toString()方法

代码

function test(a,b){
    console.log("Hello world");
    return true;
}

console.log(test.toString());

这里结合原型链就很好的说明了一点,Function对象Object原型对象当中继承来的toString方法,所以可以这样子调用,绕了一圈,现在明白了吧!

结果

那么结果就是你所到的, 一个函数对象的 toString 方法会返回一个表示函数源代码的字符串, 其中包括 function关键字,形参列表,大括号,以及函数体中的内容,都是以字符串直接返回

并且普通实例对象也因为原型链的关系,继承了这两个方法,所以也可以进行调用!

toString与valueOf方法的使用总结

说这么多,这两个方法到底有什么用呢?

其实这两个方法,我个人理解就是用来限制你在javascript中操作对象或者函数的规则

举个栗子

当你把两个对象相加 obj1 + obj2,或者相减 obj1 - obj2,或者使用打印弹框 alert(obj) 打印时会发生什么?

这种操作到底合理吗? 其实从JavaScript语言设计的角度上来说, 这样是不允许运算符函数或者对象进行这样的处理方式, 与其他的语言不同,JavaScript本身是无法实现让对象进行加法或其他运算的!

因为你觉得在JS中这样有意义吗?

例如

var user = {"username": "John"};

function test(){

}

alert(user+test);
console.log(user+test);

效果如下

所以说在此类运算的情况下,对象会被自动转换为基本数据类型,然后对这些基本数据类型进行运算,并得到运算结果,必须是一个基本数据类型, 所以说toString与valueOf方法就是用来干这事情的!

毕竟这是一个js内部重要的限制因为如果遇见类似于对象的运算结果不能是另一个对象,在JS中是无法实现这种操作的!

因此从技术上无法实现此类运算,所以在实际项目中不存在让js对象进行一些数学运算, 如果真发现有,通常是写错了!

从本质上讲toString与valueOf方法就是在以下几种这种场景才使用:

  1. 当我们把对象进行数学运算的时候,帮我们返回出应该能让JS计算的基本数据类型
  2. 当我们把对象转换成字符串的时候,帮我们返回出应该能让JS计算的基本数据类型

之前我说提到的隐式数据类型转换本质就是调用了valueOf或者toString方法, 又因为原型链的缘故那么在JS中,几乎每一种类型的对象都有一个toString和valueOf这两个方法!

我们可以通过重写来测试则两个方法,在构造函数原型中重写也可以,在实例对象中直接重写也是可以的!

如果真的遇见两个js对象要进行算术运算,那么代码如下:

var user1 = {
    "username": "张三",
    "age":30,
    toString:function (){
        //alert(1);  测试执行顺序
        return this.age;
    },
    valueOf:function (){
        //alert(2);  测试执行顺序
        return user1;
    }
}
function Person(){
    this.username="李四";
    this.age=30;
}
Person.prototype.toString=function (){
    return this.age;
}
Person.prototype.valueOf=function (){
    return Person;
}
var user2= new Person();


console.log("结果为:"+(""+user1));
console.log("结果为:"+(1+user1));
console.log("结果为:"+(user1+user2));

效果

为什么结果是这样呢?我们一个一个的来解释一下:

console.log("结果为:"+(""+user1));

分析

首先我们确定这是一个让对象做数学运算表达式对吧, 是一个空字符串加上一个user1实例对象 那么此时此刻,根据我们之前说的toString和valueOf执行顺序,就会自动的先执行valueOf方法,但是它又返回的是对象,那就继续执行toString方法 最后toString方法返回出来的是一个基本数据类型,也就所谓的原始值 这样就可以进行外面的运算了, 相当于返回出的表达式就为"" + 30 最后得到的结果就是一个字符串30

console.log("结果为:"+(1+user1));

这里最后返回的结果为31 大致流程就跟上面的差不多,只是最后返回出来的结果30还加上了1而已, 最后结果就为数值类型31

console.log("结果为:"+(user1+user2));

这里我们大致可以判断出来是两个对象在执行加法运算,那么必然就会自动执行 两个对象中的valueOf方法,而这里我让valueOf返回的是一个对象,就会分别让让toString方法自动执行,所以返回出来的都是基本数据类型的年龄属性值,最后相加而已,结果为数值60 大致流程就是这样!

小结

所以如果真要让对象进行这种运算,那么首先要执行的流程就是如下:

  1. 对象被转换为原始值,也就是基本数据类型
  2. 然后再进行进一步计算,把返回的基本数据类型被进一步进行数据类型转换之后,执行正常的计算!

还有就是要注意一下valueOf和toString的执行顺序

这里因为数算术运算需要得到一个原始值,那么尝试调用valueOf()再调用toString()无论哪个存在,如果没有重写,则会调用Object中默认的valueOf或toString方法!

那么如果你真的明白了,那你猜猜下面这样做会输出什么?这就留给大家了, 很简单!

代码如下

let test= ()=>{}

test.valueOf = () => {
    return 100
}

test.toString = () => {
    return '不准你继续这样干下去!'
}

console.log(+test);
console.log(test*2);
console.log(test==100);
console.log(test=="100");
console.log(test==="100");

最后

看完之后你应该对valueOf和toString有一个基本的认识了吧!

我们在ES6valueOf和toString也可以使用Symbol.toPrimitive来代替,以后会详细给大家介绍!

给大家一点简单的练习题 考考你们!!

说出以下代码输出什么结果:

面试题1

var obj = {
    i: 1,
    valueOf: function () {
        return this.i+100;
    },
    toString: function () {
        return this.i;
    }
}

var Person = {
    i: +obj,
    valueOf: function () {
        return this.i+200;
    },
    toString: function () {
        return this.i;
    }
}


alert(Person);

面试题2

let a = {};
let b = {};
a.toString = function() {
    return 1;
};
b.valueOf = function() {
    return "1";
};
let sum = a + b;
console.log(sum);

"👍点赞" "✍️评论" "收藏❤️"

大家的支持就是我坚持下去的动力!

如果以上内容有任何错误或者不准确的地方,🤗🤗🤗欢迎在下面 👇👇👇 留个言指出、或者你有更好的想法,
欢迎一起交流学习❤️❤️💛💛💚💚

更多 好玩 好用 好看的干货教程可以 点击下方关注❤️ 微信公众号❤️
说不定有意料之外的收获哦..🤗嘿嘿嘿、嘻嘻嘻🤗!
🌽🍓🍎🍍🍉🍇

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

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

相关文章

在C或C++中查找内存泄漏

编程软件中的内存泄漏可能很难精确定位,因为这里面有大量的数据。本文中,您可以学习如何借助运行时错误检测工具查找C和C应用程序中的内存泄漏。 什么是内存泄漏?C和C语言实例 What Is a Memory Leak? 当您面临内存泄漏时,C和C…

师德师风演讲稿写作格式:如何用三句话吸引听众的注意力

写师德师风演讲稿时,可以按照以下格式进行写作: 1. 开头部分: a. 引起听众的兴趣,可以使用一个引人入胜的故事、一个有趣的事实或者一个引人思考的问题。 b. 简要介绍自己以及演讲的主题。 2. 主体部分: a. 阐述师…

多维时序 | MATLAB实现GWO-BP多变量时间序列预测(灰狼算法优化BP神经网络)

多维时序 | MATLAB实现GWO-BP多变量时间序列预测(灰狼算法优化BP神经网络) 目录 多维时序 | MATLAB实现GWO-BP多变量时间序列预测(灰狼算法优化BP神经网络)效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.MATLAB实现GWO-BP多变量时间序列预测(灰狼算法优化BP神经网络)&…

华为云云耀云服务器L实例评测 | 云服务器搭建自己的gitlab代码仓库手把手教学

📋 前言 🖱 博客主页:在下马农的碎碎念🤗 欢迎关注🔎点赞👍收藏⭐️留言📝✍ 本文由在下马农原创,首发于CSDN📆 首发时间:2023/09/26📅 最近更新时…

crypto:Quoted-printable

题目 解压文件后可得到提示文本 好了这个没接触过,参考别的大佬wp QP为可打印字符编码,根据加密方式任何一个8位的字节值可编码为3个字符:一个等号“”后跟随两个十六进制数字(0–9或A–F)表示该字节的数值。 利用网…

完全背包 动态规划 + 一维dp数组

动态规划:完全背包理论基础 每件商品都有无限个!!! (1)0-1背包的核心代码 解决0-1背包问题(方案二):一维dp数组(滚动数组)_呵呵哒( ̄…

CodeWhisperer,非常丝滑的AI代码神器

文章目录 什么是 Amazon CodeWhisperer?快速上手CodeWhisperer安装配置如何使用 Amazon CodeWhispererCodeWhisperer初体验:hello world Python语言快速入门向文件写入数据读取csv文件排序算法之冒泡排序设计模式之单例模式 使用CodeWhisperer快速上手Py…

这本书竟然把JAVA讲的如此透彻!漫画JAVA火爆出圈!

亲爱的粉丝们,你是否曾经为学习JAVA而苦恼?繁复的代码和复杂的逻辑常常让人感到头大。不过,今天我要为大家介绍一本神奇的书——《漫画JAVA》,它以图文并茂的方式,轻松诙谐地讲解了JAVA的方方面面。在这篇文章中&#…

基于.Net Core实现自定义皮肤WidForm窗口

前言 今天一起来实现基于.Net Core、Windows Form实现自定义窗口皮肤,并实现窗口移动功能。 素材 准备素材:边框、标题栏、关闭按钮图标。 窗体设计 1、创建Window窗体项目 2、窗体设计 拖拉4个Panel控件,分别用于:标题栏、关…

LabVIEW开发实时自动化多物镜云计算全玻片成像装置

LabVIEW开发实时自动化多物镜云计算全玻片成像装置 数字病理学领域正在迅速发展,这主要是由于计算机处理能力、数据传输速度、软件创新和云存储解决方案方面的技术进步。因此,病理科室不仅将数字成像用于图像存档等简单任务,还用于远程病理学…

无菌生产使用的纯蒸汽质量检测必要性及验证服务

纯蒸汽常被用于制药行业的无菌生产中。无菌生产所用到的物料、容器、设备等物品需要使用纯蒸汽进行湿热灭菌处理。纯蒸汽的主要检测指标,如微生物限度、电导率、TOC等应满足《中华人民共和国药典》中注射用水的质量指标规定。 当纯蒸汽用于湿热灭菌时,为…

【MySQL】开启 canal同步MySQL增量数据到ES

开启 canal同步MySQL增量数据到ES canal 是阿里知名的开源项目,主要用途是基于 MySQL 数据库增量日志解析,提供增量数据订阅和消费。示使用 canal 将 MySQL 增量数据同步到ES。 一、集群模式 图中 server 对应一个 canal 运行实例 ,对应一…

C++刷题 全排列问题

C刷题 全排列问题 题目描述思路讲解代码展示 题目描述 思路讲解 代码展示 #include <iostream>using namespace std;const int maxn 11;//P为当前排列&#xff0c;hashTable记录整数x是否已经在P中 int n, P[maxn], hashTable[maxn] {false};//当前处理排列的第index号…

Mysql高级——数据库设计规范(2)

8. ER模型 ER 模型中有三个要素&#xff0c;分别是实体、属性和关系。 实体&#xff0c;可以看做是数据对象&#xff0c;往往对应于现实生活中的真实存在的个体。在 ER 模型中&#xff0c;用矩形来表示。实体分为两类&#xff0c;分别是强实体和弱实体。强实体是指不依赖于其…

ElementUI动态树,数据表格以及分页的实现

目录 前言 一. ElementUI动态树 二. 数据表格和分页 三. 后端代码 service层 controller层 前言 在上一篇博客中实现了左侧菜单栏&#xff0c;在此基础上将它变为动态的&#xff0c;即动态的展示数据库的数据。还有数据表格的实现以及分页。&#xff08;纯代码分享&#…

Opengl之基础光照

现实世界的光照是极其复杂的&#xff0c;而且会受到诸多因素的影响&#xff0c;这是我们有限的计算能力所无法模拟的。因此OpenGL的光照使用的是简化的模型&#xff0c;对现实的情况进行近似&#xff0c;这样处理起来会更容易一些&#xff0c;而且看起来也差不多一样。这些光照…

【DenseNet模型】

【DenseNet模型】 1 DenseNet结构2 DenseNet特征图保持一致方法3 模型预览方法 1 DenseNet结构 参考链接&#xff1a;https://arxiv.org/pdf/1608.06993.pdf DenseNet通过密集连接&#xff0c;可以缓解梯度消失问题&#xff0c;加强特征传播&#xff0c;鼓励特征复用&#xff0…

逻辑像素与物理像素引发学习型探索

文章目录 目的关于像素从像素到分辨率DP(设备像素&#xff09;- 物理像素DIP(逻辑像素&#xff09;- 设备独立像素CSS 像素屏幕特性 DRP&#xff08;设备像素比&#xff09;PPI(Pixels Per Inch ) - 像素密度屏幕像素密度PPI 目的 做一个前端或或者产品开发者&#xff0c; 在涉…

Simulink 封装

快捷键&#xff1a; Edit Mask&#xff1a;CtrlM Look Under Mask&#xff1a;CtrlU 封装之后的模型&#xff1a; Edit Mask界面&#xff1a; 双击模块后的提示界面&#xff1a; 封装的模块内部&#xff1a;

防火墙两台设备对接,隧道成功建立后,总部子网pc不能ping通分部子网,怎么排查解决?

环境: 总部 深信服防火墙 8.0.75 AF-2000-FH2130B-SC 分部 深信服防火墙 8.0.75 AF-2000-FH2130B-SC 问题描述: 防火墙两台设备对接,隧道成功建立后,总部子网pc不能ping通分部子网,怎么排查解决?分部子网可以ping通总部子网。 两台防火墙之前是做热备的,配置一样,…