壹 ❀ 引

原型与原型链属于老生常谈的问题,也是面试高频问题,但对于很多前端开发者来说,组织语言去解释清楚是较为困难的事情,并不是原型有多难,稍微了解的同学都知道原型这一块涉及太多知识。比如我们可以灵魂提问自己的同事以下问题:

  • 什么是原型和原型链,原型链顶端是什么?
  • 原型链和作用域链有何区别?
  • 构造函数与普通函数有什么区别?
  • 能否判断当前函数是普通调用或new构造调用?
  • prototype__proto_是什么?
  • 怎么判断对象是否包含某条属性?
  • 怎么判断某条属性是否为对象自身属性而非原型属性?
  • constructorinstanceOf有何区别?
  • 能不能手动实现new方法?
  • 能否创建严格意义上的空对象?
  • ....

我想问题没问完你应该要被锤了。我们言归正传,上述问题你能回答多少呢?带着问题,让我们重新梳理原型相关知识。

贰 ❀ 从构造函数说起

与java基于类不同,JavaScript是一门基于原型prototype的语言,至少在ES6之前JavaScript并无类的概念,但却有类的模拟实现,也就是我们常说的构造函数。

什么是构造函数呢?构造函数其实就是一个普通函数,只是我们为了区分普通函数,通常建议构造函数name首字母大写,比如:

// 这是一个构造函数
function Parent(){};

你说我就不首字母大写,那也不影响一个函数是构造函数的事实:

// 这也是一个构造函数
function parent(){
this.name = '听风';
};
let child = new parent();
console.log(child);//parent {name: "听风"}

有同学就纳闷了,这普通函数居然也能使用new操作符构造调用,没错,不仅普通函数能new调用,构造函数同样也能普通调用:

// 这是一个构造函数
function Parent() {
console.log(1);
};
Parent() //1

其实到这里,我们已经解释了 构造函数与普通函数有什么区别 这个问题,构造函数其实就是一个普通函数,且函数都支持new调用与普通调用。也正因如此导致了ES5中构造函数没有区别于普通函数的尴尬局面,这也是为何在ES6中JavaScript正式推出Class类的原因,你会发现Class只支持new调用,如果直接调用会报错:

class Parent {
sayName() {
console.log('听风');
};
};
var child = new Parent();
child.sayName(); //听风
var child = Parent();//报错,必须使用new调用

解释了构造函数,那么构造函数能用来做什么呢?最基本的就是属性继承了,我们先不聊继承模式,就从最基本的继承说起。

假设现在我们要定制一批蓝色的杯子,杯口直径与高度可互不相同,那么我们可以用构造函数表示:

//定制杯子
function CupCustom(diameter, height) {
this.diameter = diameter;
this.height = height;
};
CupCustom.prototype.color = 'blue';
var cup1 = new CupCustom(8, 15);
var cup2 = new CupCustom(5, 10);
console.log(cup1.height);//15
console.log(cup2.color);//blue

那么我们可以将构造函数CupCustom理解成一个制作杯子的模具,cup1与cup2是模具制作出来的杯子,我们称之为实例。大家可以尝试输出实例,可以看到两个实例都继承了构造函数的构造器属性(直径,高)与原型属性(颜色),颜色存放的地方还有点不同,它放在__proto__中,说到这咱们解释了为什么实例能读取height与color两个属性。

出于好奇,咱们也输出打印了构造函数的属性,有同学不知道怎么打印查看函数的属性,这里可以借用console.dir(函数),打印结果如下图:

对比图1与图2可以发现,构造函数除了自身属性与__proto__属性外还多出了一个prototype属性,这里我们其实能先给出一个结论:

所有的对象都有__proto__属性,但只有函数拥有prototype属性。

细心的同学应该还能发现,两者都有一个constructor属性指向了构造函数CupCustom。那么问题来了,prototype是啥,和__proto__有什么区别?constructor又是什么?为什么__proto__属性展开还包含了__proto_?别急,咱们从对象说起。

叁 ❀ JavaScript万物皆对象

叁 ❀ 壹 神奇的__proto__

了解JavaScript的同学一定听过这样两句话:

  • JavaScript中万物皆对象。
  • JavaScript是基于原型的语言。

通过这两句话,其实我们可以得出这样一个结论:

  • JavaScript中万物皆为对象,对象皆有原型。

光是看到万物皆对象这句话,脾气不好的同学已经要握紧砂锅大的拳头教会我什么是社会的毒打了,别慌,我们来论证这个结论。

我们知道JavaScript中数据类型分类基本数据类型与引用数据类型:

  • 基本数据类型:Number,String,Boolean,Undefined,Null,Symbol。
  • 引用数据类型:Object,Function,Date,Array,RegExp等。

引用数据类型也就是我们熟知的对象类型且种类繁多,大家最为熟悉的应该就是普通对象{},数组[]以及函数Function了。

我们来看看基本数据类型,不知道大家有没有想过这样一件事,为什么随便声明一段字符串就能使用字符串的方法?如果字符串真的就是简单类型,方法又是从哪来的呢?

'echo'.toUpperCase();//"ECHO"

经过试验可以发现,基本类型中除了undefined与null之外,任意数字,字符,布尔以及symbol值都有__proto__属性,以字符串为例,我们打印它的__ptoto__并展开,如下可以看到大量我们日常使用的字符串方法均在其中:

我们前面已经说了,所有的对象都有__ptoto__属性,而字符串居然也有__proto__属性,__proto__是一个访问器属性,它指向创建它的构造函数的原型prototype。还记得前面做杯子的构造函数吗?每实例个杯子其实只有直径与高度属性,但通过实例的__proto__属性我们找到了构造函数CupCustom的原型prototype,从而成功访问了prototype上的color属性。

你看,咱们说万物皆为对象,对象皆有原型,字符串都能通过__proto__属性找到自己的原型,它还能不是一个对象吗?

借此我们回答上面杯子构造函数留下来的问题,每个对象都有__proto__属性,你可以理解成是用来访问创建此对象的构造函数prototype的接口。函数最为特殊,它除了有__proto__属性外还有prototype属性,所以我们能直接通过prototype给函数添加原型属性,而实例能通过__proto__访问构造函数的原型属性或方法。

那为什么函数的prototype属性下还有一个__proto__属性呢?

我们知道函数有函数表达式,函数声明以及new创建三种模式,而函数声明其实等同于new Function(),我们定义的任意函数本质上也属于原始构造函数Function的实例,那么函数有一个__proto__属性指向构造函数Function的原型不是理所应当的事情么。所以这里我们又得出了一个结论:

每一个函数都属于原始构造函数Function的实例,而每一个函数又能做为构造函数生产属于自己的实例。

还是以函数CupCustom为例,它属于构造函数Function的实例,而它自己又作为构造函数生产了cup1这样的实例,为啥只有函数有prototype属性?就因为函数特殊身份,任性,这下总明白了吧。

叁 ❀ 贰 JavaScript中的包装对象

我在上文解释字符串属于对象时,有同学可能也想到了,对象都能添加属性,字符串怎么不能添加属性,比如:

var person = {};
person.name = 'echo';
console.log(person.name); //echo '听风是风'.age = 26;
console.log('听风是风'.age); //undefined

我们直接书写一个字符串这叫字符串直接量,是较为推荐的字符串创建形式,同样的字符串我们也能使用new创建,比如:

new String('听风是风');

如上图,这也解释了为什么字符串能拥有__proto__属性。

JavaScript有一个概念叫 包装对象,字符串,数字,布尔值均属于包装对象。包装对象的一大特点就是,当我们创建一个基本类型数据时,JavaScript在底层会对应创建一个基于此数据的包装类型对象,比如一段很常见的字符串转大写,可以拆分成如下步骤:

var name = 'echo';
var name_ = name.toUpperCase(); // 创建String实例,将实例赋予变量name
var string = new String('echo')
var name = string;
// 在实例上调用指定的方法
var name_ = name.toUpperCase();
// 销毁这个实例
string = null;

你看,JavaScript隐性做了额外的两件事,假设实例不被销毁,你会惊奇的发现,原来字符串上真的可以添加属性:

var string = new String('echo')
string.age = 26;
console.log(string.age); //26

我们又解锁了一个额外奖励结论:

String、Number、Boolen属于包装对象,包装对象是一种声明周期只有一瞬的对象,创建与销毁都由底层实现。

那么到这关于基本类型数据属于对象的结论算是说清楚了。

好奇心重的同学马上想到了基本数据类型中的undefined与null,这两兄弟是不是对象?

undefined与null均没有__proto__属性,且都不是对象。undefined表示未定义,它不是一个确切的值,不是对象也没有原型很正常。不对啊,typeof null明明是Object啊,怎么不是对象呢?这一点是JavaScript早期设计遗留下来的BUG且一直未得到修复,具体原因可查看MDN中关于typeof的附加信息。其次,有个小结论咱们要提前透露:

原型链的顶端是null。

所以null不是对象,身为原型顶点的null没有__proto__这很正常,因为它找不到自己的原型了,这点我们在下文介绍原型时会具体论证。

OK,我们花了较大的篇幅重新认知了对象,并介绍完了__proto__,是该介绍原型了,咱们接着聊。

肆 ❀ 认识原型prototype

肆 ❀ 壹 关于prototype

JavaScript中万物皆对象,且每个对象都有自己的原型,这是我们在上文得出的结论。说直白点就是,每个对象都有__proto__属性,对象都能通过此属性找到创建自己构造函数的原型。那么什么是原型呢?原型其实就是一个对象。

你想想原型能添加属性方法,而只有对象才拥有添加属性方法的特性。再如我们查看函数prototype下的__proto__属性,可以看到它的constructor属性指向是构造函数Object,还记得__proto__指向谁吗?所以说原型妥妥的是一个对象。

为什么这么说呢,这里又需要透露一个结论:

在不修改构造函数prototype前提下,所有实例__proto__属性中的constructor属性都指向创建自己的构造函数。

实例的__proto__指向的是创建自己的构造函数的prototype,这个prototype是一个对象,咱们先记住这一点。

我们知道java是基于类的语言,每一个实例都能找到自己对应的类。JavaScript语言在设计上借鉴了java,尽管在ES6之前没有类,但是你会惊奇的发现,JavaScript中眼见的数据类型基本都有对应创建自己的构造函数,比如:

数字 123 本质上由构造函数Number()创建,所以数字123通过__proto__访问构造函数Number()原型上的方法属性。

字符串 abc 本质上由构造函数 String()创建,所以abc也能通过__proto__访问构造函数String()原型上的方法属性。

函数本质上由原始构造函数Function创建,所以函数也能通过__proto__访问原始构造函数Function上的原型属性方法,别忘了,我们任意创建的函数都能使用call、apply等方法,不然你以为这些方法是哪来的呢。

上文也说了,我们自己创建构造函数其实和普通函数没任何区别,毕竟每个函数都能使用new调用用于创建属于自己的实例,这种继承方式是不是神似java的类,只是在JavaScript中改用原型prototype了。每一个函数都有作为构造函数的潜力,所以每一个函数都自带了prototype原型。

为了加深印象,还是以杯子的构造函数为例,我们抽象代码:

// 模拟代码,并不能真正执行
// 原始构造函数
function Function(){};
Function.prototype = {
call:function () {},
apply:function () {},
bind:function () {},
}; //由原始构造函数得到实例构造函数CupCustom
var CupCustom = new Function();
CupCustom.prototype = {
color:'blue'
};
// 由构造函数CupCustom最终得到实例
var cup1 = new CupCustom();

原始构造函数上有prototype原型对象,上面的call、apply每个函数都可以通过原型访问,而函数又可以作为构造函数调用,所以自定义构造函数又产生了属于自己的实例。通过这里我们可以知道:

原始构造函数Function()扮演着创世主女娲的角色,她创造了Object()、Number()、String()、Date()、function fn(){}等第一批人类(也就是构造函数),而人类同样具备了繁衍的能力(使用new操作符),于是Number()繁衍出了数据类型数据,String()诞生了字符串,function fn(){}作为构造函数也诞生了各种各样的对象后代。

我们可以通过如下代码论证这一点:

// 所有函数对象的__proto__都指向Function.prototype,包括Function本身
Number.__proto__ === Function.prototype //true
Number.constructor === Function //true String.__proto__ === Function.prototype //true
String.constructor === Function //true Object.__proto__ === Function.prototype //true
Object.constructor === Function //true Array.__proto__ === Function.prototype //true
Array.constructor === Function //true Function.__proto__ === Function.prototype //true
Function.constructor === Function //true

为啥说函数是JavaScript中的一等公民?女娲一般的存在,神仙啊!!!现在大家明白了没,万物都由函数产生啊,悟到了没?

所以当实例访问某个属性时,会先查找自己有没有,如果没有就通过__proto__访问自己构造函数的prototype有没有,前面说构造函数的原型是一个对象,如果原型对象也没有,就继续顺着构造函数prototype中的__proto__继续查找到构造函数Object()的原型,再看有没有,如果还没有,就返回undefined,因为再往上就是null了,这个过程就是我们熟知的原型链,说的再准确点,就是__proto__访问过程构成了原型链。

其实到这我们得到了两个结论,结论一:

在不修改构造函数原型的前提下,实例的__proto__与构造函数的prototype是对等关系。

比如下面这个例子:

function Parent() {};
var son = new Parent();
son.__proto__ === Parent.prototype;//true

原因很简单,上文解释了很多遍了,实例通过访问器属性__proto__访问创建自己的构造函数原型,相等是很正常的。

第二个结论上文提前给出了,原型链的顶点是null。我们来看个例子:

function Parent() {};
var son = new Parent();
console.log(son.__proto__); //找到了构造函数Parent的原型
console.log(son.__proto__.__proto__); //原型是对象,它的__proto__指向构造函数Object的原型
console.log(son.__proto__.__proto__.__proto__); //null,到头了,null不是对象,没有原型,所以不会继续往上了

结合代码注释以及上文原型链的解释,上文中三段__proto__分别是什么大家应该很清楚了吧。那么到这里,我们原型与原型链说的算是非常清楚透彻了。

肆 ❀ 贰 关于constructor

最后我们来说说constructor,我在上文已经给出了结论,这也是我想纠正的一个概念。很多人说实例的constructor指向创建自己的构造函数,但通过打印我们可以发现,实例自己并没有constructor属性,而是通过__proto__属性,找到了构造函数的原型,而构造函数的原型中有一个constructor属性指向自己。

如果你觉得有点绕,你可以这样理解,原型有很多,构造函数也有很多,我怎么知道这个原型是哪个构造函数的呢,constructor就起到了标识作用,函数的prototype指向自己,就是怕你弄糊涂。

这里借用其他博主一张直观的关系图。

伍 ❀ 问题解答

文章开头提出了很多问题,部分问题我们在文中已经给出了答案,大家可以尝试先回答看看,下文我们整理下统一给出答案。

1.什么是原型和原型链,原型链顶端是什么?

JavaScript中万物皆对象,且对象皆可通过__proto__属性访问创建自己构造函数的原型对象,说直白点,原型就是一个包含了诸多属性方法的对象,原型对象的__proto__指向构造函数Object()的原型。当一个对象访问某个属性时,它会先查找自己有没有,如果没有就顺着__proto__往上查找创建自己构造函数的原型有没有,这个过程就是原型链,原型链的顶端是null。

关于这个问题我印象非常深刻,17年10月我辞掉了武汉的工作奔赴了深圳,当时也就10个月工作经验,只会点JQ,自己又不是本专业出身,基础薄弱。群里大佬说招人能内推,而且是高级前端开发,当时接近年底工作真的难找(主要是自己菜),也算是想明白自己和高级到底有多少差距,还是去面试了。没有笔试题,面对面拿着简历聊,就问到了这个问题,从介绍对象到我回答说万物皆对象,一步步接着追问,可以说是把我虐的体无完肤,这也是为什么在本文中我要着重解释万物皆对象的原因。只不过当时面试官举得例子是亚当夏娃,我在文中换成了女娲。

2.原型链和作用域链有何区别?

这个算是第一个问题的拓展,所谓作用域链是在当前作用域查找某个变量时,如果没有就追溯到上层作用域,如果还没有则一直找到全局作用域,这个过程就是作用域链。区别就是,原型链顶端是null,作用域顶端是全局对象,原型链没找到某个属性返回undefined,而作用域链没找到会直接报错,告诉你未声明。

3.构造函数与普通函数有什么区别?

文中已经给出了答案,没有区别。函数均为被普通调用和new调用,所以你可以说函数都是构造函数,也正因如此,ES6才推出了Class类,算是给了构造函数一个真正的名分。

4.能否判断当前函数是普通调用或new构造调用?

这个问题我在 js 手动实现bind方法,超详细思路分析!这篇文中有给出答案,其实就是区分函数执行时this指向。如果是普通调用,this绑定属于默认绑定,一定会指向全局window(非严格模式)。如果是new调用,那自然是指向构造函数内创建的实例了,而上文我们知道实例可以通过__proto__找到构造函数的原型,原型的constructor属性又指向构造函数自身,来看个例子:

// 非严格模式
function fn() {
if (this === window) {
console.log('现在是普通调用');
} else if (this.constructor === fn) {
// 因为原型链自己会找,所以我们直接通过this.constructor访问constructor属性,不加__proto__了
console.log('现在是new调用');
};
};
fn();//现在是普通调用
new fn();//现在是new调用

2020.5.9新增 我们还可以使用new.target字段判断是否为new调用,如果为new调用,此字段将指向函数本身。

function fn() {
console.log(new.target === fn);
};
fn(); //false
new fn(); //true

5.prototype__proto_是什么?

prototype是原型对象,__proto__是访问器属性,对象就是通过这个家伙访问构造函数的原型对象。

6.判断对象是否有某条属性?

有些同学马上想到了使用obj.的方式判断,没有就是undefined,那假设我这个属性值就是undefined那不就完蛋了。

var obj = {
name: undefined
};
obj.nam; //undefined

推荐做法是使用in:

var obj = {
name: undefined
};
console.log('name' in obj);//true
console.log('age' in obj);//false

7.怎么判断某条属性是否为对象自身属性而非原型属性?

算是问题6的衍生问题,in只能判断有没有某条属性,不能判断此属性是不是对象自身属性,如果要判断这一点,就要借用hsaOwnProperty()方法了,看个例子:

function Fn() {
this.name = '听风是风';
};
Fn.prototype.age = 26;
var obj = new Fn();
console.log('name' in obj);//true
console.log('age' in obj);//true
console.log(obj.hasOwnProperty('name'));//true
console.log(obj.hasOwnProperty('age'));//false

对于实例obj来说,name是它自己拥有的属性,而age是原型上借来的属性,所以在上述例子中有所区分。

8.constructorinstanceOf有何区别?

在判断对象类型时,有时我们会用到instanceOf,而通过本身,其实constructor也能做到类型判断,那么这两点有何区别呢:

constructor是原型对象中一个属性,instanceOf是一个运算符,且constructor返回的是创建实例的构造函数,是一个方法,而instanceOf返回的时一个布尔值;最重要的,instanceOf可以判断是否属于原型链的任意一层,constructor则是找上一层。

而在判断实例是否由某个构造函数创建时,特殊情况下,instanceOf比constructor更为准确,看个例子:

function Person() {
this.name = '听风是风';
}; Person.prototype = {
name: 'echo',
age: '26'
}; var person = new Person();
console.log(person.constructor === Person); //false
console.log(person instanceof Person); //true

这也是为什么在上文中,我们在介绍__proto__与constructor时一定要加上在未修改构造函数原型为前提条件的原因。constructor说到底是原型属性,你把原型改了,它就找不到自己的构造函数了,但instanceOf并非如此。

9.能不能手动实现new方法?

我不仅能手动实现new,我还能实现call,apply与bind,来波内连推荐:

js new一个对象的过程,实现一个简单的new方法

js 实现call和apply方法,超详细思路分析

js 手动实现bind方法,超详细思路分析!

10.能否创建严格意义上的空对象?

我们随便创建一个空对象{}严格意义上说并不是真正的空对象,因为它本质上还是new Object()出来的,所以具有__proto__以及一对原型属性。那么怎么创建严格意义上的空呢?JavaScript中谁没有原型?请大声告诉我!没错,就是null,咱们可以这样:

//方法一
var obj = Object.create(null);
console.log(obj)//{} 真正的空对象 //方法二
var obj = {};
Object.setPrototypeOf(obj,null); //参数一 将被设置原型的对象. 参数二 该对象新的原型链
console.log(obj)//{} 真正的空对象

undefined虽然也没有原型,但是不能这样用,会报错。

陆 ❀ 总

其实读完这篇文章,我想各位一定和我有同样的想法,我知道了原型,开发中我好像也用不上。没错,但这也不影响你这次真的知道了什么是原型和原型链,不影响你在面试时对于是对象,函数的理解又上了一个台阶。我们知道原型继承有花里胡哨贼多种方式,如果我们不懂原型,又从何理解这些继承模式呢?你说对吧。

这篇文章前前后后花了我一周时间,光是周六,我就从中午十二点一直写到了下午五点,我需要整合语言,我需要解答自己的疑惑,当然我最想的就是把大家都整的明明白白。

时隔这么久才发了这一篇博客,主要原因还是受疫情影响,我家在湖北仙桃,这次回来也没带电脑,封城至今出不去,也买不了电脑,物流不配送,只能去我哥家借电脑远程上班苟延残喘...心里还是希望国家能快点战胜新冠病毒,大家都健健康康,医护人员也能尽快休息。

有问题请留言,我会在第一时间回复大家,那么到这里,本文正式结束了。近七千字,算是我写过最有耐心的一篇文章了...

有兴趣可以阅读博主下面这篇文章,这篇文章介绍了Function.prototype与Object.prototype究竟是什么东西,谁更早出现之类的有趣问题。

2020.2.29更新

JS 究竟是先有鸡还是有蛋,Object与Function究竟谁出现的更早,Function算不算Function的实例等问题杂谈

2020.7.2更新

今天同事问了我一个很有的问题,代码如下,问我分别输出什么?

var a = 2;
console.log(a instanceof Number);
console.log(a.constructor === Number);

当我看到代码,脑袋里第一想到了两个true。我就对他说,如果是2个true你就不会考我了,于是在控制台输出了一下,发现第一个是false,第二个是true。

同事就提出了疑问,说这个2照理来说也是Number构造函数的实例,怎么instanceof还为false,感觉之前的理解被颠覆了...

于是我打开百度,输入1 instanceof Number定位找到了原因,理由很简单,instanceof语法其实是object instanceof constructor,左边必须是一个对象,不是对象就直接false了。

如果我们是通过new的数字,像这样,你看它就没问题:

var a = new Number(1);// 此时是个包装对象
typeof a;//Object
a instanceof Number;// true

最后补充一点的是,JS总是会将包装对象转变为基础类型,比如下面这个例子:

var a = new Number(1);
typeof (a+1);// number

柒 ❀ 参考

最详尽的 JS 原型与原型链终极详解,没有「可能是」。(一)

你还认为JS中万物皆对象?

[重新认识构造函数、原型和原型链](https://www.muyiy.cn/blog/5/5.1.html#引言]

JS 疫情宅在家,学习不能停,七千字长文助你彻底弄懂原型与原型链,武汉加油!!中国加油!!(破音)的更多相关文章

  1. MySQL(十四)分析查询语句Explain 七千字总结

    分析查询语句:EXPLAIN 1概述 ​ 定位了查询慢的SQL之后,就可以使用EXPLAIN或者DESCRIBE工具做针对性的分析查询.两者使用方法相同,并且分析结果也是相同的. ​ MySQL中有专 ...

  2. 转-Spring 注解学习手札(七) 补遗——@ResponseBody,@RequestBody,@PathVariable

    转-http://snowolf.iteye.com/blog/1628861/ Spring 注解学习手札(七) 补遗——@ResponseBody,@RequestBody,@PathVariab ...

  3. Spring 注解学习手札(七) 补遗——@ResponseBody,@RequestBody,@PathVariable(转)

    最近需要做些接口服务,服务协议定为JSON,为了整合在Spring中,一开始确实费了很大的劲,经朋友提醒才发现,SpringMVC已经强悍到如此地步,佩服! 相关参考: Spring 注解学习手札(一 ...

  4. 我的MYSQL学习心得(七) 查询

    我的MYSQL学习心得(七) 查询 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类 ...

  5. 【特别推荐】Node.js 入门教程和学习资源汇总

    这篇文章与大家分享一批很有用的 Node.js 入门教程和学习资源.Node 是一个服务器端的 JavaScript 解释器,它将改变服务器应该如何工作的概念.它的目标是帮助程序员构建高度可伸缩的应用 ...

  6. opencv学习笔记(七)SVM+HOG

    opencv学习笔记(七)SVM+HOG 一.简介 方向梯度直方图(Histogram of Oriented Gradient,HOG)特征是一种在计算机视觉和图像处理中用来进行物体检测的特征描述子 ...

  7. 《JS高程》事件学习笔记

    事件:文档或浏览器窗口中发生的一些特定的交互瞬间,也即用户或浏览器自身执行的某种动作. -------------------------------------------------------- ...

  8. [Python学习笔记][第七章Python文件操作]

    2016/1/30学习内容 第七章 Python文件操作 文本文件 文本文件存储的是常规字符串,通常每行以换行符'\n'结尾. 二进制文件 二进制文件把对象内容以字节串(bytes)进行存储,无法用笔 ...

  9. Node.js 入门教程和学习资源汇总

    这篇文章与大家分享一批很有用的 Node.js 入门教程和学习资源.Node 是一个服务器端的 JavaScript 解释器,它将改变服务器应该如何工作的概念.它的目标是帮助程序员构建高度可伸缩的应用 ...

  10. VSTO学习笔记(七)基于WPF的Excel分析、转换小程序

    原文:VSTO学习笔记(七)基于WPF的Excel分析.转换小程序 近期因为工作的需要,要批量处理Excel文件,于是写了一个小程序,来提升工作效率. 小程序的功能是对Excel进行一些分析.验证,然 ...

随机推荐

  1. 洛谷 P9916 「RiOI-03」Just a Q. (Easy ver.) 题解

    前言 Div.2 Rank \(13\) 获奖了,题目也好评. 解法 题目链接:\(\color{Purple}\texttt{P9916「RiOI-03」Just a Q. (Easy ver.)} ...

  2. iview 表单有值却校验失败

    转载请注明出处: iview 表单校验数值的时候,表单有值,却在提交的时候,提示表单校验失败: 解决方案: 1. IviewUI的文档里查到了rules规则里面有个校验类型的属性字段type rule ...

  3. springboot启动流程 (3) 自动装配

    在SpringBoot中,EnableAutoConfiguration注解用于开启自动装配功能. 本文将详细分析该注解的工作流程. EnableAutoConfiguration注解 启用Sprin ...

  4. VSCode + GCC编译器(MinGW)开发环境中文字符乱码问题踩坑与解决办法

    .markdown-body { line-height: 1.75; font-weight: 400; font-size: 16px; overflow-x: hidden; color: rg ...

  5. [springmvc] - 配置文件 springmvc-config.xml 和 web.xml

    springmvc-config.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmln ...

  6. 处理命令行main函数args参数

    引用 System.CommandLine 库(需要显示预览版才能看到) var fileOption = new Option<FileInfo?>( name: "--fil ...

  7. 百度网盘(百度云)SVIP超级会员共享账号每日更新(2024.01.02)

    一.百度网盘SVIP超级会员共享账号 可能很多人不懂这个共享账号是什么意思,小编在这里给大家做一下解答. 我们多知道百度网盘很大的用处就是类似U盘,不同的人把文件上传到百度网盘,别人可以直接下载,避免 ...

  8. [转帖]Web技术(六):QUIC 是如何解决TCP 性能瓶颈的?

    文章目录 一.QUIC 如何解决TCP的队头阻塞问题? 1.1 TCP 为何会有队头阻塞问题 1.2 QUIC 如何解决队头阻塞问题 1.3 QUIC 没有队头阻塞的多路复用 二.QUIC 如何优化T ...

  9. Raid卡在Write back 与Write through 时的性能差异

    还是读姜老师的 mysql技术内核innodb存储引擎这本书里面的内容. 之前知道raid卡的设置会影响性能, 预计也是十几倍的性能差距, 但是从来没有用数据库进行过验证 书中有针对不通raid卡的设 ...

  10. 你对iframe知道多少

    iframe 嵌套第三方页面出现的问题 我们需要通过一个接口获取被嵌套的地址. 然后将改地址赋值给iframe的src中,代码如下 <template> <div> <i ...