刷题总结

7 篇文章 0 订阅

 

目录

 

1.JS中的引用赋值与传值赋值

2.JS运行机制 

3.JS中获取对象

4.JS中的空对象转为布尔类型

5.onclick等事件加不加括号问题

6.html5的优势

7.ES6的特性

8.css3新特性

9.css选择器

10.setTimeout和Promise的执行顺序

11.JS里的对象类型

12.JS里的变量回收规则

13.Array对象方法哪些会改变原数组哪些不会

14.let与setTimeout的问题 

15. 变量与变量重名、变量与函数重名问题

16.JS中的垃圾回收机制


1.JS中的引用赋值与传值赋值

JS中字符串的值是无法被改变的,例如

var S1 = "hello world!"

S1[0] = 'a'

console.log(S1[0]) //打印'h',不会变成'a'

但实施以下操作是成立的:

var s1 = "heihei"
s1 += "haha"
console.log(s1) //"heiheihaha"

var s2 = "world"
s2 = "hello"
console.log(s1) //"hello"

但是,这里的s1最后 已经指向了一个新的地址空间,而不是在原来的地址空间上对字符串做修改。原来的地址空间存放的字符串还是"heihei"。同理,s2也是指向了一个新的地址空间

在JS中,对于基本类型:string、number、boolean、null、undefined,他们的变量是存放在栈区的,也就是说可以操作保存在变量中实际的值。当基本类型赋值的时候,赋的是实际的值,例如

var a = 10
var b = a

 a和b是没有关联的,b由a复制得到,他们在内存中的关系如下:

a和b是两个不同的空间。

对于引用类型,Array、Function、Object。可以拥有属性和方法,并且我们可以修改其属性和方法。引用对象存放的方式是:在栈中存放对象变量标示名称和该对象在堆中的存放地址,在堆中存放数据。对象使用的是引用赋值。当我们把一个对象赋值给一个新的变量时,赋的其实是该对象的在堆中的地址,而不是堆中的数据。也就是两个对象指向的是同一个存储空间,无论哪个对象发生改变,其实都是改变的存储空间的内容,因此,两个对象是联动的。举个栗子:

var a1 = [1,2,3];

var b1 = a1;

a1 = [4,5,6];

alert(b1); //[1,2,3]


var a2 = [1,2,3];

var b2 = a2;

a2.pop();

alert(b2); //[1,2]

 a1 = [4,5,6];//改变的是a引用本身,没有改变数组对象,a1和b1没有了关系。

a2.pop();//改变的是数组对象,a引用没有改变。

b2 = a2;//该操作后,b直接指向数组对象,不是b指向a,a再指向数组。

所以改变a引用并不会对b引用造成影响,改变数组对象可以。

2.JS运行机制 

<ul>
 <li>click me</li>
 <li>click me</li>
 <li>click me</li>
 <li>click me</li>
</ul>

 

    var elements=document.getElementsByTagName('li');
    var length=elements.length;
    for(var i=0;i<length;i++){
        elements[i].onclick=function(){
        alert(i);
    }
 }

依次点击4个li标签,会依次弹出4,4,4,4

JS运行机制:事件(click,focus等等),定时器(setTimeout和setInterval),ajax,都是会触发异步,属于异步任务;js是单线程的,一个时间点只能做一件事,优先处理同步任务; 按照代码从上往下执行,遇到异步,就挂起,放到异步任务里,继续执行同步任务,只有同步任务执行完了,才去看看有没有异步任务,然后再按照顺序执行! 这里for循环是同步任务,onclick是异步任务,所以等for循环执行完了,i变成4了,注意:这里因为i是全局变量,最后一个i++,使得i为4(后面的onclick函数,最后在循环外面执行,不受i<length限制); 所以for循环每执行一次,onclick事件函数都会被挂起一次,共4次; for循环结束后,点击事件 触发了4个onclick函数,接着输出4个4!

3.JS中获取对象

在js里面添加的属性名使用驼峰法,在css里面使用连接线。

除了id和query 其他返回的都是节点列表。document.getElementClass返回的是一个数组

4.JS中的空对象转为布尔类型

 

5.onclick等事件加不加括号问题

 第一种情况:

在上图中,这是一个onclick函数,clickIt()则是在函数内部,所以当触发了onclick事件的时候,onclick函数就执行,这时候因为clickIt在onclick函数内部已经执行了,所以会打印出来hahaha.

如果改成οnclick="clickIt",这时候打印出来的就是function onclick(){  },而不会打印出hahaha,所以即使点击了按钮,触发了onclick事件,clickIt依然不会执行。

 

第二种情况: 

 上图中,是用DOM0级绑定点击事件的方法,打印onclick,结果发现onclick就是clickIt函数。


所以这个时候clickIt后面就不用加括号,当你触发onclick事件的时候,直接就会执行.

如果要是在clickIt后面加个括号,不触发onclick事件也会直接执行clickIt。

总结:加上括号是执行的意思,添加事件的回调函数应该就是给相应的事件属性赋值,而很明显需要把一个函数赋值给这个事件属性,而不是函数的调用结果。所以在js中的绑定是直接赋值(上述第二种情况)。而在标签内的事件属性的值是由引号包裹的,代表的是当点击该元素时,执行引号内的代码,直接把引号内的代码拿出来跑,如果不加括号,那就不会调用那个函数(上述第一种情况)。 

在Vue.js里,@click点击事件带不带括号没有多大区别,因为Vue会在底层把传过去的函数统一解析成方法,如果带小括号的话说明有相应的实参要传入方法体里面

6.html5的优势

1.有明确的语义,语义化(header,footer,aside……)代码可读性更高

2.对视频和音频的支持,可以插入

3.本地存储,localStorage和SessionStorage

4.移动端

7.ES6的特性

8.css3新特性

transform、transition、animation

9.css选择器

优先级:

1.越具体的优先级越高(#xxx > .yyy)

2.同一个层级的,写在后边的优先级高

<div class = "xxx yyy"></div> 

.xxx{width:20px}

.yyy{width:50px}

3.属性后面加了!important的优先级最高 

10.setTimeout和Promise的执行顺序

setTimeout(function () {
  console.log('定时器开始啦')
});
new Promise(function (resolve) {
  console.log('马上执行for循环啦');
  for (var i = 0; i < 10000; i++) {
    i == 99 && resolve();
  }
}).then(function () {
  console.log('执行then函数啦')
});
console.log('代码执行结束');
//输出:马上执行for循环啦  代码执行结束  执行then函数啦  定时器开始啦

11.JS里的对象类型

JS中,可以将对象分为“内部对象”、“宿主对象”和“自定义对象”三种。

1.内部对象

js中的内部对象包括Array、Boolean、Date、Function、Global、Math、Number、Object、RegExp、String以及各种错误类对象,包括Error、EvalError、RangeError、ReferenceError、SyntaxError和TypeError。

其中Global和Math这两个对象又被称为“内置对象”,这两个对象在脚本程序初始化时被创建,不必实例化这两个对象。

2.宿主对象

宿主对象就是执行JS脚本的环境提供的对象。对于嵌入到网页中的JS来说,其宿主对象就是浏览器提供的对象,所以又称为浏览器对象,如IE、Firefox等浏览器提供的对象。不同的浏览器提供的宿主对象可能不同,即使提供的对象相同,其实现方式也大相径庭!这会带来浏览器兼容问题,增加开发难度。

浏览器对象有很多,如Window和Documen,Element,form,image,等等。

3.自定义对象

顾名思义,就是开发人员自己定义的对象。JS允许使用自定义对象,使JS应用及功能得到扩充

12.JS里的变量回收规则

1.全局变量不会被回收。

2.局部变量会被回收,也就是函数一旦运行完以后,函数内部的东西都会被销毁。

3.只要被另外一个作用域所引用就不会被回收

13.Array对象方法哪些会改变原数组哪些不会

以下这些方法会改变原数组

var arr = []
arr.splice()返回被删除的项目
arr.reverse()
arr.fill()
arr.copyWithin()
arr.sort()
arr.push()返回的数组长度
arr.pop()
arr.unshift()
arr.shift()

不会改变原数组

var arr = []
arr.slice()
arr.map()
arr.forEach()
arr.every()
arr.some()
arr.filter()
arr.reduce()
arr.entries()
arr.find()
arr.concat('1',['2','3']) //[1,2,3]
 

Array 的reduce方法

实现 一个累加器,

array.reduce(function(total, currentValue, currentIndex, arr), initialValue)

如果没有指定initialValue,则把array中第一个元素作为初始值,total初始值是array第一个元素,currentValue从数组中第二个元素开始。

如果指定了initialValue,total初始值就是initialValue,currentValue从array中第一个元素开始。

14.let与setTimeout的问题 

//(1)
for(var i = 0; i < 4; i ++){
    let j = i
    setTimeout(function(){
        console.log(j)
    }, 1000)
}//0,1,2,3,4

//(2)
for(let i = 0; i < 5; i ++){
    setTimeout(function(){
        console.log(i)
    }, 1000)
}//0,1,2,3,4


//(3)
for(var i = 0; i < 5; i++){
    (function(){
        var j = i
        setTimeout(function(){
            console.log(j)
        }, 1000)
    })()
}//0,1,2,3,4

(1)中,在每一次循环的时候,都会有一个let j = i,let会创建一个块级作用域,五次循环的j是不同的地址。let j = i后遇到了setTimeout,这是一个WebAPI(如下图),将setTimeout的回调函数放进异步任务的的等待队列里:

这里的setTimeout的回调函数指的是

function(){
    console.log(j)
}

放进等待队列的时候,console.log(j)这句话里的j的地址也被指定了。由于5次j是不同的地址,所以会输出0,1,2,3,4。

 当同步任务(这段代码里是for循环)执行完了后,js引擎就会去等待队列里读取异步任务(就是五次setTimeout 的回调函数),然后开始执行这些异步任务,输出0,1,2,3,4

 (2)的原理与(1)相同。如果(2)的循环体改成

for(var i = 0; i < 5; i ++){}

 var不会创建块级作用域,每一次循环的i都是同一个地址,所以在输出的时候就会输出5,5,5,5,5

(3)这段代码里有一个立即执行函数表达式,立即执行函数表达式也会创建函数作用域。每一次循环的时候,里面的匿名函数都会立即执行,然后var j = i,然后遇到setTimeout,把回调函数放进等待队列,j的引用也被放进去。值得注意的是,因为立即执行函数表达式也会创建函数作用域,这里就创建了5个不同的函数作用域。不同的函数作用域的变量存放地址不同,也就是说这里的j是5个不同地址的j,所以在输出的时候也会输出0,1,2,3,4

//(3)
for(var i = 0; i < 5; i++){
    (function(){
        var j = i
        setTimeout(function(){
            console.log(j)
        }, 1000)
    })()
}//0,1,2,3,4

设定一个 150ms 后执行的定时器不代表到了 150ms 代码就立刻执行,它表示代码会在 150ms 后被加入到队列中。如果在这个时间点上,队列中没有其他东西,那么这段代码就会被执行。 

15. 变量与变量重名、变量与函数重名问题

(1)变量与变量重名

如果仅声明则忽略

var a = 1
var a  //会忽略这个声明
console.log(a) //1

如果赋值了,则覆盖原值

var a = 1
var a = 2
console.log(a) //2

(2)变量与函数重名

变量与函数都存在变量提升的问题,例如以下代码

var a = 1
function a(){console.log('ha')}

这段代码在预解析的时候,会解析成这样:

function a() {}
var a

函数声明比变量声明提升到更高的位置,当处于预解析阶段时,内存分配过程应当是这样的:


预解析开始


第一行:为funcion a()分配空间,把function a的代码片放进去(注意此时a函数并没有执行,因为还没有被调用)

第二行:var a 声明a变量,此时a变量还没有类型,只是声明

变量a也是指向了同一块区域,此时变量a并没有赋值,所以没有类型。由于这块内存已经存放了一个函数类型的a,所以此时变量a的类型也应是函数。


预解析结束


此后,就会根据函数被调用的位置和变量被赋值的位置,决定a到底是个啥

(1)如果变量赋值在先:

var a 
function a(){console.log('a')}
a = 1
a() //报错,a不是一个函数

在第三行,a被赋值为1,那么上述属于a的空间,就会存进1,并且类型是Number,之前的函数类型会被覆盖,所以现在a是个变量,而不是一个函数,所以如果之后再调用函数a就会报错。

(2)如果函数调用在先

var a 
function a(){console.log('ha')}
a() //输出ha
a = 1
a()//报错,a不是一个函数

在代码运行到第三行时,a还是一个函数(变量a还没有被赋值),所以调用a可以成功,输出ha。第四行,a被赋值为1,此后a不再是一个函数了,而是一个变量,所以第五行执行a()会报错(a不是一个函数)

16.JS中的垃圾回收机制

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值