JavaScript面试的完美指南(开发者视角)

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

摘要: 面试季手册。

  • 原文:javascript 面试的完美指南(开发者视角)
  • 作者:前端小智

Fundebug经授权转载,版权归原作者所有。

为了说明 JS 面试的复杂性,首先,请尝试给出以下结果:

onsole.log(2.0 == “2” == new Boolean(true) == “1”)

十有八九的会给出false, 其实运行结果是true,原因请看 这里。

1) 理解 JS 函数

函数是 JavaScript 的精华,是 JS 一等公民。JS 函数不仅仅是一个普通的函数,与其他语言不同,JS 函数可以赋值给变量,作为参数传递给另一个函数,也可以从另一个函数返回。

console.log(square(5));
/* ... */
function square(n) { return n * n; }

以为代码很简单,大家应该都知道会打印:25。接着看一个:

console.log(square(5));var square = function(n) { return n * n; 
}

乍一看,你可能会忍不住说也打印了 25。但很不幸,会报错:

TypeError: square is not a function

在 JavaScript 中,如果将函数定义为变量,变量名将被提升,是 JS 执行到它的定义才能被访问。

你可能在一些代码中频繁的见到如下代码。

var simpleLibrary = function() {var simpleLibrary = {a,b,add: function(a, b) {return a + b;},subtract: function(a, b) {return a - b;   }}return simpleLibrary;
}();

为什么会做这种奇怪的事情? 这是因为一个函数变量中变量和函数被分装,可以避免全局变量污染。 JQueryLodash 的库采用这种技术提供 $_

2) 理解 bind、apply 和 call

你可能在所有常用库中看到过这三个函数。它们允许局部套用, 我们可以把功能组合到不同的函数。一个优秀的js开发者可以随时告诉你关于这三个函数。

基本上,这些是改变行为以实现某些功能的原型方法,根据 JS 开发人员 Chad 的说法,用法如下:

希望使用某个上下文调用该函数,请使用 .bind() ,这在事件中很有用。 如果要立即调用函数,请使用.call().apply(),并修改上下文。

举例说明

让我们看看上面的陈述是什么意思! 假设你的数学老师要求你创建一个库并提交。你写了一个抽象的库,它可以求出圆的面积和周长:

var mathLib = {pi: 3.14,area: function(r) {return this.pi * r * r;},circumference: function(r) {return 2 * this.pi * r;}
};

提交后,老师调用了它:

mathLib.area(2);
12.56

老师发现他给你要求是 pi 精确到小数点后 5 位数而你只精确到 2 位, 现在由于最后期限已过你没有机会提交库。 这里 JS的 call 函数可以帮你, 只需要调用你的代码如下:

mathLib.area.call({pi: 3.1.159}, 2)

它会动态地获取新的 pi 值,结果如下:

12.56636

这时,注意到 call 函数具有两个参数:

  • Context
  • 函数参数

area 函数中, 上下文是对象被关键词 this 代替,后面的参数作为函数参数被传递。 如下:

var cylinder = {pi: 3.14,volume: function(r, h) {return this.pi * r * r * h;}
};

调用方式如下:

cylinder.volume.call({pi: 3.14159}, 2, 6);
75.39815999999999

Apply 类似,只是函数参数作为数组传递。

cylinder.volume.apply({pi: 3.14159}, [2, 6]);
75.39815999999999

如果你会使用 call 你基本就会用 apply 了,反之亦然, 那 bind 的用法又是如何呢 ?

bind 将一个全新的 this 注入到指定的函数上,改变 this 的指向, 使用 bind 时,函数不会像 callapply 立即执行。

var newVolume = cylinder.volume.bind({pi: 3.14159});
newVolume(2,6); // Now pi is 3.14159

bind 用途是什么?它允许我们将上下文注入一个函数,该函数返回一个具有更新上下文的新函数。这意味着这个变量将是用户提供的变量,这在处理 JavaScript 事件时非常有用。

3) 理解 js 作用域(闭包)

JavaScript 的作用域是一个潘多拉盒子。从这一个简单的概念中,就可以构造出数百个难回答的面试问题。有三种作用域:

  • 全局作用域
  • 本地/函数作用域
  • 块级作用域(ES6引进)

全局作用域事例如下:

x = 10;
function Foo() {console.log(x); // Prints 10
}
Foo()

函数作用域生效当你定义一个局部变量时:

pi = 3.14;
function circumference(radius) {    pi = 3.14159;console.log(2 * pi * radius); // 打印 "12.56636" 不是 "12.56"
}
circumference(2);

ES16 标准引入了新的块作用域,它将变量的作用域限制为给定的括号块。

var a = 10;function Foo() {if (true) {let a = 4;}alert(a); // alerts '10' because the 'let' keyword
}
Foo();

函数和条件都被视为块。以上例子应该弹出 4,因为 if 已执行。但 是ES6 销毁了块级变量的作用域,作用域进入全局。

现在来到神奇的作用域,可以使用闭包来实现,JavaScript 闭包是一个返回另一个函数的函数。

如果有人问你这个问题,编写一个输入一个字符串并逐次返回字符。 如果给出了新字符串,则应该替换旧字符串,类似简单的一个生成器。

function generator(input) {var index = 0;return {next: function() {if (index < input.lenght) {return input[index -1];}return "";}}
}

执行如下:

var mygenerator = generator("boomerang");
mygenerator.next(); // returns "b"
mygenerator.next() // returns "o"
mygenerator = generator("toon");
mygenerator.next(); // returns "t"

在这里,作用域扮演着重要的角色。闭包是返回另一个函数并携带数据的函数。上面的字符串生成器适用于闭包。index 在多个函数调用之间保留,定义的内部函数可以访问在父函数中定义的变量。这是一个不同的作用域。如果在第二级函数中再定义一个函数,它可以访问所有父级变量。

4) this (全局域、函数域、对象域)

在 JavaScript 中,我们总是用函数和对象编写代码, 如果使用浏览器,则在全局上下文中它引用 window 对象。 我的意思是,如果你现在打开浏览器控制台并输入以下代码,输出结果为 true

this === window;

当程序的上下文和作用域发生变化时,this 也会发生相应的变化。现在观察 this 在一个局部上下文中:

function Foo(){console.log(this.a);
}
var food = {a: "Magical this"};
Foo.call(food); // food is this

思考一下,以下输出的是什么:

function Foo(){console.log(this); // 打印 {}?
}

因为这是一个全局对象,记住,无论父作用域是什么,它都将由子作用域继承。打印出来是 window 对象。上面讨论的三个方法实际上用于设置这个对象。

现在,this 的最后一个类型,在对象中的 this, 如下:

var person = {name: "Stranger",age: 24,get identity() {return {who: this.name, howOld: this.age};}
}

上述使用了 getter 语法,这是一个可以作为变量调用的函数。

person.identity; // returns {who: "Stranger", howOld: 24}

此时,this 实际上是指对象本身。正如我们前面提到的,它在不同的地方有不同的表现。

5) 理解对象 (Object.freeze, Object.seal)

通常对象的格式如下:

var marks = {physics: 98, maths:95, chemistry: 91};

它是一个存储键、值对的映射。 javascript 对象有一个特殊的属性,可以将任何东西存储为一个值。这意味着我们可以将一个列表、另一个对象、一个函数等存储为一个值。

可以用如下方式来创建对象:

var marks = {};
var marks = new Object();

可以使用 JSON.stringify() 将一个对象转制成字符串,也可以用 JSON.parse 在将其转成对象。

// returns "{"physics":98,"maths":95,"chemistry":91}"
JSON.stringify(marks);
// Get object from string
JSON.parse('{"physics":98,"maths":95,"chemistry":91}');

使用 Object.keys 迭代对象:

var highScere = 0;for (i of Object.keys(marks)) {if (marks[i] > highScore)highScore = marks[i];
}

Object.values 以数组的方式返回对象的值。

对象上的其他重要函数有:

  • Object.prototype(object)
  • Object.freeze(function)
  • Object.seal(function)

Object.prototype 上提供了许多应用上相关的函数,如下:

Object.prototype.hasOwnProperty 用于检查给定的属性/键是否存在于对象中。

marks.hasOwnProperty("physics"); // returns true
marks.hasOwnProperty("greek"); // returns false

Object.prototype.instanceof 判断给定对象是否是特定原型的类型。

function Car(make, model, year) {this.make = make;this.model = model;this.year = year;
}
var newCar = new Car('Honda', 'City', 2007);
console.log(newCar instanceof Car); // returns true

使用 Object.freeze 可以冻结对象,以便不能修改对象现有属性。

var marks = {physics: 98, maths:95, chemistry: 91};
finalizedMarks = Object.freeze(marks);
finalizedMarks["physics"] = 86; // throws error in strict mode
console.log(marks); // {physics: 98, maths: 95, chemistry: 91}

在这里,试图修改冻结后的 physics 的值,但 JavaScript不允许这样做。我们可以使用 Object.isFrozen 来判断,给定对象是否被冻结:

Object.isFrozen(finalizedMarks); // returns true

Object.sealObject.freeze 略有不同。 Object.seal() 方法封闭一个对象,阻止添加新属性并将所有现有属性标记为不可配置。当前属性的值只要可写就可以改变。

var marks = {physics: 98, maths:95, chemistry: 91};
Object.seal(marks);
delete marks.chemistry; // returns false as operation failed
marks.physics = 95; // Works!
marks.greek = 86; // Will not add a new property

同样, 可以使用 Object.isSealed 判断对象是否被密封。

Object.isSealed(marks); // returns true

在全局对象函数上还有许多其他重要的函数/方法,在这里找到他们。

代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug。

6) 理解原型继承

在传统 JavaScript 中,有一种伪装的继承概念,它是通过使用原型技术来实现的。在ES5、ES6中看到使用 new 的语法只是底层原型OOP的语法糖。创建类是使用 JavaScript 中的函数完成的。

var animalGroups = {MAMMAL: 1,REPTILE: 2,AMPHIBIAN: 3,INVERTEBRATE: 4
};
function Animal(name, type) {this.name = name;this.type = type;
}
var dog = new Animal("dog", animalGroups.MAMMAL);
var crocodile = new Animal("crocodile", animalGroups.REPTILE);

这里我们为类创建对象(使用 new 关键字),可以使用如下方式对类追加方法:

Animal.prototype.shout = function() {console.log(this.name+'is'+this.sound+'ing...');
}

这里你可能会有疑问。类中并没 sound 属性。是的,它打算由继承了上述类的子类传递。

JavaScript中, 如下实现继承:

function Dog(name, type) {
Animal.call(this, name, type);
this.sound = 'bow';
}

我定义了一个更具体的函数,叫做 Dog。在这里,为了继承 Animal 类,我需要call传递this和其他参数。使用如下方式来实例化一只德国牧羊犬

var pet = Dog("德国牧羊犬", animalGroups.MAMMAL);
console.log(pet); // returns Dog {name: "德国牧羊犬", type: 1, sound: "bow"}

我们没有在子函数中分配 nametype 属性,我们调用的是超级函数 Animal 并设置相应的属性。pet 具有父类的属性(name、type)。但是方法呢。他们也继承的吗? 来看看:

pet.shout(); // Throws error

为什么会这样? 之所以发生这种情况,是因为没有指定让 JavaScript来继承父类方法。 如何解决?

// Link prototype chains
Dog.prototype = Object.create(Animal.prototype);
var pet = new Dog("germanShepard", animalGroups.MAMMAL);
// Now shout method is available
pet.shout(); // 德国牧羊犬 bowing...

现在可以使用 shout 方法。 我们可以使用 object.constructor 函数检查 JavaScript 中给定对象的类 来看看 pet 是什么类:

pet.constructor; // returns Animal

这是模糊的,Animal 是一个父类。但是 pet 到底是什么类型的呢? pet 应该是 Dog 的类型。之所以是 Animal 类型,是因为 Dog 类的构造函数:

Dog.prototype.constructor; // returns Animal

它是 Animal 类型的。我们应该将它设置为 Dog 本身,这样类的所有实例(对象)才能给出正确的类名。

Dog.prototype.constructor = Dog;

关于原型继承, 我们应该记住以下几条:

  • 类属性使用 this 绑定
  • 类方法使用 prototype 对象来绑定
  • 为了继承属性, 使用 call 函数来传递 this
  • 为了继承方法, 使用 Object.create 连接父和子的原型
  • 始终将子类构造函数设置为自身,以获得其对象的正确类型

7)理解 callback 和 promise

回调是在 I/O 操作完成后执行的函数。一个耗时的I/O操作会阻塞代码, 因此在Python/Ruby不被允许。但是在 JavaScript中,由于允许异步执行,我们可以提供对异步函数的回调。这个例子是由浏览器到服务器的AJAX(XMLHettpRequest)调用,由鼠标、键盘事件生成。如下:

function reqListener () {console.log(this.responseText);
}var req = new XMLHttpRequest();
req.addEventListener("load", reqListener);
req.open("GET", "http://www.example.org/example.txt");
req.send();

这里的 reqListener 是一个回调函数,当成功响应 GET 请求时将执行该回调函数。

Promise 是回调函数的优雅的封装, 使得我们优雅的实现异步代码。在以下给出的这篇文章中讨论了很多 promise,这也是在 JS 中应该知道的重要部分。

Writing neat asynchronous Node JS code with Promises

8)理解正则表达

正则表达式有许多应用地方,处理文本、对用户输入执行规则等。JavaScript 开发人员应该知道如何执行基本正则表达式并解决问题。Regex 是一个通用概念,来看看如何从 JS 中做到这一点。

创建正则表达式,有如下两种方式:

var re = /ar/;
var re = new RegExp('ar'); 

上面的正则表达式是与给定字符串集匹配的表达式。定义正则表达式之后,我们可以尝试匹配并查看匹配的字符串。可以使用 exec 函数匹配字符串:

re.exec("car"); // returns ["ar", index: 1, input: "car"]
re.exec("cab"); // returns null

有一些特殊的字符类允许我们编写复杂的正则表达式。RegEx 中有许多类型的元素,其中一些如下:

  • 字符正则:\w-字母数字, \d- 数字, \D- 没有数字
  • 字符类正则:[x-y] x-y区间, [^x] 没有x
  • 数量正则:+ 至少一个、? 没或多个、* 多个
  • 边界正则,^ 开始、$ 结尾

例子如下:

/* Character class */var re1 = /[AEIOU]/;
re1.exec("Oval"); // returns ["O", index: 0, input: "Oval"]
re1.exec("2456"); // null
var re2 = /[1-9]/;
re2.exec('mp4'); // returns ["4", index: 2, input: "mp4"]/* Characters */var re4 = /\d\D\w/;
re4.exec('1232W2sdf'); // returns ["2W2", index: 3, input: "1232W2sdf"]
re4.exec('W3q'); // returns null/* Boundaries */var re5 = /^\d\D\w/;
re5.exec('2W34'); // returns ["2W3", index: 0, input: "2W34"]
re5.exec('W34567'); // returns null
var re6 = /^[0-9]{5}-[0-9]{5}-[0-9]{5}$/;
re6.exec('23451-45242-99078'); // returns ["23451-45242-99078", index: 0, input: "23451-45242-99078"]
re6.exec('23451-abcd-efgh-ijkl'); // returns null/* Quantifiers */var re7 = /\d+\D+$/;
re7.exec('2abcd'); // returns ["2abcd", index: 0, input: "2abcd"]
re7.exec('23'); // returns null
re7.exec('2abcd3'); // returns null
var re8 = /<([\w]+).*>(.*?)<\/\1>/;
re8.exec('<p>Hello JS developer</p>'); //returns  ["<p>Hello JS developer</p>", "p", "Hello JS developer", index: 0, input: "<p>Hello JS developer</p>"]

有关 regex 的详细信息,可以看 这里。

除了 exec 之外,还有其他函数,即 matchsearchreplace,可以使用正则表达式在另一个字符串中查找字符串,但是这些函数在字符串本身上使用。

"2345-678r9".match(/[a-z A-Z]/); // returns ["r", index: 8, input: "2345-678r9"]
"2345-678r9".replace(/[a-z A-Z]/, ""); // returns 2345-6789

Regex 是一个重要的主题,开发人员应该理解它,以便轻松解决复杂的问题。

9)理解 map、reduce 和 filter

函数式编程是当今的一个热门讨论话题。许多编程语言都在新版本中包含了函数概念,比如 lambdas(例如:Java >7)。在 JavaScrip t中,函数式编程结构的支持已经存在很长时间了。我们需要深入学习三个主要函数。数学函数接受一些输入和返回输出。纯函数都是给定的输入返回相同的输出。我们现在讨论的函数也满足纯度。

map

map 函数在 JavaScript 数组中可用,使用这个函数,我们可以通过对数组中的每个元素应用一个转换函数来获得一个新的数组。map 一般语法是:

arr.map((elem){process(elem)return processedValue
}) // returns new array with each element processed

假设,在我们最近使用的串行密钥中输入了一些不需要的字符,需要移除它们。此时可以使用 map 来执行相同的操作并获取结果数组,而不是通过迭代和查找来删除字符。

var data = ["2345-34r", "2e345-211", "543-67i4", "346-598"];
var re = /[a-z A-Z]/;
var cleanedData = data.map((elem) => {return elem.replace(re, "")});
console.log(cleanedData); // ["2345-34", "2345-211", "543-674", "346-598"]

map 接受一个作为参数的函数, 此函数接受一个来自数组的参数。我们需要返回一个处理过的元素, 并应用于数组中的所有元素。

reduce

reduce 函数将一个给定的列表整理成一个最终的结果。通过迭代数组执行相同的操作, 并保存中间结果到一个变量中。这里是一个更简洁的方式进行处理。js 的 reduce 一般使用语法如下:

arr.reduce((accumulator,currentValue,currentIndex) => {process(accumulator, currentValue)return intermediateValue/finalValue
}, initialAccumulatorValue) // returns reduced value

accumulator 存储中间值和最终值。currentIndexcurrentValue分别是数组中元素的 index 和 value。initialAccumulatorValueaccumulator 初始值。

reduce 的一个实际应用是将一个数组扁平化, 将内部数组转化为单个数组, 如下:

var arr = [[1, 2], [3, 4], [5, 6]];
var flattenedArray = [1, 2, 3, 4, 5, 6];

我们可以通过正常的迭代来实现这一点,但是使用 reduce,代码会更加简洁。

var flattenedArray = arr.reduce((accumulator, currentValue) => {return accumulator.concat(currentValue);
}, []); // returns [1, 2, 3, 4, 5, 6]

filter

filtermap 更为接近, 对数组的每个元素进行操作并返回另外一个数组(不同于 reduce 返回的值)。过滤后的数组可能比原数组长度更短,因为通过过滤条件,排除了一些我们不需要的。

filter 语法如下:

arr.filter((elem) => {return true/false
})

elem 是数组中的元素, 通过 true/false 表示过滤元素保存/排除。假设, 我们过滤出以 t 开始以 r 结束的元素:

var words = ["tiger", "toast", "boat", "tumor", "track", "bridge"]
var newData = words.filter((str) => {return str.startsWith('t') && str.endsWith('r');
})
newData // (2) ["tiger", "tumor"]

当有人问起JavaScript的函数编程方面时,这三个函数应该信手拈来。 如你所见,原始数组在所有三种情况下都没有改变,这证明了这些函数的纯度。

10) 理解错误处理模式

这是许多开发人员最不关心的 JavaScript。 我看到很少有开发人员谈论错误处理, 一个好的开发方法总是谨慎地将 JS 代码封装装在 try/catch 块周围。

在 JavaScript中,只要我们随意编写代码,就可能会失败,如果所示:

$("button").click(function(){$.ajax({url: "user.json", success: function(result){updateUI(result["posts"]);}});
});

这里,我们陷入了一个陷阱,我们说 result 总是 JSON 对象。但有时服务器会崩溃,返回的是 null 而不是 result。在这种情况下,null["posts"] 将抛出一个错误。正确的处理方式可能是这样的:

$("button").click(function(){$.ajax({url: "user.json", success: function(result){try {     updateUI(result["posts"]);}catch(e) {// Custom functionslogError();flashInfoMessage();      }}});
});

logError 函数用于向服务器报告错误。flashInfoMessage 是显示用户友好的消息,如“当前不可用的服务”等。

Nicholas 说,当你觉得有什么意想不到的事情将要发生时,手动抛出错误。区分致命错误和非致命错误。以上错误与后端服务器宕机有关,这是致命的。在那里,应该通知客户由于某种原因服务中断了。

在某些情况下,这可能不是致命的,但最好通知服务器。为了创建这样的代码,首先抛出一个错误,, 从 window 层级捕捉错误事件,然后调用API将该消息记录到服务器。

reportErrorToServer = function (error) {$.ajax({type: "POST", url: "http://api.xyz.com/report",data: error,success: function (result) {}});
}
// Window error event
window.addEventListener('error', function (e) {reportErrorToServer({message: e.message})
})}
function mainLogic() {// Somewhere you feel like fishythrow new Error("user feeds are having fewer fields than expected...");
}

这段代码主要做三件事:

  • 监听window层级错误
  • 无论何时发生错误,都要调用 API
  • 在服务器中记录

你也可以使用新的 Boolean 函数(es5,es6)在程序之前监测变量的有效性并且不为null、undefined

if (Boolean(someVariable)) {
// use variable now
} else {throw new Error("Custom message")
}

始终考虑错误处理是你自己, 而不是浏览器。

其他(提升机制和事件冒泡)

以上所有概念都是 JavaScript 开发人员的需要知道基本概念。有一些内部细节需要知道,这些对你会有很在帮助。 这些是JavaScript引擎在浏览器中的工作方式,什么是提升机制和事件冒泡?

提升机制

变量提升是 在代码执行过程中将声明的变量的作用域提升到全局作用哉中的一个过程,如:

doSomething(foo); // used before
var foo; // declared later

当在 Python 这样的脚本语言中执行上述操作时,它会抛出一个错误,因为需要先定义然后才能使用它。尽管 JS 是一种脚本语言,但它有一种提升机制,在这种机制中,JavaScript VM 在运行程序时做两件事:

  • 首先扫描程序,收集所有的变量和函数声明,并为其分配内存空间
  • 通过填充分配的变量来执行程序, 没有分配则填充 undefined

在上面的代码片段中,console.log 打印 “undefined”。 这是因为在第一次传递变量 foo 被收集。 JS 虚拟机 查找为变量 foo 定义的任何值。 这种提升可能导致许多JavaScript 在某些地方抛出错误,和另外地方使用 undefined

学习一些 例子 来搞清楚提升。

事件冒泡

现在事件开始冒泡了! 根据高级软件工程师 Arun P的说法:

“当事件发生在另一个元素内的元素中时,事件冒泡和捕获是 HTML DOM API 中事件传播的两种方式,并且这两个元素都已为该事件注册了处理程序,事件传播模式确定元素接收事件的顺序。“

通过冒泡,事件首先由最内部的元素捕获和处理,然后传播到外部元素。对于捕获,过程是相反的。我们通常使用addEventListener 函数将事件附加到处理程序。

addEventListener("click", handler, useCapture=false)

useCapture 是第三个参数的关键词, 默认为 false。因此, 冒泡模式是事件由底部向上传递。 反之, 这是捕获模式。

冒泡模式:

<div onClick="divHandler()"><ul onClick="ulHandler"><li id="foo"></li></ul>
</div>
<script>
function handler() {// do something here
}
function divHandler(){}
function ulHandler(){}
document.getElementById("foo").addEventListener("click", handler)
</script>

点击li元素, 事件顺序:

handler() => ulHandler() => divHandler()

在图中,处理程序按顺序向外触发。类似地,捕获模型试图将事件从父元素向内触发到单击的元素。现在更改上面代码中的这一行。

document.getElementById("foo").addEventListener("click", handler, true)

事件顺序:

divHandler => ulHandler() => handler()

你应该正确地理解事件冒泡(无论方向是指向父节点还是子节点),以实现用户界面(UI),以避免任何不需要的行为。

这些是 JavaScript中的基本概念。正如我最初提到的,除了工作经验和知识之外,准备有助理于你通过 JavaScript 面试。始终保持学习。留意最新的发展(第六章)。深入了解JavaScript的各个方面,如 V6 引擎、测试等。最后,没有掌握数据结构和算法的面试是不成功的。Oleksii Trekhleb 策划了一个很棒的 git repo,它包含了所有使用 JS 代码的面试准备算法。

关于Fundebug

Fundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java线上应用实时BUG监控。自从2016年双十一正式上线,Fundebug累计处理了10亿+错误事件,付费客户有Google、360、金山软件、百姓网等众多品牌企业。欢迎大家免费试用!

转载于:https://my.oschina.net/u/3375885/blog/3012864

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

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

相关文章

windows qt 不能debug_linux配置vlc-qt

vlc-qt 是基于vlc库&#xff0c;用于开发音频视频应用&#xff0c;性能优秀。vlc-qt/vlc-qt​github.com使用vlc-qt首先需要编译vlc-qt &#xff08;windows可以下载使用编译好的&#xff0c;但是只能用在release模式&#xff09;&#xff08;在windows系统中&#xff09;使用w…

idou老师教你学Istio 27:解读Mixer Report流程

1、概述 Mixer是Istio的核心组件&#xff0c;提供了遥测数据收集的功能&#xff0c;能够实时采集服务的请求状态等信息&#xff0c;以达到监控服务状态目的。 1.1 核心功能 •前置检查&#xff08;Check&#xff09;&#xff1a;某服务接收并响应外部请求前&#xff0c;先通过E…

mysql删除密码代码_mysql 用户新建、受权、删除、密码修改

mysql 用户新建、授权、删除、密码修改首先要声明一下&#xff1a;一般情况下&#xff0c;修改MySQL密码&#xff0c;授权&#xff0c;是需要有mysql里的root权限的。注&#xff1a;本操作是在WIN命令提示符下&#xff0c;phpMyAdmin同样适用。用户&#xff1a;phplamp 用户数…

KindEditor 上传漏洞致近百个党政机关网站遭植入

开发四年只会写业务代码&#xff0c;分布式高并发都不会还做程序员&#xff1f; >>> 2月21日消息&#xff0c;近日&#xff0c;安恒明鉴网站安全监测平台和应急响应中心监测发现近百起党政机关网站被植入色情广告页面&#xff0c;分析发现被植入色情广告页面的网站都…

Insql 1.8.2 发布,轻量级 .NET ORM 类库

开发四年只会写业务代码&#xff0c;分布式高并发都不会还做程序员&#xff1f; >>> Insql 是一个轻量级的.NET ORM 类库。对象映射基于 Dapper, Sql 配置灵感来自于 Mybatis。 TA 的追求&#xff1a;简洁、优雅、性能与质量 TA 的宗旨&#xff1a;让你用起来感觉到…

教程 | 如何利用C++搭建个人专属的TensorFlow

在开始之前&#xff0c;首先看一下最终成型的代码&#xff1a; 分支与特征后端&#xff08;https://github.com/OneRaynyDay/autodiff/tree/eigen&#xff09;仅支持标量的分支&#xff08;https://github.com/OneRaynyDay/autodiff/tree/master&#xff09;这个项目是我与 Min…

docker kali安装mysql_kali安装docker(有效详细的教程) ——vulhub漏洞复现 001

前记&#xff1a;博主有着多次安装docker的丰富经验&#xff0c;曾经为了在kali成功安装docker花费不少时间。在kali2016.3一直到最新的kali2019.4都通吃&#xff01;所以跟着下面的步骤走&#xff0c;绝对不会出错。(该机子此前没装过docker&#xff0c;并且配置好了kali更新源…

PDF文件如何转成markdown格式

百度上根据pdf转makrdown为关键字进行搜索&#xff0c;结果大多数是反过来的转换&#xff0c;即markdown文本转PDF格式。 但是PDF转markdown的解决方案很少。 正好我工作上有这个需求&#xff0c;所以自己实现了一个解决方案。 下图是一个用PDF XChange Editor打开的PDF文件&am…

kangle支不支持PHP_【转载】PHP调用kangle的API

摘要&#xff1a;根据管理的API公布写了一个类封装了一个操作集合&#xff0c;这是一个kangleAPI的一个封...根据管理的API公布写了一个类封装了一个操作集合&#xff0c;这是一个kangleAPI的一个封装吧&#xff0c;是在其他地方看到的&#xff0c;接口包含获取easypanel的信息…

mysql数据库容量和性能_新品速递丨容量盘性能提升超 300%,数据库支持 MySQL 8.0...

2关系型数据库 MySQL Plus支持 MySQL 8.0 内核及 XtraBackup 物理在线迁移方式关系型数据库服务 MySQL Plus 发布新版本 1.0.6 &#xff0c; 新增多项功能&#xff0c;提升了集群自动化运维能力。主要升级有&#xff1a;- 支持 MySQL 8.0 内核&#xff1a;根据官方测试&#xf…

tiger4444/rabbit4444后缀勒索病毒怎么删除 能否百分百恢复

上海某客户中了tiger4444的勒索病毒&#xff0c;找到我们后&#xff0c;一天内全部恢复完成。说了很多关于勒索病毒的事情&#xff0c;也提醒过大家&#xff0c;可总是有人疏忽&#xff0c;致使中招后&#xff0c;丢钱丢面子&#xff0c;还丢工作。 那么要怎样预防呢与处理呢&a…

GPT-5、开源、更强的ChatGPT!

年终岁尾&#xff0c;正值圣诞节热闹气氛的OpenAI写下了2024年的发展清单。 OpenAI联合创始人兼首席执行官Sam Altman在社交平台公布&#xff0c;AGI&#xff08;稍晚一些&#xff09;、GPT-5、更好的语音模型、更高的费率限制&#xff1b; 更好的GPTs&#xff1b;更好的推理…

CentOS_7 安装MySql5.7

2019独角兽企业重金招聘Python工程师标准>>> 下载mysql的源 wget http://dev.mysql.com/get/mysql57-community-release-el7-7.noarch.rpm 安装yum库 yum localinstall -y mysql57-community-release-el7-7.noarch.rpm 安装MySQL yum install -y mysql-community-…

性能测试总结(一)---基础理论篇(转载)

随着软件行业的快速发展&#xff0c;现代的软件系统越来越复杂&#xff0c;功能越来越多&#xff0c;测试人员除了需要保证基本的功能测试质量&#xff0c;性能也随越来越受到人们的关注。但是一提到性能测试&#xff0c;很多人就直接连想到Loadrunner。认为LR就等于性能测试&a…

java listen_JavaWeb之Filter、Listener

昨天和大家介绍了一下JSON的用法&#xff0c;其实JSON中主要是用来和数据库交互数据的。今天给大家讲解的是Filter和Listener的用法。一、Listenner监听器1.1、定义Javaweb中的监听器是用于监听web常见对象HttpServletRequest,HttpSession,ServletContext。1.2、监听器的作用监…

java jasypt_Jasypt

软件简介Jasypt这个Java类包为开发人员提供一种简单的方式来为项目增加加密功能&#xff0c;包括&#xff1a;密码Digest认证&#xff0c;文本和对象加密&#xff0c;集成hibernate&#xff0c;SpringSecurity(Acegi)来增强密码管理。Jasypt开发团队推出了Java加密工具Jasypt 1…

ZABBIX监控JAVA日志文件

最近开发人员有一个需求&#xff0c;监控java程序的报错日志&#xff0c;如日志中包含“ERROR”关键字的信息&#xff0c;就邮件告警&#xff0c;以下是具体实现方法。 一、创建模板以上是已经创建好的模板&#xff0c;名为“Template App Java logs”创建应用集二、创建监控项…

如何快速把音乐转成MP3格式

身边有这样一群朋友经常搞音乐&#xff0c;仿佛生活的乐趣只有音乐&#xff0c;不能也能理解&#xff0c;谁没有点自己的爱好呢&#xff1f;但是如果想要在茫茫人海中成为佼佼者&#xff0c;并不是这么容易的&#xff0c;但是我们要在速度上赢更多的人&#xff0c;所以写了这篇…

JavaWeb学习笔记(九)--HttpServletResponse

web服务器接收到客户端的HTTP请求&#xff0c;会针对每一次请求&#xff0c;分别创建一个用于代表请求的request对象和代表响应的response对象。 request和response对象既然代表请求和响应&#xff0c;那我们要获取客户端提交过来的数据&#xff0c;只需要找request对象即可。要…

centos 6.5 yum java_Centos6.5 yum 安装jdk1.8

centos 6.5 安装卸载jdk-- 查看有没有预装jdk版本java -version-- 查看已安装的版本rpm -qa|grep java-- 卸载预装版本 rpm -e --nodeps 命令卸载rpm -e --nodeps java-1.7.0-openjdk-1.7.0.45-2.4.3.3.el6.x86_64-- 查找可以安装的jdk列表yum search java | grep -i --color J…