我是靠谱客的博主 洁净老师,最近开发中收集的这篇文章主要介绍JavaScript中常见的看代码写结果例题(二),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

上一篇博客总结了几种典型的事件循环机制和原型链问题的例题,这篇文章来看下变量提升箭头函数闭包例题。

三、变量提升

现阶段的开发,需要大家掌握一些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的指向问题,这部分也是面试环节经常考的内容。

  1. 普通函数中this
    (1)总是代表着它的直接调用者,如obj.fn,fn里的最外层this就是指向obj
    (2)默认情况下,没有直接调用者,this指向window
    (3)严格模式下(设置了’use strict’),this为undefined
    (4)当使用call,apply,bind(ES5新增)绑定的,this指向绑定对象
  2. 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

五、闭包问题

问这个问题就可以看出你对闭包理解的深刻程度了. 如果只回答闭包的概念“能够读取其他函数内部变量的函数”就属于理解不透彻.如果能答出"词法作用域"、"内存泄漏"与"箭头函数"等关键词就可以锦上添花了!

闭包

  1. 闭包指的是闭包就是能够读取其他函数内部变量的函数。
  2. 在 JavaScript 中,闭包在每个函数被创建时形成。是由函数引用其周边状态(词法环境)绑在一起形成的(封装)组合结构。
  3. 要使用闭包,只需要简单地将一个函数定义在另一个函数内部,并将它暴露出来。要暴露一个函数,可以将它返回或者传给其他函数。
  4. 内部函数将能够访问到外部函数作用域中的变量,即使外部函数已经执行完毕。(变量缓存的效果)
    (创建闭包的常见方式,就是在一个函数A内部创建另一个函数B,那么函数B就是一个闭包,可以访问函数A作用域中的所有变量。)

作用域

  • 作用域就是变量的作用域:全局变量、局部变量(使用范围)

作用域链

  • 用链式查找的方式从子级作用域向父级作用域中寻找变量,就叫做作用域链。

5.1 例题

输出结果:

解析

  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 0

  2. b 执行过程:
    • 第一次调用第一层_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 2

  3. c 执行过程:
    • 在第一次调用第一层 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中常见的看代码写结果例题(二)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(64)

评论列表共有 0 条评论

立即
投稿
返回
顶部