『读书笔记』你不知道的JavaScript(上)
前言
文章只记录理解以及容易遗忘的知识点。
词法作用域、块作用域
词法作用域
词法作用域:简单的说,词法作用域就是定义在词法阶段的作用域。换句话说,词法作用域就是在你写代码时将变量和块作用域写在哪里来决定的,因此在词法分析器处理代码时会保持作用域不变(大部分情况是这样的)。
当然有一些欺骗词法作用域的方法,这些方法在词法分析器处理后依然可以改变作用域。
欺骗词法作用域的方法有:
- eval():可以接受一个字符串作为参数。
- with:通常被当作重复引用同一个对象中的多个属性的快捷方式,可以不需要重复引用对象本身。
var obj = {
a:1,
b:2,
c:3
}; //单调乏味的重复"obj"
obj.a=2;
obj.b=3;
obj.c=4; //简单的快捷方式
with(obj){
a=2;
b=3;
c=4;
}
块作用域
- with
- try/catch
- let
- const
简单解释下箭头函数:简单来说,箭头函数在涉及this绑定时的行为和普通函数的行为完全不一致。它放弃了所有普通this绑定规则,取而代之的是用当前的词法作用域覆盖了this本来的值。
作用域闭包
现代的模块机制
大多数模块依赖加载器/管理器本质上都是将这种模块定义封装进一个友好的API。这里并不会研究某个具体的库,为了宏观了解简单介绍一些核心概念:
var MyModules = (function Manager(){
var modules = {};
function define(name,deps,impl){
for(var i = 0; i < deps.length; i++){
deps[i] = modules[deps[i]];
}
modules[name] = impl.apply(impl,deps);
} function get(name){
return modules[name];
}
return {
define:define,
get:get
}
})();
这段代码的核心是modules[name] = impl.apply(impl,deps)。为了模块的定义引入了包装函数(可以传入任何依赖),并且将返回值,也就是模块的API,存储在一个根据名字来管理的模块列表中。
下面用它来如何定义模块:
MyModules.define("bar",[],function(){
function hello(who){
return "Let me introduce:" + who;
}
return {
hello:hello
}
}); MyModules.define("foo",['bar'],function(bar){
var hungry = "hippo";
function awesome(){
console.log(bar.hello(hungry).toUpperCase());
}
return {
awesome:awesome
}
}); var bar = MyModules.get("bar");
var foo = MyModules.get("foo"); console.log(bar.hello("hippo")); //Let me introduce:hippo
foo.awesome(); //LET ME INTRODUCE:HIPPO
“foo”和“bar”模块都是通过一个返回公共API的函数来定义的。“foo”甚至接受“bar”的示例作为依赖参数,并能相应地使用它。
未来的模块机制
bar.js
function hello(who){
return "Let me introduce:" + who;
}
export hello; foo.js
//仅从"bar"模块导入hello()
import hello from "bar";
var hungry = "hippo";
function awesome(){
console.log(hello(hungry).toUpperCase());
}
export awesome; baz.js
//导入完整的"foo"和"bar"模块
module foo from "foo";
module bar from "bar";
console.log(bar.hello("hippo")); //Let me introduce:hippo
foo.awesome(); //LET ME INTRODUCE:HIPPO
import可以将一个模块中的一个或多个API导入到当前作用域中,并分别绑定在一个变量上(在我们的例子里是hello)。module会将整个模块的API导入并绑定到一个变量上(在我们的例子里是foo和bar).export会将当前模块的一个标识符(变量、函数)导出为公共API。这些操作可以在模块定义中根据需要使用任意多次。
动态作用域
function foo(){
console.log(a); //2
}
function bar(){
var a = 3;
foo();
}
var a = 2;
bar();
如果JS具有动态作用域,那么打印的值就是3,而不是2了。需要明确的是,事实上JS并不具有动态作用域。它只有词法作用域,简单明了。但是this机制某种程度上很像动态作用域。
主要区别:词法作用域是在写代码或者说定义时确定的,而动态作用域是在运行时确定的。(this也是!)词法作用域关注函数在何处声明,而动态作用域关注函数从何处调用。最后,this关注函数如何调用,这就表明了this机制和动态作用域之间的关系那么紧密。
this解析
JS有许多的内置函数,都提供了一个可选的参数,通常被成为“上下文”(context),其作用和bind(...)一样,确保你的回调函数使用指定的this。如下例子:
function foo(el){
console.log(el,this.id);
} var obj = {
id:"awesome"
}; //调用foo(...)时把this绑定到obj
[1,2,3].forEach(foo,obj); //结果:1 "awesome" 2 "awesome" 3 "awesome"
bind()
bind()方法创建一个新的函数,在调用时设置this关键字为提供的值。并在调用新函数时,将给定参数列表作为原函数的参数序列的前若干项。
语法:function.bind(thisArg[, arg1[, arg2[, ...]]])
简单例子:
var module = {
x: 42,
getX: function() {
return this.x;
}
} var unboundGetX = module.getX;
console.log(unboundGetX()); // The function gets invoked at the global scope
// expected output: undefined var boundGetX = unboundGetX.bind(module);
console.log(boundGetX());
// expected output: 42
你可以将下面这段代码插入到你的脚本开头,从而使你的 bind() 在没有内置实现支持的环境中也可以部分地使用bind。
if (!Function.prototype.bind) {
Function.prototype.bind = function(oThis) {
if (typeof this !== 'function') {
// closest thing possible to the ECMAScript 5
// internal IsCallable function
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
} var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function() {},
fBound = function() {
// this instanceof fBound === true时,说明返回的fBound被当做new的构造函数调用
return fToBind.apply(this instanceof fBound
? this
: oThis,
// 获取调用时(fBound)的传参.bind 返回的函数入参往往是这么传递的
aArgs.concat(Array.prototype.slice.call(arguments)));
}; // 维护原型关系
if (this.prototype) {
// Function.prototype doesn't have a prototype property
fNOP.prototype = this.prototype;
}
// 下行的代码使fBound.prototype是fNOP的实例,因此
// 返回的fBound若作为new的构造函数,new生成的新对象作为this传入fBound,新对象的__proto__就是fNOP的实例
fBound.prototype = new fNOP(); return fBound;
};
}
详细参考地址:《MDN:Function.prototype.bind()》
对象
对象键只能是字符串
在 symbol 出现之前,对象键只能是字符串,如果试图使用非字符串值作为对象的键,那么该值将被强制转换为字符串,如下:
const obj = {};
obj.foo = 'foo';
obj['bar'] = 'bar';
obj[2] = 2;
obj[{}] = 'someobj';
console.log(obj);
结果:
2:2
[object Object]:"someobj"
bar:"bar"
foo:"foo"
属性描述符
从ES5开始,所有的属性都具备了属性描述符。
思考如下代码,使用Object.getOwnPropertyDescriptor():
var myObject = {
a:2
};
var result = Object.getOwnPropertyDescriptor(myObject,"a");
console.log(result);
得到的结果如下:
{
configurable:true,
enumerable:true,
value:2,
writable:true
}
这个普通的对象属性对应的属性描述符除了有value值为2,还有另外三个特性:writable(可写)、enumerable(可枚举)和configurable(可配置)。
使用Object.defineProperty()来添加一个新属性或者修改一个已有属性(如果它是configurable)并对特性进行设置。
writable
如下代码:
var myObject = {}
Object.defineProperty(myObject,"a",{
value:2,
writable:false, //不可写
configurable:true,
enumerable:true
});
myObject.a = 3;
console.log(myObject.a); //2
如果在严格模式下,上面这写法报错:
"use strict";
var myObject = {}
Object.defineProperty(myObject,"a",{
value:2,
writable:false, //不可写
configurable:true,
enumerable:true
});
myObject.a = 3; //Uncaught TypeError: Cannot assign to read only property 'a' of object '#<Object>'
configurable
var myObject = {}
Object.defineProperty(myObject,"a",{
value:2,
writable:true,
configurable:false, //不可配置
enumerable:true
});
myObject.a = 5;
console.log(myObject.a); //5
delete myObject.a;
console.log(myObject.a); //configurable:false,禁止删除这个属性 Object.defineProperty(myObject,"a",{
value:6,
writable:true,
configurable:true,
enumerable:true
}); //TypeError: Cannot redefine property: a
上面代码可以看出,设置configurable为false是单向操作,无法撤销。同时还会禁止删除这个属性。
注意:要注意一个小小的例外,即使属性configurable:false,我们还是可以把writable的状态有true改为false,但是无法由false改为true。
enumerable
从名字可以看出来,这个描述符控制的是属性是否出现在对象的属性枚举中,比如for...in循环。
不变性
有时候我们希望属性或者对象是不可改变的。ES5中有很多方法可以实现。
对象常量
结合writable:false和configurable:false就可以真正的创建一个常量属性(不可修改、重定义或者删除)。
var myObject = {}
Object.defineProperty(myObject,"a",{
value:2,
writable:false,
configurable:false
});
禁止扩展Object.preventExtensions()
如果你想禁止一个对象添加新的属性并且保留已有属性,可以使用Object.preventExtensions():
var myObject = {
a:2
};
Object.preventExtensions(myObject);
myObject.b = 3;
console.log(myObject.b); //undefined
在严格模式下,将会抛出TypeError错误。
密封Object.seal()
Object.seal()会创建一个“密封”的对象,这个方法实际上会在现有对象上调用Object.preventExtensions()并把所有现有属性标记为configurable:false。
所以,密封之后不仅不能添加新的属性,也不能重新配置或者删除任何属性(虽然可以修改属性的值)。
冻结Object.freeze()
Object.freeze()会创建一个冻结对象,这个方法实际上会在一个现有对象上调用Object.seal()并把所有“数据访问”属性标记为writable:false,这样就无法修改它们的值。
这个方法是你可以应用在对象上的级别最高的不可变性,它会禁止对于对象本身及其任意直接属性的修改(这个对象引用的其它对象是不受影响的)。
你可以“深度冻结”一个对象,具体方法为,首先在这个对象上调用Object.freeze(),然后遍历它所有引用的所有对象并在这些对象上调用Object.freeze()。但你一定要小心,因为这样做,你可能会在无意中冻结其它(共享)对象。
Getter和Setter
对象默认的[[Put]]和[[Get]]操作分别可以控制属性值的设置和获取。
当你给一个属性定义getter、setter或者两者都有时,这个属性会被定义为“访问描述符”(和“数据描述符”相对的)。对于访问描述符来说,JS会忽略它们的value和writable特性,取而代之的是关心set和get(还有configurable和enumerable)特性。
思考如下代码:
var myObject = {
get a(){
return 2;
}
}; Object.defineProperty(myObject,"b",{
get:function(){
return this.a * 2;
},
enmuerable:true
})
console.log(myObject.a); //2
console.log(myObject.b); //4
为了让属性更合理,还应该定义setter,setter会覆盖单个属性默认的[[Put]](也被称为赋值)操作。通常来说getter和setter是成对出现的。
var myObject = {
get a(){
return this._a_;
},
set a(val){
this._a_ = val * 2;
}
};
myObject.a = 2;
console.log(myObject.a); //4
遍历
for...in循环可以用来遍历对象的可枚举属性列表(包括[[Prototype]]链)。
ES5增加了一些数组的辅助迭代器,包括forEach()、every()和some()。每种迭代器都可以接受一个回调函数并把它应用到数组的每个元素上,唯一的区别就是它们对于回调函数返回值的处理方式不同。
- forEach():会遍历数组中的所有值并忽略回调函数的返回值。
- every():会一直运行直到回调函数返回false(或者“假”值)。
- some():会一直运行直到回调函数返回true(或者“真”值)。
注:every()和some()中特殊的返回值和普通for循环中的break语句相似,他们会提前终止遍历。
使用for...in遍历对象是无法直接获得属性值的 ,它只是遍历了对象中所有可以枚举的属性,你需要手动获取属性值。
ES6增加了一种用来遍历数组的for...of循环语法(如果对象本身定义了迭代器的话也可以遍历对象):
var myArray = [1,2,3];
for(var v of myArray){
console.log(v); //1 2 3
};
for...of循环首先会向被访问对象请求一个迭代器对象,然后通过调用迭代器对象的next()方法来遍历所有返回值。
数组有内置的@@iterator,因此for...of可以直接应用在数组上。我们使用内置的@@iterator来手动遍历数组,看看它是怎么工作的:
var myArray = [1,2,3];
var it = myArray[Symbol.iterator]();
var next1 = it.next();
var next2 = it.next();
var next3 = it.next();
var next4 = it.next();
console.log(next1); //{value: 1, done: false}
console.log(next2); //{value: 2, done: false}
console.log(next3); //{value: 3, done: false}
console.log(next4); //{value: undefined, done: true}
注:我们使用ES6中的符号Symbol.iterator来获取对象的@@iterator内部属性。@@iterator本身并不是一个迭代器对象,而是一个返回迭代器对象的函数--这一点非常精妙并且非常重要。
普通的对象并没有内置的@@iterator,所以无法自动完成for...of遍历。当然,你也可以给任何想遍历的对象定义@@iterator,如下代码:
var myObject = {
a:2,
b:3
};
Object.defineProperty(myObject,Symbol.iterator,{
enumerable:false,
writable:false,
configurable:true,
value:function(){
var o = this,
idx = 0,
ks = Object.keys(o);
return {
next:function(){
return {
value:o[ks[idx++]],
done:(idx > ks.length)
}
}
}
}
}); //手动遍历myObject
var it = myObject[Symbol.iterator]();
var next1 = it.next();
var next2 = it.next();
var next3 = it.next();
console.log(next1); //{value: 2, done: false}
console.log(next2); //{value: 3, done: false}
console.log(next3); //{value: undefined, done: true} //用for...of遍历myObject
for(var v of myObject){
console.log(v);
}
//2
//3
注:我们使用Object.defineProperty()定义了我们自己的@@iterator(主要是为了让它不可枚举),不过注意,我们把符号当做可计算属性名。此外,也可以直接在定义对象时进行声明,比如:
var myObject = {
a:2,
b:3,
[Symbol.iterator]:function(){
/*..*/
}
};
对于用户定义的对象来说,结合for...of和用户自定义的迭代器可以组成非常强大的对象操作工具。
再看一个例子,写一个迭代器生成“无限个”随机数,我们添加一条break语句,防止程序被挂起,代码如下:
var randoms = {
[Symbol.iterator]:function(){
return {
next:function(){
return {
value:Math.random()
}
}
}
}
}; var random_pool = [];
for(var n of randoms){
random_pool.push(n);
console.log(n);
//防止无限运行
if(random_pool.length === 10) break;
}
constructor 属性
语法:object.constructor
返回值:对象的constructor属性返回创建该对象的函数的引用。
// 字符串:String()
var str = "张三";
alert(str.constructor); // function String() { [native code] }
alert(str.constructor === String); // true // 数组:Array()
var arr = [1, 2, 3];
alert(arr.constructor); // function Array() { [native code] }
alert(arr.constructor === Array); // true // 数字:Number()
var num = 5;
alert(num.constructor); // function Number() { [native code] }
alert(num.constructor === Number); // true // 自定义对象:Person()
function Person(){
this.name = "CodePlayer";
}
var p = new Person();
alert(p.constructor); // function Person(){ this.name = "CodePlayer"; }
alert(p.constructor === Person); // true // JSON对象:Object()
var o = { "name" : "张三"};
alert(o.constructor); // function Object() { [native code] }
alert(o.constructor === Object); // true // 自定义函数:Function()
function foo(){
alert("CodePlayer");
}
alert(foo.constructor); // function Function() { [native code] }
alert(foo.constructor === Function); // true // 函数的原型:bar()
function bar(){
alert("CodePlayer");
}
alert(bar.prototype.constructor); // function bar(){ alert("CodePlayer"); }
alert(bar.prototype.constructor === bar); // true
原型
对象关联
使用Object.create()可以完美的创建我们想要的关联关系。
var foo = {
something:function(){
console.log("tell me something");
}
}; var bar = Object.create(foo);
bar.something(); //tell me something
Object.create()的polyfill代码,由于Object.create()是在ES5中新增的函数,所以在旧版浏览器中不支持,使用下面这段代码兼容:
if(!Object.create){
Object.create = function(o){
function F(){};
F.prototype = o;
return new F();
}
}
标准ES5中内置的Object.create()函数还提供了一系列的附加功能。如下代码:
var anotherObject= {
a:2
};
var myObject = Object.create(anotherObject,{
b:{
enumerable:false,
writable:true,
configurable:false,
value:3
},
c:{
enumerable:true,
writable:false,
configurable:false,
value:4
}
});
console.log(myObject.hasOwnProperty('a')); //false
console.log(myObject.hasOwnProperty('b')); //true
console.log(myObject.hasOwnProperty('c')); //true console.log(myObject.a); //2
console.log(myObject.b); //3
console.log(myObject.c); //4
Object.create(..)第二个参数指定了需要添加到新对象中的属性名以及这些属性的属性描述符。
关联关系是备用
下面代码可以让你的API设计不那么“神奇”,同时仍然能发挥[[Prototype]]关联的威力:
var anotherObject= {
cool:function(){
console.log('cool!');
}
};
var myObject = Object.create(anotherObject);
myObject.deCool = function(){
this.cool();
}
myObject.deCool();
行为委托
面向委托的设计:比较思维模型
下面比较下这两种设计模式(面向对象和对象关联)具体的实现方法。下面典型的(“原型”)面向对象风格:
function Foo(who){
this.me = who;
}
Foo.prototype.identify = function(){
return "I am " + this.me;
} function Bar(who){
Foo.call(this,who);
}
Bar.prototype = Object.create(Foo.prototype);
Bar.prototype.speak = function(){
console.log("hello, " + this.identify() + ".");
}
var b1 = new Bar("b1");
var b2 = new Bar("b2"); b1.speak(); //hello, I am b1.
b2.speak(); //hello, I am b2.
子类Bar继承了父类Foo,然后生成了b1和b2两个实例,b1委托了Bar.prototype,后者委托了Foo.prototype。这种风格很常见。
对象关联风格实现相同的功能:
var Foo = {
init:function(who){
this.me = who;
},
identify:function(){
return "I am " + this.me;
}
}; var Bar = Object.create(Foo); Bar.speak = function(){
console.log("hello, " + this.identify() + ".");
} var b1 = Object.create(Bar);
b1.init("b1");
var b2 = Object.create(Bar);
b2.init("b2"); b1.speak(); //hello, I am b1.
b2.speak(); //hello, I am b2.
这段代码同样利用[[Prototype]]把b1委托给Bar并把Bar委托给Foo,和上一段代码一模一样。我们仍然实现了三个对象直接的关联。
类与对象
web开发一种典型的前端场景:创建UI控件(按钮,下拉列表等等)。
控件“类”
下面代码是在不使用任何“类”辅助库或者语法的情况下,使用纯JavaScript实现类风格的代码:
//父类
function Widget(width,height){
this.width = width || 50;
this.height = height || 50;
this.$elem = null;
};
Widget.prototype.render = function($where){
if(this.$elem){
this.$elem.css({
width:this.width + "px",
height:this.height + "px"
}).appendTo($where);
}
}; //子类
function Button(width,height,label){
//调用"super"构造函数
Widget.call(this,width,height);
this.label = label || "Default";
this.$elem = $("<button>").text(this.label);
} //让子类“继承”Widget
Button.prototype = Object.create(Widget.prototype); //重写render()
Button.prototype.render = function($where){
Widget.prototype.render.call(this,$where);
this.$elem.click(this.onClick.bind(this));
}
Button.prototype.onClick = function(evt){
console.log("Button '"+this.label+"'clicked! ");
}; $(document).ready(function(){
var $body = $(document.body);
var btn1 = new Button(125,30,"Hello");
var btn2 = new Button(150,40,"World");
btn1.render($body);
btn2.render($body);
});
ES6的class语法糖:
class Widget {
constructor(width,height) {
this.width = width || 50;
this.height = height || 50;
this.$elem = null;
}
render($where){
if(this.$elem){
this.$elem.css({
width:this.width + "px",
height:this.height + "px"
}).appendTo($where);
}
}
} class Button extends Widget {
constructor(width,height,label){
super(width,height);
this.label = label || "Default";
this.$elem = $("<button>").text(this.label);
}
render($where){
super($where);
this.$elem.click(this.onClick.bind(this));
}
onClick(evt){
console.log("Button '"+this.label+"'clicked! ");
}
} $(document).ready(function(){
var $body = $(document.body);
var btn1 = new Button(125,30,"Hello");
var btn2 = new Button(150,40,"World");
btn1.render($body);
btn2.render($body);
});
委托控件对象
下面例子使用对象关联风格委托来更简单地实现Wiget/Button:
var Widget = {
init:function(width,height){
this.width = width || 50;
this.height = height || 50;
this.$elem = null;
},
insert:function($where){
if(this.$elem){
this.$elems.css({
width:this.width + "px",
height:this.height + "px"
}).appendTo($where);
}
}
} var Button = Object.create(Widget);
Button.setup = function(width,height,label){
//委托调用
this.init(width,height);
this.label = label || "Default";
this.$elem = $("<button>").text(this.label);
}
Button.build = function($where){
//委托调用
this.insert($where);
this.$elem.click(this.onClick.bind(this));
}
Button.onClick = function(evt){
console.log("Button '"+this.label+"'clicked! ");
} $(document).ready(function(){
var $body = $(document.body); var btn1 = Object.create(Button);
btn1.setup(125,30,"Hello"); var btn2 = Object.create(Button);
btn2.setup(150,40,"World"); btn1.build($body);
btn2.build($body);
})
对象关联可以更好的支持关注分离(separation of concerns)原则,创建和初始化并不需要合并成一个步骤。
#s3gt_translate_tooltip_mini { display: none !important }
#s3gt_translate_tooltip_mini { display: none !important }
#s3gt_translate_tooltip_mini { display: none !important }
『读书笔记』你不知道的JavaScript(上)的更多相关文章
- 【读书笔记】-- 你不知道的JavaScript
<你不知道的JavaScript>是一个不错的JavaScript系列书,书名可能有些标题党的意思,但实符其名,很多地方会让你有耳目一新的感觉. 1.typeof null === &qu ...
- 【读书笔记】你不知道的JavaScript(上卷)--作用域是什么
第一章 作用域 1.理解作用域 几个名词的介绍 引擎:从头到尾负责整个JavaScript程序的编译及执行过程 编译器:负责语法分析及代码生成器等脏活累活 作用域:负责收集并维护由所有声明的标识符(变 ...
- 读书笔记-你不知道的JavaScript(上)
本文首发在我的个人博客:http://muyunyun.cn/ <你不知道的JavaScript>系列丛书给出了很多颠覆以往对JavaScript认知的点, 读完上卷,受益匪浅,于是对其精 ...
- Spring读书笔记——bean创建(上)
通过<Spring读书笔记--bean加载>和<Spring读书笔记--bean解析>,我们明白了两件事. Spring如何加载消化一个xml配置文件 Spring如何将xml ...
- 《你不知道的javascript(上)》笔记
作用域是什么 编译原理 分词/词法分析 这个过程会将由字符组成的字符串分解成(对编程语言来说)有意义的代码块,这些代码块被称为词法单元 解析/语法分析 词法单元流(数组)转换成一个由元素逐级嵌套所组成 ...
- javascript 数据结构和算法读书笔记 > 第一章 javascript的编程环境和模型
1.变量的声明和初始化 必须使用关键字 var,后跟变量名,后面还可以跟一个赋值表达式. var name; var age = 5; var str = 'hello'; var flg = fal ...
- 读书笔记(05) - 事件 - JavaScript高级程序设计
HTML依托于JavaScript来实现用户与WEB网页之间的动态交互,接收用户操作并做出相应的反馈,而事件在此间则充当桥梁的重要角色. 日常开发中,经常会为某个元素绑定一个事件,编写相应的业务逻辑, ...
- 读书笔记(03) - 性能 - JavaScript高级程序设计
作用域链查找 作用域链的查找是逐层向上查找.查找的层次越多,速度越慢.随着硬件性能的提升和浏览器引擎的优化,这个慢我们基本可以忽略. 除了层级查找损耗的问题,变量的修改应只在局部环境进行,尽量避免在局 ...
- 读书笔记(02) - 可维护性 - JavaScript高级程序设计
编写可维护性代码 可维护的代码遵循原则: 可理解性 (方便他人理解) 直观性 (一眼明了) 可适应性 (数据变化无需重写方法) 可扩展性 (应对未来需求扩展,要求较高) 可调试性 (错误处理方便定位) ...
- 读书笔记(01) - JSON - JavaScript高级程序设计
JSON与JavaScript对象 JSON是一种表示结构化数据的存储格式,语法格式上与JavasScript对象有些类似. TIPS: 与JavaScript对象的格式区别 不支持变量.函数或对象实 ...
随机推荐
- CF-957(D-E)
CF-957 赛时A去写全排列--前三题我的写法都挺丑的,后面改进了再更-- Problem - D - Codeforces 虽然是很简单很经典的线性dp,但也是我第一次自己把这种题写出来ヾ(≧▽≦ ...
- leetcode中等(字符串):[3, 6, 8, 49, 179, 299, 524, 539, 609, 648]
目录 3. 无重复字符的最长子串 6. Z 字形变换 8. 字符串转换整数 (atoi) 49. 字母异位词分组 179. 最大数 299. 猜数字游戏 524. 通过删除字母匹配到字典里最长单词 5 ...
- memset函数&&bzro函数_C
// Code file created by C Code Develop #include "ccd.h" #include "stdio.h" #incl ...
- SQL提高查询性能的几种方式
创建索引,提高性能 索引可以极大地提高查询性能,其背后的原理: 索引是的数据库引擎能够快速的找到表中的数据,它们类似于书籍的目录,使得你不需要逐页查找所需要的信息 索引能够帮助数据库引擎直接定位到所需 ...
- mindspore.ops.Pow()等算子不能处理float64类型的数据
原文地址: https://gitee.com/mindspore/mindspore/issues/I3ZG99 Software Environment: -- MindSpore r1.2 GP ...
- cloudpickle —— Python分布式序列化的专用模块
给出cloudpickle的GitHub地址: https://github.com/cloudpipe/cloudpickle =================================== ...
- css手撕奥运五环
巴黎奥运会正如火如荼地进行,本文来使用 CSS 来画一个奥运五环.奥运五环是相互连接的,因此在视觉上会产生重叠效果,这也是实现五环最有挑战性的部分.接下来,将利用 CSS 的伪元素,巧妙地实现环环相扣 ...
- 【技术积累】如何处理Feign的超时问题
在使用Feign进行微服务之间的通信时,由于网络延迟等原因,可能会出现请求超时的情况.为了解决这个问题,我们可以对Feign进行配置,设置超时时间. 配置Feign的超时时间 在使用Feign时,我们 ...
- Apache DolphinScheduler 如何实现自动化打包+单机/集群部署?
Apache DolphinScheduler 是一款开源的分布式任务调度系统,旨在帮助用户实现复杂任务的自动化调度和管理.DolphinScheduler 支持多种任务类型,可以在单机或集群环境下运 ...
- JavaScript设计模式样例二十一 —— 解释器模式
解释器模式(Interpreter Pattern) 定义:提供了评估语言的语法或表达式的方式.目的:对于一些固定文法构建一个解释句子的解释器.场景:编译器.运算表达式计算. // 定义对于语法的断言 ...