概述
上一篇博客总结了几种典型的事件循环机制和原型链问题的例题,这篇文章来看下变量提升、箭头函数和闭包例题。
三、变量提升
现阶段的开发,需要大家掌握一些ES6新特性,其中块级变量let、块级常量const和var一样,都是用来声明变量,解决变量提升问题。
let和const特点:
i. 没有变量的提升(Js是弱语言,使用var变量再后声明,在执行中会对变量预解析,而let不会)
ii. 同一个作用不能重复定义同一个名称(var会覆盖、let会报错)
iii. 有严格的作用域(var属于函作用域(在该函数中都可以调用、起作用)、let是块级作用域(只在{}之间起作用))
3.1 例题
const w=100;
w=200;
console.log(w); //不可以,不可以更改
解析
const这里是引用声明一个只读的常量,一旦声明,常量的值不可以改变
3.2 例题
const w; //报错
const obj={};
obj.name="amy";
console.log(obj); //正确输出
解析
一定要初始化,不能只声明不赋值(这里指的是字符、字符串、数字,【数组、对象属于引用,可以后赋值】)
3.3 例题
输出结果:
解析
1、两个数组进行大小比较,也就是两个对象进行比较。
当两个对象进行比较时,会转为原始类型的值,算法是先调用 valueOf 方法;如果返回的还是对象,再接着调用 toString 方法。
2、JavaScript 有两种比较方式,严格比较运算符和转换类型比较运算符。
对于严格比较运算符===
来说,仅当两个操作数的类型相同且值相等为 true ,而对于被广泛使用的比较运算符==
来说,会在进行比较之前,将两个操作数转换成相同的类型。对于关系运算符(比如<=)来说,会先将操作数转换成原始值,使他们类型相同,再进行比较运算。
3、当两个操作数都是对象时,JavaScript 会比较其内部的引用,当且仅当他们的引用指向内存中的相同对象(区域)时才相等,即他们在栈内存中的引用地址相同。
JavaScript 中的 Array 也是对象,所以这里 a , b , c 的引用显然是不相同的,所以这里 a == b , a=== b 都为 false 。
3.4 例题
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 1);
}
for (var j = 0; j < 3; j++) {
setTimeout(() => console.log(j), 1);
}
输出结果:
0,1,2
3,3,3
四、箭头函数
箭头函数也是ES6中一个必须掌握的新特性,箭头函数简化了函数的定义,ES5中函数和ES6中箭头函数的写法如下:
ES5
var foo = function(a) {
return a;
}
console.log(foo(5));
等价于与:
ES6
let foo = a => a; // 函数名=参数=》返回值(函数体)
console.log(foo(5));
解析
提到箭头函数,通常会让你区分和普通函数的区别,以及箭头函数中this的指向问题,这部分也是面试环节经常考的内容。
- 普通函数中this
(1)总是代表着它的直接调用者,如obj.fn,fn里的最外层this就是指向obj
(2)默认情况下,没有直接调用者,this指向window
(3)严格模式下(设置了’use strict’),this为undefined
(4)当使用call,apply,bind(ES5新增)绑定的,this指向绑定对象- ES6箭头函数中this
(1)默认指向定义它时,所处上下文的对象的this指向。即ES6箭头函数里this的指向就是上下文里对象this指向,偶尔没有上下文对象,this就指向window
(2)即使是call,apply,bind等方法也不能改变箭头函数this的指向
4.1 例题
function test1(){
console.log(test1.prototype);
}
var test2=()=>{
console.log(test2.prototypee);
}
test1();
test2();
输出结果:
constructor function Object
undefined
解析
箭头函数没有函数原型,所以箭头函数本身没有this,它的this永远指向上下文this的指向。
4.2 例题
var object = {
a:1,
b:()=>{
console.log(this.a)
console.log(this)
},
c:function(){
console.log(this.a)
console.log(this)
}
}
object.b();
object.c();
输出结果:
undefined
Window {postMessage: f, blur: f, foucs:f, close: f, frames: Window, ... }
1
Object { a: 1, b: b(), c: c() }
解析
1、箭头函数不绑定this,会捕捉其所在上下文的this值,作为自己的this值。
2、箭头函数this指向在定义的时候继承自外层第一个普通函数大的this。
3、任何函数都改变不了其this指向问题,如call()、apply()、bind()函数,但普通函数this指向调用它的哪个对象。
4.3 例题
let test3 = ()=>{
console.log(this);
}
let test4 = new test3();
输出结果:
Uncaught TypeError: test3 is not a constructor
解析
箭头函数是匿名函数,不能作为构造函数,不能使用new。
4.4 例题
function f(a){
console.log(arguments);
}
f(1,2,3,4);
let f1 = a => {
console.log(arguments);
}
f1(5,6,7,8);
let f2 = (...a) => {
console.log(arguments);
}
f2(6,7,8,9);
输出结果:
1,2,3,4
arguments is not defined
6,7,8,9
解析
箭头函数不绑定arguments,取而代之可以用rest(…)函数代替
4.5 例题
const obj = {
test: '123',
f1: () => {
console.log(this.test)
},
f2: function () {
console.log(this.test)
},
}
obj.f1()
obj.f2()
new obj.f1()
new obj.f2()
输出结果:
undefined
123
报错
undefined
五、闭包问题
问这个问题就可以看出你对闭包理解的深刻程度了. 如果只回答闭包的概念“能够读取其他函数内部变量的函数”就属于理解不透彻.如果能答出"词法作用域"、"内存泄漏"与"箭头函数"等关键词就可以锦上添花了!
闭包
- 闭包指的是闭包就是能够读取其他函数内部变量的函数。
- 在 JavaScript 中,闭包在每个函数被创建时形成。是由函数引用其周边状态(词法环境)绑在一起形成的(封装)组合结构。
- 要使用闭包,只需要简单地将一个函数定义在另一个函数内部,并将它暴露出来。要暴露一个函数,可以将它返回或者传给其他函数。
- 内部函数将能够访问到外部函数作用域中的变量,即使外部函数已经执行完毕。(变量缓存的效果)
(创建闭包的常见方式,就是在一个函数A内部创建另一个函数B,那么函数B就是一个闭包,可以访问函数A作用域中的所有变量。)作用域
- 作用域就是变量的作用域:全局变量、局部变量(使用范围)
作用域链
- 用链式查找的方式从子级作用域向父级作用域中寻找变量,就叫做作用域链。
5.1 例题
输出结果:
解析
a 执行过程:
• const a = fn(0);调用最外层的函数,只传入了 n,所以打印 o 是 undefined
• a.fn(1);调用了 fn(1) 时 m 为 1 ,此时 fn 闭包了外层函数的 n ,也就是第一次调用的 n=0 ,即 m =1 ,n= 0,并在内部调用第一层 fn(1,0);所以 o 为 0;
• a.fn(2);调用 fn(2) 时 m 为 2 ,但依然是调用 a.fn,所以还是闭包了第一次调用时的 n ,所以内部调用第一层的 fn(2,0);所以 o 为 0
• a.fn(3);同上
所以结果是 undefined 0 0 0b 执行过程:
• 第一次调用第一层_fn_(0) 时,o 为 undefined
• 第二次调用 .fn(1) 时 m 为 1,此时 fn 闭包了外层函数的 n ,也就是第一次调用的 n=0,即 m=1,n=0,并在内部调用第一层的_fn_(1,0);所以 o 为 0;
• 第三次调用 .fn(2) 时 m 为 2,此时当前的 fn 函数不是第一次执行的返回对象,而是第二次执行的返回对象。而在第二次第一层 fn(1,0) 时,n=1,o=0,返回时闭包了第二次的 n,所以在第三次调用第三层的 fn 函数时,m=2,n=1,即调用第一层 fn(2,1) 函数,所以 o 为 1;
• 第四次调用 .fn(3) 时 m=3,闭包了第三次的 n ,同理,最终调用第一层 fn(3,2);所以 o 为 2
所以结果为: undefined 0 1 2c 执行过程:
• 在第一次调用第一层 fn(0) 时,o 为 undefined
• 在第二次调用, .fn(1) 时,m 为 1,此时 fn 闭包了外层函数的 n ,也就是第一次调用的 n=0,即 m=1,n=0,并在内部调用第一层 fn(1,0);所以 o 为 0
• 第三次调用, .fn(2) 时 m=2,此时 fn 闭包的是第二次调用的 n=1,即 m=2,n=1,并在内部调用第一层 fn(2,1);所以 o 为 1
• 第四次 .fn(3) 时同理,但依然时调用第二次的返回值,所以最终调用第一层的 fn(3,1),所以 o 为 1
所以结果是 undefined 0 1 1
最后
以上就是洁净老师为你收集整理的JavaScript中常见的看代码写结果例题(二)的全部内容,希望文章能够帮你解决JavaScript中常见的看代码写结果例题(二)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复