当前位置: 首页 > 编程日记 > 正文

JavaScript夯实基础系列(四):原型

在JavaScript中有六种数据类型:number、string、boolean、null、undefined以及对象,ES6加入了一种新的数据类型symbol。其中对象称为引用类型,其他数据类型称为基础类型。在面向对象编程的语言中,对象一般是由类实例化出来的,但是在JavaScript中并没有类,对象是以与类完全不同的设计模式产生的。

一、创建对象

最常用来创建的方式是通过对象字面量的方式,简单便捷。但是该方式为单例模式,如果创建类似的对象会产生过多重复的代码,如下代码所示:

var person1 = {name: 'LiLei',age: 18,sayName: function () {console.log(this.name)}
}
var person2 = {name: 'HanMeiMei',age: 18,sayName: function () {console.log(this.name)}
}
person1.sayName() // LiLei
person2.sayName() // HanMeiMei

使用工厂模式能够避免产生重复代码,但是工厂模式的弊端在于不能很好的将产生的对象分类。如下代码所示:

function person (name, age) {var obj = new Object()obj.name = nameobj.age = ageobj.sayName = function () {console.log(this.name)}return obj
}var person1 = person('LiLei',18)
var person2 = person('HanMeiMei',18)person1.sayName() // LiLei
person2.sayName() // HanMeiMei

1、构造函数模式

构造函数模式能够将实例化出来的对象很好的分类,如下代码所示:

function Person (name, age) {this.name = namethis.age = agethis.sayName = function () {console.log(this.name)}
}var person1 = new Person('LiLei',18)
var person2 = new Person('HanMeiMei',18)person1.sayName() // LiLei
person2.sayName() // HanMeiMei

首先要说明的是,在JavaScript中并不存在构造函数的语法,有的仅仅是函数的构造调用。构造函数与普通的函数没有什么不同,当函数通过关键字new来调用时才称为构造函数。用来作为构造函数调用的函数名以大写字母开头也是一种书写规范,JavaScript语言层面没有这种约束。通过new关键字来调用构造函数经历了以下四个阶段:

1、创造一个空对象。
2、对象的[[proto]]属性指向构造函数prototype属性指向的对象。
3、以新建的空对象为执行上下文,通过构造函数内部的代码初始化空对象。
4、如果构造函数有返回值且是对象,则返回该对象。否则,返回新建的对象。

对比工厂模式来说,构造函数模式能够清楚的将对象分类;对比单例模式来说,构造函数不会产生大量重复的代码。但是也不是完全没有产生重复代码,如上代码所示:person1对象和person2对象是可以共享一个sayName方法的。只使用构造函数模式,每个对象都有各自新的方法,彼此之间不能共享,为了克服这种缺陷,原型模式应运而生。

2、原型模式

每一个函数在创建时会拥有一个prototype属性(Function.bind()方法返回的函数除外),该属性指向同时创建的该函数的原型对象,在这个原型对象中拥有一个不可枚举的属性constructor,该属性指向原型对应的函数。

  通过构造函数生成的实例对象拥有一个指向该构造函数原型对象的的指针,在ES5中被称为[[proto]],ES6中称为__proto__。在通过构造函数创建对象的过程中,实质上就做了两件事:1、将实例对象的[[proto]]属性指向构造函数prototype属性指向的对象;2、将实例对象作为构造函数的执行上下文,执行构造函数完成初始化。一旦实例对象构建完毕,跟原有的构造函数不再有什么关系,即使可以将实例对象以构造函数名称分类也是通过原型对象来判定的。

  在实例对象中查找属性时,先在对象自身上查找,如果没有找到会通过[[proto]]来在原型链上查找。

  构造函数、原型对象、实例对象三者的关系如下图所示:

948021-20180712180347624-651394392.png

原型模式本质上就是共享,所有[[proto]]指针指向原型对象的实例对象,都可以访问该原型对象上的属性。实例对象上如果有跟原型对象同名的属性,就会形成“遮蔽”,访问该属性时就会访问实例对象上的值,而不是原型对象上的值。不能通过实例对象来修改原型上的属性值,但是这个性质就跟ES6中定义常量的关键字const一样,不可以改变的是这个属性的地址,如果原型对象上的属性是引用类型的话,引用类型的地址不可以改变,引用指向的对象却可以通过实例对象来改变。如下代码所示:

function Student () {}
Student.prototype.score = 60
Student.prototype.course = ['语文','数学']let LiLei = new Student()
let HanMeiMei = new Student()console.log(LiLei.score) // 60
console.log(HanMeiMei.score) // 60LiLei.score = 90
console.log(LiLei.score) // 90
console.log(HanMeiMei.score) // 60LiLei.course.push('英语')
console.log(LiLei.course) // ['语文','数学','英语']
console.log(HanMeiMei.course) // ['语文','数学','英语']

原型模式基本上不单独使用,因为原型模式产生的对象都一样,不能像构造函数那样通过传递参数来完成各自的初始化。罗素说过:“参差多态才是幸福的源泉”,面向对象编程很大程度上是模拟现实世界,所以这句话在编程世界里同样适用。

3、构造函数与原型模式组合使用

组合使用构造函数和原型模式是创建自定义对象最常见的方式。通过构造函数传参使对象拥有实例属性,通过原型对象来使同一类型的对象共享属性。一般来说,引用对象属于实例属性,原型对象上没有除了函数以外的引用对象,防止一个对象修改原型对象上的引用对象影响其它对象。如下代码所示:

function Student (name,age) {this.name = namethis.age = age
}
Student.prototype.score = 60let LiLei = new Student('LiLei',18)
let HanMeiMei = new Student('HanMeiMei',16)console.log(LiLei.name) // LiLei
console.log(LiLei.age) // 18
console.log(LiLei.score) // 60
console.log(HanMeiMei.name) // HanMeiMei
console.log(HanMeiMei.age) // 16
console.log(HanMeiMei.score) // 60

4、修改原型对象

在向构造函数的原型中添加属性或者函数时,逐个添加有时候显得比较繁琐,因此很多时候是直接更改构造函数的原型对象。如下代码所示:

function Student (name,age) {this.name = namethis.age = age
}Student.prototype = {score: 60,sayName: function () {console.log(this.name)},sayAge: function () {console.log(this.age)}
}let LiLei = new Student('LiLei',18)
LiLei.sayName() // LiLei

在这里有两点需要注意,第一点是这种方式废弃构造函数原有的原型对象,新建一个对象来作为构造函数的原型对象。这就导致了一个问题:如果在添加新原型对象之前就通过构造函数创建对象,那么创建的对象的[[proto]]属性指向的依然是老的原型对象,新原型对象上的一切属性与该对象无关。第二点是函数创建时自动生成的原型对象中有一个不可枚举的属性constructor,该属性是一个指向函数的指针。在新创建的对象中没有这个属性,如果要用到该属性来判定对象的类别,那么可以自行添加。如下代码所示:

function Student (name,age) {this.name = namethis.age = age
}
Student.prototype.score = 80
let HanMeiMei = new Student('HanMeiMei',16)Student.prototype = {score: 60,sayName: function () {console.log(this.name)}
}
Object.defineProperty(Student.prototype,'constructor',{value: Student,enumerable: false
})let LiLei = new Student('LiLei',18)
console.log(LiLei.score) // 60
LiLei.sayName() // LiLeiconsole.log(HanMeiMei.score) // 80
HanMeiMei.sayName() // TypeError

二、继承

继承是面向对象编程中的一个重要概念,在JavaScript中继承是通过原型链来实现的。

1、原型继承

原型继承的思路是子对象的原型是父对象的实例,几乎所有的对象都继承自Object,这里说几乎是因为可以通过Object.create()方法来创建不继承自任何对象的对象。

function Person () {this.name = 'person'
}
Person.prototype.sayName = function () {console.log(this.name)
}function Student () {this.id = '001'
}
Student.prototype = new Person()
Student.prototype.sayId = function () {console.log(this.id)
}let LiLei = new Student()
LiLei.sayId() // 001
LiLei.sayName() // person
console.log(LiLei.toString()) // [object Object]

如上代码所示,函数Student的原型对象是Person函数的实例,所以对象LiLei可以使用Person原型对象上的属性。而函数Person的原型对象是Object函数的实例,所以对象LiLei可以使用Object.prototype.toString()方法。如下图所示:

948021-20180712180416628-1156385143.png

对象查找属性的规则是:先在对象自身上查找,若查找到则停止,否则沿着原型链继续查找。即查找[[proto]]指针指向的对象,查找到则停止,查询不到则查找该对象[[proto]]指针指向的对象,直到Object.prototype为止。

  对象添加属性的情况却比较复杂:对象自身有要添加的属性时,只是修改自身的值;当要添加的属性不在对象自身上,而在对象原型链上能够找到时分三种情况,以向对象obj上添加属性add为例:

1、在原型链上找到的add属性是数据属性且不是只读属性,则add添加到obj上,形成遮蔽

2、在原型链上找到的add属性是数据属性且是只读属性,则add属性添加失败,obj对象自身不会有add属性。

3、在原型链上找到的add属性是一个setter,这个setter会被调用,add属性添加失败。

上述描述的后两种情况都是属性添加失败,这两种情况下想要强制添加属性可以用Object.defineProperty()方法。

2、组合继承

在使用原型模式创建对象的时候有两个问题:一是引用类型不适合放在原型对象上,二是没办法通过传参来初始化对象。使用原型继承依然会存在这两方面的问题,上述代码将父构造函数的实例作为子构造函数的原型,那么在很多时候子构造函数的原型中拥有引用类型的属性,而且还不能向父构造函数中传递参数。为消除单独使用原型继承的弊端,一般都是使用借用构造函数原型继承的组合来实现继承的。

  函数通过new来构造调用时执行上下文默认是新创建的对象,但是在JavaScript中可以通过apply()和call()方法来给函数任意指定执行上下文,所谓借用构造函数就是使用这条性质,来使用父构造函数完成对子构造函数实例对象的初始化。如下代码所示:

function Person (person1,person2) {this.friends = []this.friends.push(person1)this.friends.push(person2)
}function Student (person1,person2) {Person.call(this,person1,person2)
}let LiLei = new Student('tom','mary')
let HanMeiMei = new Student('tom','mary')
LiLei.friends.push('penny')
console.log(LiLei.friends) // ['tom','mary','penny']
console.log(HanMeiMei.friends) // ['tom','mary']

单独使用借用构造函数可以很方便的定制对象的实例属性,但是在共享方面却很欠缺,因此实现继承一般是将原型继承借用构造函数组合使用。组合继承的思路是:通过原型链实现原型属性和方法的继承,通过借用构造函数实现对实例属性的继承。如下代码所示:

function Person (name) {this.name = namethis.friends = ['tom','mary']
}Person.prototype.sayName = function () {console.log(this.name)
}function Student (name,age) {Person.call(this,name)this.age = age
}Student.prototype = new Person()
Student.prototype.sayAge = function () {console.log(this.age)
}let LiLei = new Student('LiLei',20)
LiLei.friends.push('pony')
console.log(LiLei.name)
console.log(LiLei.friends)let HanMeiMei = new Student('HanMeiMei',18)
console.log(HanMeiMei.name)
console.log(HanMeiMei.friends)

3、继承的本质

在优化上述代码之前,先说一下JavaScript中继承的本质。通过new关键字对函数进行构造调用时,将新对象中[[proto]]指针指向构造函数的prototype指向的对象,然后将实例对象作为执行上下文来执行一遍构造函数。所谓继承,本质上就是对象的[[proto]]指针指向另一个对象,当查找对象上的属性时,先查询自身,没找到的话再沿着[[proto]]指针查询。其实这种方式称为委托更为合适,对象一部分属性在对象自身上,另外一部分属性或者方法委托给了另外一个对象。如果只考虑这种委托关系,不考虑对象自身上的属性的话可以不经过new关键字,直接为新创建的对象指定原型对象。

  在ES5中添加了Object.create()方法体现了继承实际上是对象委托的本质。该方法创建一个新对象链接到指定的对象,可以接收两个参数,第一个参数为指定的原型对象,第二个参数是要添加进新对象自身上的属性。其中该方法接收的第二个参数与Object.definePropertier()方法的第二个参数相同,每个属性都是通过自己的描述符定义的。如下代码所示:

let Person = {name: 'any',age: 18
}let LiLei = Object.create(Person,{name: {value: 'LiLei'}
})console.log(LiLei.name) // LiLei
console.log(LiLei.age) // 18

Object.create()方法是对原型式继承的规范实现。所谓原型式继承是指不必创建自定义类型,基于已有对象创建新对象。在不兼容Object.create()的情况下可以使用如下代码部分填补:

if (!Object.create) {Object.create = function(o) {function F(){}F.prototype = o;return new F();};
}

之所以说是部分填补是因为上述方式并没用办法使用像Object.create()第二个参数那样为新对象添加属性。

4、优化组合继承

说完继承的本质之后来优化一下组合继承的代码。组合继承的方式通过借用父构造函数来实例化新对象,然后将子构造函数的原型链接到父构造函数的实例对象上,这会导致调用两次父构造函数来重复创建相同的属性。如下代码所示:

function Person (name) {this.name = namethis.friends = ['tom','mary']
}function Student (name,age) {Person.call(this,name)this.age = age
}Student.prototype = new Person()let LiLei = new Student('LiLei',20)
console.log(LiLei) // {age: 20, friends:[ "tom", "mary" ], name: "LiLei"}
console.log(Student.prototype) // {friends:[ "tom", "mary" ], name: undefined}

可以看出实例对象上和原型对象上的属性有重复,这是将父构造函数实例对象作为原型对象的后遗症。因为查询对象属性的时候,对象自身拥有属性会对原型对象上的属性形成“遮蔽”,从这个角度来说组合继承完全可以达到继承的目的。但是冗余数据终归是不好的,可以通过原型式继承来加以优化:通过借用父构造函数来实例化对象,通过直接将子构造函数的prototype指向父构造函数的原型对象来实现继承。如下代码所示:

function Person (name) {this.name = namethis.friends = ['tom','mary']
}Person.prototype.score = 60function Student (name,age) {Person.call(this,name)this.age = age
}Student.prototype = Object.create(Person.prototype)let LiLei = new Student('LiLei',20)
console.log(LiLei) // {age: 20, friends:[ "tom", "mary" ], name: "LiLei"}
console.log(Student.prototype) // {}

这种方式被称为寄生组合式继承,是实现引用类型继承的最佳方式。

三、对象的类型

在JavaScript中检测数据类型可以使用typeof操作符,如下代码所示:

var a;
typeof a;                // "undefined"a = "hello world";
typeof a;                // "string"a = 42;
typeof a;                // "number"a = true;
typeof a;                // "boolean"a = null;
typeof a;                // "object" -- 当做空对象处理a = undefined;
typeof a;                // "undefined"a = { b: "c" };
typeof a;                // "object"

在使用typeof关键字检测对象类型时,并不能返回对象的具体类型。对于对象类型的检测,通常遵循“鸭式辩型”的原则:

像鸭子一样走路、游泳以及鸣叫的鸟就是鸭子

在JavaScript中,不关心对象的类型是什么,而是关心对象能够做什么。当然有些时候也需要知道对象的类型,可以通过如下几种各有缺陷的方式来判定对象类型。

1、constructor

除了Function.bind()返回的函数之外,所有的函数执行时都有一个prototype属性,prototype指向该函数的原型对象,在自动生成的原型对象中有一个不可枚举的属性constructor,constructor指向该函数。在该函数构造调用时,创建的实例对象中[[proto]]与构造函数prototype指向相同的原型对象。可以通过这个关系来确定实例对象的类型,如下代码所示:

function Person () {this.age = 18
}
let LiLei = new Person()
console.log(Person.prototype.constructor === Person) // true
console.log(LiLei.constructor === Person) // true

使用constructor属性来判定对象的类型在多个执行上下文的场景下无法工作,比如在浏览器打开多个窗口来显示子页面, 子页面中的对象是同一类型也没办法使用constructor属性来判定。

  使用constructor属性来判定对象类型是建立在不变更构造函数默认原型对象的基础上,但是在很多时候都会改变默认原型的。比如感觉一个一个往函数原型上添加属性和方法比较繁琐,一般会通过字面量的方式创建一个新的对象来作为原型对象;还有在实现继承时将父构造函数的实例对象或者原型对象作为子构造函数的原型时;在这些情况下,需要往新的原型对象上添加一个不可枚举的属性constructor来指向构造函数。

  一般没有必要特意去维持这种比较脆弱的关系,在很多时候不经意间就改变了constructor属性的指向或者改变了原型对象,因此不提倡使用constructor来判定对象的类型。

2、prototype

原型对象是对象类型的唯一标志。当且仅当两个对象继承自同一原型对象时,这两个对象才属于相同类型。

  isPrototypeOf()方法可以判断对象之间是否有原型关系,用于测试一个对象是否存在于另一个对象的原型链上。如下代码所示:

function Person (name) {this.name = name
}let LiLei = new Person('LiLei')console.log(Person.prototype.isPrototypeOf(LiLei)) // true
console.log(Object.prototype.isPrototypeOf(LiLei)) // true

ES5中新增的了Object.getPrototypeOf()方法,该方法返回指定对象的原型,即内部[[Prototype]]属性的值。如下代码所示:

function Person (name) {this.name = name
}Person.prototype.score = 60let LiLei = new Person('LiLei')console.log(Object.getPrototypeOf(LiLei)) // { score:60 }
console.log(Object.getPrototypeOf(LiLei) === Person.prototype) // true

3、instanceof

检测对象和原型对象之间的关系简单直接,有时希望确定实例对象与构造函数之间的关系,可以通过instanceof运算符来检测。instanceof运算符用来检测函数的prototype属性指向的对象是否存在于参数实例对象的原型链上。如下代码所示:

function Person (name) {this.name = name
}Person.prototype.score = 60function Animal () {this.type = 'dog'
}function Student (name,age) {Person.call(this,name)this.age = age
}Student.prototype = Object.create(Person.prototype)let LiLei = new Student('LiLei',20)console.log(LiLei instanceof Student) // true
console.log(LiLei instanceof Person) // true
console.log(LiLei instanceof Object) // true
console.log(LiLei instanceof Animal) // false

isPrototypeOf()、instanceof运算符来判断对象的类型时,只能检测对象属不属于某一类型,而不能通过对象来获取类型名称。Object.getPrototypeOf()方法只能获取对象[[proto]]指针指向的对象。另外这些方法检测对象类型和constructor运算符一样,在多个执行上下文的场景下无法工作。

四、总结

作为面向对象编程语言,JavaScript中没有类,只有对象。在通过构造函数创建对象时,没有发生其他面向对象编程语言中从类中“拷贝”的事情,只是创建一个新对象,作为构造函数的执行上下文来执行构造函数而已,对象最终通过原型链链接在一起。

  创建对象最常见的方式是采用对象字面量的方式,而创建特定类型的自定义对象最常用的组合使用构造函数和原型模式的方式。使用构造函数添加实例对象的自身属性,使用原型对象来添加同一类型对象共享的属性和方法,一般对象的引用类型属性的添加都是放在构造函数中的。

  JavaScript中的继承更确切的名称是委托,通过对象之间的委托来实现方法和属性的共享以及复用,可以通过Object.create()方法来直接完成这种委托关系。一个对象想要继承自身拥有引用类型属性的对象的全部属性和方法,实现的最佳方式是寄生组合式继承

  原型对象是对象类型的唯一标志,想要确定对象的类型,可以通过验证对象的原型来实现。JavaScript更多关注的是对象能做什么,而不是对象是什么类型。

如需转载,烦请注明出处:https://www.cnblogs.com/lidengfeng/p/9300910.html

转载于:https://www.cnblogs.com/lidengfeng/p/9300910.html

相关文章:

python中意外缩进是什么意思_Python 的缩进是不是反人类的设计?

前些天,我写了《Python为什么使用缩进来划分代码块?》,文中详细梳理了 Python 采用缩进语法的 8 大原因。我极其喜欢这种简洁优雅的风格,所以对它赞美有加。 然而文章发出去后,非常意外,竟收到了大量的反对…

netstat命令

使用netstat -nap可以查看当前发送和接收队列,Send-Q 很高时表示发送队列太长,可能网络阻塞 转载于:https://www.cnblogs.com/wx170119/p/11606909.html

mysql操作数字名称的schema时字符的逃逸问题

一个简单的问题折腾了好大一会儿,mysql不支持直接操作数字名称的schema,在sql操作时必须做字符逃逸,如: char sql_str[1000]; memset(sql_str, 0x0, 1000); sprintf(sql_str, "CREATE TABLE IF NOT EXIST %s.%s(data_id INT(…

使用XMLSpyDocEditPlugIn2.dll,页面加载失败

维护项目中遇到问题,项目用到XMLSpyDocEditPlugIn2.dll的acticex控件,客户换了其他pc后,不能下载安装acticex控件,所以不能使用此功能。解决方法: 1 下载 XMLSpyDocEditPlugIn2.dll, 路径 http://download.…

[bzoj4562][Haoi2016]食物链_记忆化搜索_动态规划

食物链 bzoj-4562 Haoi-2016 题目大意:给你n个点,m条边的DAG,求所有的满足条件的链,使得每条链的起点是一个入度为0的点,中点是一条出度为0的点。 注释:$1\le n\le 10^5$,$1\le m\le 2*10^5$。 …

Apache源码包在LINUX(CENTOS6.8)中的安装(出现问题及解决)

任务:在CENT6.8系统中安装Apache(版本为:httpd-2.4.41) 前提:由于源码包必须先编译后安装,所以必须先安装编译器:gcc 理论步骤: 1.检测gcc软件包,如果不存在则进行安装。…

append函数_连载|想用Python做自动化测试?函数的参数传递机制及变量作用域

“ 这一节有点难。看不懂没关系。继续往后学,回头再来看。”10.6 函数参数传递的机制10.6.1 值传递与引用传递编程语言的参数传递机制通常有两种:值传递拷贝参数的值,然后传递给函数里的新变量。这样,原变量和新变量之间互相独立&…

PowerDesigner生成数据库

此文中图片不小心被删除了,特重写了PowerDesigner生成数据库修改 一、 用POWERDESIGNER生成数据库 FILE-》NEW 在MODEL NAME中输入模版名 在DBMS中选择要连接的数据库类型 点击确定 确定后出现如下页面 选中工具条面版上的 表按钮 在…

随想_8_Windows_XP_Explorer_错误

最近发现微软的系统的稳定性,还是有待提高啊,这不XP SP3的资源管理器,就犯毛病了,俗话说有图 有真相,各位请看: 大家看,资源管理器左边的导航栏, 就可以发现,里面很多东西…

webpack笔记(6)调试模式

在配置devtool时,webpack给我们提供了四种选项。 source-map:在一个单独文件中产生一个完整且功能完全的文件。这个文件具有最好的source map,但是它会减慢打包速度;cheap-module-source-map:在一个单独的文件中产生一个不带列映射的map,不带…

nicstat命令安装与分析

nicstat安装包下载与安装: wget https://downloads.sourceforge.net/project/nicstat/nicstat-1.95.tar.gz tar -zxvf nicstat-1.95.tar.gz cd nicstat-1.95 cp Makefile.Linux Makefile vi Makefile 后修改 CFLAGS $(COPT) make && make install //…

component是什么接口_【Android每日一题】从Activity创建到View呈现中间发生了什么?...

前言前段时间公司招人,作为面试官,我经常让面试者简述View的绘制流程。他们基本都能讲明白View的测量(measure)、布局(layout)、绘制(draw)等过程。还有少数人会提到DecorView和ViewRootImp的作用。但是,当我继续追问关于Window的内容时&…

wp 删除独立存储空间文件(多级非空文件夹删除)

void DelFile(string unZipFilePath)//unZipFilePath第一次传递的是根目录名 { using (var store IsolatedStorageFile.GetUserStoreForApplication()) { if (store.DirectoryExists(unZipFilePath)) { …

重拾博客小序与杂思

寒假期间,条件所限,不能上网,也不能更新博客。寒假结束,懈怠了两个星期,打算重拾博客,继续更新。这学期(2012年2月到2012年8月)在专业学习上将突出几个集中研究的领域,在…

Ubuntu iso镜像文件写入U盘

Ubuntu iso镜像文件写入U盘 Ubuntu iso镜像文件写入U盘方法 分步指南 命令行输入 usb-creator-gtk如下:3、Device 选择插入的U盘 4、image 选择镜像文件 5、make startup disk

页面布局让footer居页面底部_网站各页面该如何布局关键词优化提升排名?

在网站优化中,最值得关注的一个事情就是关键词的布局,因为关键词的布局直接影响着网站的排名。那么怎样布局关键词才能提高页面和关键词的相关性,并提高网站排名呢?下面一起来看看。一、利用HTML标签布局关键词众所周知&#xff0…

Linux中如何配置IP

与网络相关的文件:1) /etc/sysconfig/network 设置主机名称及能否启动Network2) /etc/sysconfig/network-scripts/ifcfg-eth0设置网卡参数的文件3) /etc/modprobe.conf 开机时用来设置加载内核模块的文件4) /etc/resolv.conf 设置DNS IP(解析服务器&…

《DSP using MATLAB》Problem 5.7

代码&#xff1a; %% %% Output Info about this m-file fprintf(\n***********************************************************\n); fprintf( <DSP using MATLAB> Problem 5.7 \n\n);banner(); %% % -------------------------------------------…

一般将来时语法课教案_「英语语法」一般过去时用法技巧全解

大家好&#xff0c;我是教课蚪英语的张老师&#xff0c;今天我们来学习英语语法100讲的第一课&#xff0c;一般过去时&#xff01;一、首先我们了解一下什么是一般过去时&#xff1f;英语语法1. 概念&#xff1a;描述过去的状态或过去的动作。 在英语中&#xff0c;非现在的以前…

修改Ubuntu的启动logo

修改Ubuntu的启动logo 原文链接: https://my.oschina.net/jmjoy/blog/380262 内容: Plymouth splash screen is the initial splash screen at boot-up.Ubuntu 10.04 uses Plymouth instead of xsplash to manage the fancy boot graphics.If you want something different,y…

每周四十小时,你有多少是在为自己干活?

努力工作为什么&#xff1f;普通人不外乎希望加薪、升职&#xff0c;过的更好。 但是&#xff0c;要想达到这个目标&#xff0c;靠什么&#xff1f; 普通人当然要靠提升自己的能力和经验。 可是&#xff0c;你是不是已经发现&#xff0c;工作最踏实的&#xff0c;却未必取得最好…

在Linux下查看共享文件夹

一般情况&#xff0c;我们用到smbclient&#xff0c;常用方法所如下&#xff1a;#smbclient -L //IP地址或计算机名smbclient是samba的Linux客户端&#xff0c;在Linux机器上用来查看服务器上的共享资源&#xff0c;也可以向ftp一样&#xff0c;用户可以等里samba服务器&#x…

算法复杂度的定义

算法复杂度分为时间复杂度和空间复杂度。其作用&#xff1a; 时间复杂度是指执行算法所需要的计算工作量&#xff1b;而空间复杂度是指执行这个算法所需要的内存空间。&#xff08;算法的复杂性体现在运行该算法时的计算机所需资源的多少上&#xff0c;计算机资源最重要的是时间…

C#操作OFFICE一(EXCEL)

C#操作Excel! publicclassImportExportToExcel { private string strConn ; private System.Windows.Forms.OpenFileDialog openFileDlgnew System.Windows.Forms.OpenFileDialog(); private System.Windows.Forms.SaveFileDialog saveFileDlg…

c语言最小费用流_策略算法工程师之路-图优化算法(一)(二分图amp;最小费用最大流)...

目录1.图的基本定义2.双边匹配问题2.1 二分图基本概念2.2 二分图最大匹配求解2.3 二分图最优匹配求解2.4 二分图最优匹配建模实例2.4.1 二分图最优匹配在师生匹配中的应用2.4.2 二分图最优匹配在多对多拼车算法中的应用3.网络最大流3.1 网络流基本定义3.2 最大流的问题线性规划…

linux 查看库的安装信息

ldconfig -p | grep 库名(例如&#xff1a;lib***&#xff09; 比如&#xff1a; ldconfig -p | grep libcrypto

Asp.net无刷新调用后台实体类数据并以Json格式返回

新建一般处理程序public class Temp {public int Index { get; set; }public string Description { get; set; }public string ImagePath { get; set; }public DateTime MyDate { get; set; } }//数据源 List<Temp> listTemp new List<Temp>(){new Temp(){ Index1…

HDU 排名(简单题)

好久没在oj上做题了&#xff0c;刚开始第二天做一道简单题的心得记录。 1 #include <cstdio>2 #include <cstring>3 #include <string>4 #include <iostream>5 #include <algorithm>6 using namespace std;7 8 /*9 超级无语的错误&#xff0c;#d…

linux系统操作常见问题(ubuntu和opensuse)

在玩linux的过程中&#xff0c;会遇到各种看似奇怪的问题&#xff0c;这些问题往往让那些刚刚接触linux没多久的人不知所措&#xff0c;心中烦躁&#xff0c;这里把我曾经遇到对各种问题列出来&#xff0c;供喜欢linux对人参考&#xff1a; linux下以root身份成功运行chromium…

java iso8583 socket 服务_JAVA客户端amp;服务器的socket通信

JAVA客户端&服务器的socket通信socket是两台主机之间的一个连接通道&#xff0c;它可以完成七个基本操作&#xff1a;发送远程机器发送数据接收数据关闭连接绑定端口监听入站数据再绑定端口上接收来自远程机器的连接在客户端上使用socket程序用构造函数创建一个新的sockets…