首页 > 编程知识 正文

js代码提升(js 函数提升)

时间:2023-12-19 16:21:18 阅读:317890 作者:WQVV

本文目录一览:

解释JavaScript中的变量声明提升?

由于JavaScript在设计之初就是弱类型,所以很多地方设计的不是特别严格。JavaScript代码是自上而下执行的,变量提升指的就是你明明在第10行通过 var 申明了变量并赋值,但是在程序运行时还没加载到第10行的时候,变量就被申明,但是到第10行的时候变量才被赋值。这个就是变量提升。所以一般都是把变量申明放在JavaScript的最顶端 或者使用let const 申明避免变量的提升

Web前端工程师应该知道的提高JavaScript技能的技巧!

今天小编要跟大家分享的文章是关于Web前端工程师应该知道的提高JavaScript

技能的技巧!熟悉web前端工作的小伙伴都知道,JavaScript是前端工程师的必备技能。JavaScript

是一种复杂的语言。如果是你是高级或者初级web开发人员,了解它的基本概念非常重要。本篇文章小编就为大家介绍几种提高JavaScript

技能的技巧,下面让我们一起来看一看吧!

01、变量赋值(值vs引用)

理解JavaScript如何给变量赋值可以帮助我们减少一些不必要的bug。如果你不理解这一点,可能很容易地编写被无意中更改值的代码。

JavaScript总是按照值来给变量赋值。这一部分非常重要:当指定的值是JavaScript的五种基本类型之一(即

Boolean,null,undefined,String和Number)时,将分配实际值。但是,当指定的值是

Array,Function或Object时,将分配对内存中对象的引用给变量。

在以下代码段中,使用var1对var2进行赋值。由于var1是基本类型(String),因此var2的值等于var1的String

值,并且可以认为此时与var1完全不同。因此,重新赋值var2对var1没有影响。

letvar1='Mystring';

letvar2=var1;

var2='Mynewstring';

console.log(var1);

//'Mystring'

console.log(var2);

//'Mynewstring'

接着,与对象赋值进行比较。

letvar1={name:'Jim'}

letvar2=var1;

var2.name='John';

console.log(var1);

//{name:'John'}

console.log(var2);

//{name:'John'}

如果你期望它会像原始类型赋值那样,很可能会出问题!如果你创建了一个无意中会改变对象的函数,就会出现一些非预期的行为。

02、闭包

闭包是一个重要的JavaScript模式,可以私有访问变量。在本例中,createGreeter返回一个匿名函数,这个函数可以访问参数

greeting(在这里是“Hello”)。在后续的调用中,sayHello将有权访问这个greeting!

functioncreateGreeter(greeting){

returnfunction(name){

console.log(greeting+','+name);

}

}

constsayHello=createGreeter('Hello');

sayHello('Joe');

//Hello,Joe

在更真实的场景中,你可以设想一个初始函数apiConnect(apiKey),它返回一些使用APIkey的方法。在这种情况下,apiKey

只需要提供一次即可。

functionapiConnect(apiKey){

functionget(route){

returnfetch(`${route}?key=${apiKey}`);

}

functionpost(route,params){

returnfetch(route,{

method:'POST',

body:JSON.stringify(params),

headers:{

'Authorization':`Bearer${apiKey}`

}

})

}

return{get,post}

}

constapi=apiConnect('my-secret-key');

//NoneedtoincludetheapiKeyanymore

api.get('#/get-endpoint');

api.post('#/post-endpoint',{name:'Joe'});

03、解构

JavaScript参数解构可以从对象中干中提取所需属性的常用方法。

constobj={

ame:'Joe',

food:'cake'

}

const{name,food}=obj;

console.log(name,food);

//'Joe''cake'

如果要以其他名称提取属性,可以使用如下方式:

constobj={

ame:'Joe',

food:'cake'

}

const{name:myName,food:myFood}=obj;

console.log(myName,myFood);

//'Joe''cake'

解构经常也用于直接用于提取传给函数的参数。如果你熟悉React,可能已经见过这个:

constperson={

ame:'Eddie',

age:24

}

functionintroduce({name,age}){

console.log(`I'm${name}andI'm${age}yearsold!`);

}

console.log(introduce(person));

//"I'mEddieandI'm24yearsold!"

04、展开运算

ES6的一个常用之一的特性就是展开(...)运算符了,在下面的例子中,Math.max不能应用于arr

数组,因为它不将数组作为参数,但它可以将各个元素作为参数传入。展开运算符...可用于提取数组的各个元素。

constarr=[4,6,-1,3,10,4];

constmax=Math.max(...arr);

console.log(max);

//10

05、剩余参数

剩余参数语法和展开语法看起来的一样的,不同的是展开语法是为了结构数组和对象;而剩余参数和展开运算符是相反的,剩余参数收集多个元素合成一个数组。

functionmyFunc(...args){

console.log(args[0]+args[1]);

}

myFunc(1,2,3,4);

//3

restparameters和arguments的区别

1.arguments是伪数组,包含所有的实参

2.剩余参数是标准的数组,可以使用数组的方法

06、数组方法

JavaScript数组方法通常可以提供令人难以置信的、优雅的方法来执行所需的数据转换。作为StackOverflow

的贡献者,我经常看到关于如何以某种方式操纵对象数组的问题,这往往也是数组方法的完美用例。

map、filter、reduce

JavaScript数组方法map、filter和reduce容易混淆,这些都是转换数组或返回聚合值的有用方法。

map:返回一个数组,其中每个元素都使用指定函数进行过转换。

constarr=[1,2,3,4,5,6];

constmapped=arr.map(el=el+20);

console.log(mapped);

//[21,22,23,24,25,26]

filter:返回一个数组,只有当指定函数返回true时,相应的元素才会被包含在这个数组中。

constarr=[1,2,3,4,5,6];

constfiltered=arr.filter(el=el===2||el===4);

console.log(filtered);

//[2,4]

reduce:按函数中指定的值累加

constarr=[1,2,3,4,5,6];

constreduced=arr.reduce((total,current)=total+current);

console.log(reduced);

//21

find,findIndex,indexOf

find:返回与指定条件匹配的第一个实例,如果查到不会继续查找其他匹配的实例。

constarr=[1,2,3,4,5,6,7,8,9,10];

constfound=arr.find(el=el5);

console.log(found);

//6

再次注意,虽然5之后的所有元素都满足条件,但是只返回第一个匹配的元素。当你发现匹配项时,通常会中断for循环,在这种情况下,这实际上非常有用。

findIndex:这与find几乎完全相同,但不是返回第一个匹配元素,而是返回第一个匹配元素的索引。

constarr=['Nick','Frank','Joe','Frank'];

constfoundIndex=arr.findIndex(el=el==='Frank');

console.log(foundIndex);

//1

indexOf:与findIndex几乎完全相同,但它不是将函数作为参数,而是采用一个简单的值。

当w你需要更简单的逻辑并且不需要使用函数来检查是否存在匹配时,可以使用此方法。

constarr=['Nick','Frank','Joe','Frank'];

constfoundIndex=arr.indexOf('Frank');

console.log(foundIndex);

//1

push,pop,shift,unshift

push:这是一个相对简单的方法,它将一个项添加到数组的末尾。它就地修改数组,函数本身会返回添加到数组中的项。

letarr=[1,2,3,4];

constpushed=arr.push(5);

console.log(arr);

//[1,2,3,4,5]

console.log(pushed);

//5

pop:这将从数组中删除最后一项。同样,它在适当的位置修改数组,函数本身返回从数组中删除的项。

letarr=[1,2,3,4];

constpopped=arr.pop();

console.log(arr);

//[1,2,3]

console.log(popped);

//4

shift:从数组中删除第一项。同样,它在适当的位置修改数组。函数本身返回从数组中删除的项。

letarr=[1,2,3,4];

constshifted=arr.shift();

console.log(arr);

//[2,3,4]

console.log(shifted);

//1

unshift:将一个或多个元素添加到数组的开头。同样,它在适当的位置修改数组。与许多其他方法不同,函数本身返回数组的新长度。

letarr=[1,2,3,4];

constunshifted=arr.unshift(5,6,7);

console.log(arr);

//[5,6,7,1,2,3,4]

console.log(unshifted);

//7

splice,slice

splice:通过删除或替换现有元素和/或添加新元素来更改数组的内容,此方法会修改了数组本身。

下面的代码示例的意思是:在数组的位置1上删除0个元素,并插入b。

letarr=['a','c','d','e'];

arr.splice(1,0,'b')

slice:从指定的起始位置和指定的结束位置之前返回数组的浅拷贝。如果未指定结束位置,则返回数组的其余部分。

重要的是,此方法不会修改数组,而是返回所需的子集。

letarr=['a','b','c','d','e'];

constsliced=arr.slice(2,4);

console.log(sliced);

//['c','d']

console.log(arr);

//['a','b','c','d','e']

sort

sort:根据提供的函数对数组进行排序。这个方法就地修改数组。如果函数返回负数或0,则顺序保持不变。如果返回正数,则交换元素顺序。

letarr=[1,7,3,-1,5,7,2];

constsorter=(firstEl,secondEl)=firstEl-secondEl;

arr.sort(sorter);

console.log(arr);

//[-1,1,2,3,5,7,7]

07、Generators(生成器)

生成器是一种特殊的行为,实际上是一种设计模式,我们通过调用next()方法来遍历一组有序的值。想象一下,例如使用遍历器对数组[1,2,3,4,5]进行遍历。第一次调用next()方法返回1,第二次调用next()方法返回2,以此类推。当数组中的所有值都返回后,调用next()方法将返回null或false或其它可能的值用来表示数组中的所有元素都已遍历完毕。

function*greeter(){

yield'Hi';

yield'Howareyou?';

yield'Bye';

}

constgreet=greeter();

console.log(greet.next().value);

//'Hi'

console.log(greet.next().value);

//'Howareyou?'

console.log(greet.next().value);

//'Bye'

console.log(greet.next().value);

//undefined

使用生成器生成无限个值:

function*idCreator(){

leti=0;

while(true)

yieldi++;

}

constids=idCreator();

console.log(ids.next().value);

//0

console.log(ids.next().value);

//1

console.log(ids.next().value);

//2

//etc...

08、恒等运算符(===)与相等运算符(==)

大家一定要知道JavaScript中的恒等运算符(===)和相等运算符(==)之间的区别!

==运算符在比较值之前会进行类型转换,而===运算符在比较之前不会进行任何类型转换。

console.log(0=='0');

//true

console.log(0==='0');

//false

09、对象比较

我看到JavaScript新手所犯的错误是直接比较对象。变量指向内存中对象的引用,而不是对象本身!实际比较它们的一种方法是将对象转换为JSON

字符串。这有一个缺点:对象属性顺序不能保证!比较对象的一种更安全的方法是引入专门进行深度对象比较的库(例如,lodash的isEqual)。

下面的对象看起来是相等的,但实际上它们指向不同的引用。

constjoe1={name:'Joe'};

constjoe2={name:'Joe'};

console.log(joe1===joe2);

//false

相反,下面的计算结果为true,因为一个对象被设置为与另一个对象相等,因此指向相同的引用(内存中只有一个对象)。

constjoe1={name:'Joe'};

constjoe2=joe1;

console.log(joe1===joe2);

//true

相反,以下计算结果为true,因为一个对象设置为等于另一个对象,因此指向相同的引用(内存中只有一个对象)。

constjoe1={name:'Joe'};

constjoe2=joe1;

console.log(joe1===joe2);

//true

10、回调函数

很多人都被JavaScript回调函数吓倒了!他们很简单,举个例子。console.log函数作为回调传递给myFunc。

它在setTimeout完成时执行。

functionmyFunc(text,callback){

setTimeout(function(){

callback(text);

},2000);

}

myFunc('Helloworld!',console.log);

//'Helloworld!'

11、Promises

一旦你理解了JavaScript回调,很快就会发现自己陷入了“回调地狱”中。这个时候可以使用promise,将异步逻辑包装在promise

中,成功时resolve或在失败时reject使用“then”来处理成功的情况,使用catch来处理异常。

constmyPromise=newPromise(function(res,rej){

setTimeout(function(){

if(Math.random()

returnres('Hooray!');

}

returnrej('Ohno!');

},1000);

});

myPromise

.then(function(data){

console.log('Success:'+data);

})

.catch(function(err){

console.log('Error:'+err);

});

//IfMath.random()returnslessthan0.9thefollowingislogged:

//"Success:Hooray!"

//IfMath.random()returns0.9orgreaterthefollowingislogged:

//"Error:Onno!"

12、Async/Await

在掌握了promise的用法后,你可能也会喜欢asyncawait,它只是一种基于promise

的“语法糖”。在下面的示例中,我们创建了一个async函数,并awaitgreeterpromise。

constgreeter=newPromise((res,rej)={

setTimeout(()=res('Helloworld!'),2000);

})

asyncfuncti

var a=0; function fun(){ a++; if(a

var a=0; function fun(){ a++; if(a=10){ fun(); } console.log(a+=1) } fun();

为什么结果是十一个十一?理由如下:

带 var 的只声明还没有被定义,带 function 的已经声明和定义。所以在代码执行前有带 var 的就提前声明。

变量提升示例:

console.log(a)  // undefinedvar

a = 10

变量提升是当栈内存作用域形成时,JS代码执行前,浏览器会将带有var, function关键字的变量提前进行声明 declare(值默认就是 undefined)。

定义 defined(就是赋值操作),这种预先处理的机制就叫做变量提升机制也叫预定义。

在变量提升阶段:带 var 的只声明还没有被定义,带 function 的已经声明和定义。所以在代码执行前有带 var 的就提前声明,比如这里的 a 就赋值成 undefined,在代码执行过程中遇到创建函数的代码浏览器会直接跳过。

变量提升只发生在当前作用域。比如:在页面开始加载时,只有全局作用域发生变量提升,这时候的函数中存储的都是代码字符串。

全局作用域中不带var声明变量虽然也可以但是建议带上 var声明变量,不带 var 的相当于给window对象设置一个属性罢了。

私有作用域(函数作用域),带 var 的是私有变量。不带 var 的是会向上级作用域查找,如果上级作用域也没有那么就一直找到 window 为止,这个查找过程叫作用域链。

全局作用域中使用 var 申明的变量会映射到 window 下成为属性。

js中if是一个代码块嘛? 写在if里面的函数声明和var变量会得到提升嘛?

你好,你的这个问题是这样的首先第一个打印a,是在源码开头定义的var变量a。

紧接着在第一个if内嵌套定义了一个名为a的函数,因为js是弱语言,所以实现对应的变量a被重新指向了函数a,所以在最后一次打印a的时候是函数a

Jsp中有大量js和css,如何提高页面加载速度

加载速度不必刻意强求,真正项目尤其是前端开发讲究的是可读性,如真的项目写好后可以考虑压缩css和js代码,css带走方向的复合属性如边框,外边距,补白等最好用一个属性代替,顺序为上,右,下,左。表格尽量少用。

js判断对象里是否有内容

Javascript语言的设计不够严谨,很多地方一不小心就会出错。

举例来说,请考虑以下情况。

现在,我们要判断一个全局对象myObj是否存在,如果不存在,就对它进行声明。用自然语言描述的算法如下:

复制代码代码如下:

if (myObj不存在){

声明myObj;

}

你可能会觉得,写出这段代码很容易。但是实际上,它涉及的语法问题,远比我们想象的复杂。Juriy Zaytsev指出,判断一个Javascript对象是否存在,有超过50种写法。只有对Javascript语言的实现细节非常清楚,才可能分得清它们的区别。

第一种写法

根据直觉,你可能觉得可以这样写:

复制代码代码如下:

if (!myObj) {

myObj = { };

}

但是,运行这段代码,浏览器会直接抛出ReferenceError错误,导致运行中断。请问错在哪里?

对了,if语句判断myObj是否为空时,这个变量还不存在,所以才会报错。改成下面这样,就能正确运行了。

复制代码代码如下:

if (!myObj) {

var myObj = { };

}

为什么加了一个var以后,就不报错了?难道这种情况下,if语句做判断时,myObj就已经存在了吗?

要回答这个问题,就必须知道Javascript解释器的工作方式。Javascript语言是"先解析,后运行",解析时就已经完成了变量声明,所以上面的代码实际等同于:

复制代码代码如下:

var myObj;

if (!myObj) {

var myObj = { };

}

因此,if语句做判断时,myObj确实已经存在了,所以就不报错了。这就是var命令的"代码提升"(hoisting)作用。Javascript解释器,只"提升"var命令定义的变量,对不使用var命令、直接赋值的变量不起作用,这就是为什么不加var会报错的原因。

第二种写法

除了var命令,还可以有另一种改写,也能得到正确的结果:

复制代码代码如下:

if (!window.myObj) {

myObj = { };

}

window是javascript的顶层对象,所有的全局变量都是它的属性。所以,判断myobj是否为空,等同于判断window对象是否有myobj属性,这样就可以避免因为myObj没有定义而出现ReferenceError错误。不过,从代码的规范性考虑,最好还是对第二行加上var:

复制代码代码如下:

if (!window.myObj) {

var myObj = { };

}

或者写成这样:

if (!window.myObj) {

window.myObj = { };

}

第三种写法

上面这种写法的缺点在于,在某些运行环境中(比如V8、Rhino),window未必是顶层对象。所以,考虑改写成:

复制代码代码如下:

if (!this.myObj) {

this.myObj = { };

}

在全局变量的层面中,this关键字总是指向顶层变量,所以就可以独立于不同的运行环境。

第四种写法

但是,上面这样写可读性较差,而且this的指向是可变的,容易出错,所以进一步改写:

复制代码代码如下:

var global = this;

if (!global.myObj) {

global.myObj = { };

}

用自定义变量global表示顶层对象,就清楚多了。

第五种写法

还可以使用typeof运算符,判断myObj是否有定义。

复制代码代码如下:

if (typeof myObj == "undefined") {

var myObj = { };

}

这是目前使用最广泛的判断javascript对象是否存在的方法。

第六种写法

由于在已定义、但未赋值的情况下,myObj的值直接等于undefined,所以上面的写法可以简化:

复制代码代码如下:

if (myObj == undefined) {

var myObj = { };

}

这里有两个地方需要注意,首先第二行的var关键字不能少,否则会出现ReferenceError错误,其次undefined不能加单引号或双引号,因为这里比较的是undefined这种数据类型,而不是"undefined"这个字符串。

第七种写法

上面的写法在"精确比较"(===)的情况下,依然成立:

复制代码代码如下:

if (myObj === undefined) {

var myObj = { };

}

第八种写法

根据javascript的语言设计,undefined == null,所以比较myObj是否等于null,也能得到正确结果:

复制代码代码如下:

if (myObj == null) {

var myObj = { };

}

不过,虽然运行结果正确,但是从语义上看,这种判断方法是错的,应该避免。因为null指的是已经赋值为null的空对象,即这个对象实际上是有值的,而undefined指的是不存在或没有赋值的对象。因此,这里只能使用"比较运算符"(==),如果这里使用"精确比较运算符"(===),就会出错。

第九种写法

还可以使用in运算符,判断myObj是否为顶层对象的一个属性:

复制代码代码如下:

if (!('myObj' in window)) {

window.myObj = { };

}

第十种写法

最后,使用hasOwnProperty方法,判断myObj是否为顶层对象的一个属性:

复制代码代码如下:

if (!this.hasOwnProperty('myObj')) {

this.myObj = { };

}

总结

1. 如果只判断对象是否存在,推荐使用第五种写法。

2. 如果除了对象是否存在,还要判断对象是否有null值,推荐使用第一种写法。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。