前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >10个例子,深入了解JavaScript

10个例子,深入了解JavaScript

作者头像
学前端
发布2020-04-07 15:44:32
5150
发布2020-04-07 15:44:32
举报
文章被收录于专栏:前端之巅

本文原文来自 Medium ,本文仅进行翻译,如需转载请注明来源!

介绍

作为一门灵活的编程语言,JS中有很多缺陷,这很可能被人们所忽略,而产生很大的失误,在本文中,我们将通过10个容易出错的示例来学习JS语法的一些关键部分,有些甚至是现实世界中的错误,而某些示例则直接来自于JS的基本语法。

示例1 Object Destructing

看以下代码,回答问题:

代码语言:javascript
复制
const { var1: a, var2, var3 = 10 } = { var1: 2, var2: NaN, var3: 5 };

function testFn(){
  let sum = 0;
  for(const ele of arguments){
    if(ele !== ele) break;
    else sum += ele;
  }
  return sum;
}

const res = testFn(a,var2,var3);
console.log(res);

该代码的输出是什么?

(1) 12 (2) NaN (3) 2 (4) 7

语法说明

  • 不同形式的Object Destructing
  • 可以从ES5的argument变量中检索输入参数(可以将代码改为箭头函数,看看会发生什么)
  • NaN 是唯一不等于它本身的值
答案 (3)

示例2 逻辑运算符

看以下代码,回答问题:

代码语言:javascript
复制
function testFn(){
  const a = {} && -1 || 0;
  console.log(a / 0);
}

testFn();

该代码将会输出什么?

(1) false (2) Error (3) NaN (4)-Infinity

语法说明

  • 与其他编程语言不同,JS中的逻辑运算符&&或是||返回最后检查的值,而不是简单的布尔值
  • 在JS 中 :'',null,NaN,-0,0,+0,false都是Falsy值
  • 在JS中将一个非零数字除以0会产生-InfinityInfinity代替抛出错误
答案(4)

示例3 一元运算符和强制转换

看以下代码,回答问题:

代码语言:javascript
复制
function testFn(){
    const a = "3.14";
    const b = -a - + - + 3.14;
    const c = a + + - + 3.14;
    console.log(b + c);
}

testFn();

该代码将会输出什么?(1) 3.14 (2) "03.14-3.14" (3) NaN (4)-3.14

语法说明

  • 一元运算符的关联性是从右到左
  • 一元运算符+,-可用于字符串到数字的强制转换
  • +运算符和数字之间使用的运算符会将数字强制为字符串值
答案(2)

###示例4 Promise 流控制

看以下代码,回答问题:

代码语言:javascript
复制
function testFn(){
    const p = new Promise((rsv,rjt) => {
      console.log("1");
      rsv();
    }).then(res => {
      console.log("2");
      setTimeout(() => {
        console.log("3");
      }, 0);
    });
    console.log("4");
    setTimeout(() => {
      console.log("5");
    }, 0);
    console.log("6");
}

testFn();

该代码将会输出什么?

代码语言:javascript
复制
(1) > "1" > "4" > "6" > "2" > "5" > "3"

(2) > "4" > "6" > "1" > "5" > "2" > "3"

(3) > "1" > "4" > "6" > "2" > "3" > "5"

(4) > "1" > "4" > "6" > "5" > "2" > "3"

语法说明

  • Promise将保留在调用堆栈的初始位置
  • setTimeout()将放置在调用堆栈的末尾
答案(1)

示例5 异步函数错误处理

看以下代码,回答问题:

代码语言:javascript
复制
function testFn(fn){
  try{
    fn();
  }catch(err) {
    console.log("Error caught: ", err.message);
  }
}

function innerFn(){
  throw Error("Error from Synchronous Fn");
}

async function innerAsyncFn(){
    throw Error('Error from Asynchronous Fn');
}

testFn(innerFn);
testFn(innerAsyncFn);

以下哪个是输出的内容?

(1) Error caught: Error from Synchronous Fn Error caught: Error from Asynchronous Fn

(2) Error caught: Error from Synchronous Fn Uncaught (in promise) Error: Error from Asynchronous Fn

(3) Uncaught Error: Error from Synchronous Fn Uncaught (in promise) Error: Error from Asynchronous Fn

(4) Uncaught Error: Error from Synchronous Fn Error caught: Error from Asynchronous Fn

语法说明

  • 从异步函数引发的错误将被包装到一个被拒绝的promise中,它等效于 return new Promise.reject(Error('msg')) 被拒绝的Promise将在Promise.catch()中进行处理.
  • 从同步函数引发的错误将被视为Uncaught Error,如果try{}catch(e){}在当前函数范围内未被处理,则将引发该错误到函数调用的外部范围
答案(2)

示例6 异步函数作为范围

看以下代码,回答问题:

代码语言:javascript
复制

async function testFn(){
    console.log('start');
    const sampleArr = [1, 2, 3];
    for(const ele of sampleArr){
        const val = await ele;
        console.log(val);
    }
    console.log('end');
}

testFn();

以下哪个是输出的值?

代码语言:javascript
复制
(1)
'start'
1
2
3
'end'
(2)
'start'
'end'
1
2
3

如果使用以下做法呢?

代码语言:javascript
复制
async function testFn(){
    console.log('start');
    const sampleArr = [1, 2, 3];
    sampleArr.forEach(async ele => {
        const val = await ele;
        console.log(val);
    });
    console.log('end');
}

testFn();

语法说明

  • asyncawait可以成对使用(尽管async可以是多个await),这意味着await关键字将仅使其对应async函数的执行同步。如果将异步函数作为参数传递给第三方函数处理程序,那么该第三方函数处理程序在当前作用域中将变为黑色,并且将会失去对异步函数的控制。
  • 在第二段代码中,将async箭头函数传递给.forEach()函数,因此await仅在异步箭头函数的作用域内起作用。但是在第一段代码中,for循环没有作用域范围,这意味着 await可以和该函数的作用域一起使用。
答案 第一段(1) 第二段(2)

示例7 闭包和this的绑定

代码语言:javascript
复制
var obj1 = {
    name: "John Wick",
    gender: "male",
    myFn: function(val){
        var innerFn = function(val2){
            console.log(val, val2, this.name);
        }.bind(this);

        return innerFn;
    }
};

var obj2 = {
    name: "Trinity",
    gender: "female"
};

obj2.testFn = obj1.myFn;
obj2.testFn("Hello")("World");

看看以下哪个是输出结果

(1) undefined "World" "John Wick" (2) "Hello" "World" "John Wick" (3) undefined "World" "Trinity" (4) "Hello" "World" "Trinity"

语法说明

  • 函数是一个对象,JS中的对象分配是引用分配。this关键字始终指向引用当前函数的对象
  • val内部变量innerFn引用外部作用域的变量val。此引用是从一个作用域范围到外部范围的引用。
  • .bind(this)强制绑定innerFn到其外部范围的调用函数
答案 (4)

示例8 ...展开运算符

代码语言:javascript
复制
const object1 = {a: 1, b: 2, c: 3};
const object2 = Object.create(object1,{
  d: {
    value: 4,
    enumerable: true
  }
});
object2.e = 5;
const newObj = {
    ...object2
};
console.log("new obj: ", newObj);

//Array spreading
const array1 = ['a', 'b', 'c'];
const array2 = Object.create(array1,{
  3: {
    value: 'd',
    enumerable: true
  }
});

const newArr = [...array2];
console.log("new arr:", newArr);

以下哪个是输出的结果?

代码语言:javascript
复制
(1)
new obj: {d: 4, e: 5}
new arr: ["a", "b", "c"]
(2)
new obj: {a: 1, b: 2, c: 3, d: 4, e: 5}
new arr: ["a", "b", "c", "d"]
(3)
new obj: {a: 1, b: 2, c: 3, d: 4, e: 5}
new arr: ["a", "b", "c"]
(4)
new obj: {d: 4, e: 5}
new arr: ["a", "b", "c", "d"]

语法说明

  • ...扩展操作符在对象上使用仅迭代对象自身的属性,类似于for (const prop in Object.keys(obj))。另一方面,for ( const prop in obj) 将仅迭代原型链中的所有属性。
  • ...在数组上使用时将遍历数组对象的原型链中的所有可迭代的元素,类似于for (const ele of arr)
答案 (1)

示例9 null和对象

代码语言:javascript
复制
{
const valArr = [null || 0, {}, null];
function testFn(val) {
    switch (typeof val){
        case "object":
         console.log("object");
         break;
        case "number":
         console.log("number");
         break;
        case "null":
         console.log("null");
         break;
        default:
         break;
    }
};
valArr.forEach(testFn);
}

以下哪个是输出的结果?

(1) "number" "object" "null" (2) "null" "object" "object" (3) "number" "object" "object" (4) "null" "object" "null"

语法说明

  • null 在JS中也是一个对象
  • ||操作返回最后的检查值0 即使0是一个falsy值
答案 (3)

示例10 对象克隆

代码语言:javascript
复制

const obj1 = {
    name: "John Wick",
    gender: "male"
};
const obj2 = Object.assign({}, obj1);
const obj3 = obj1;
const obj4 = {
    ...obj1
};
 console.log(obj1 === obj2);
 console.log(obj1 === obj3);
 console.log(obj1 === obj4);

以下哪个是输出的内容?

(1) true true false (2) false true true (3) false false false (4) false true false

语法说明

  • =用于对象分配的是分配对象引用(浅拷贝),而不是将对象真正复制到新对象(深拷贝)。要使用深拷贝,就要用Object.assign()...运算符
  • === 逻辑运算符在对象上使用时将检查两个对象是否都引用相同的对象内存。
答案 (4)

总结

希望看完了本文之后,能够学习到一些新的内容,当然,在本文中有许多知识并不需要讲(例如深拷贝,Promise等等),这些内容大家可以在很多地方看到。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-12-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 一起学前端 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 介绍
    • 示例1 Object Destructing
      • 语法说明
        • 答案 (3)
      • 示例2 逻辑运算符
        • 语法说明
          • 答案(4)
        • 示例3 一元运算符和强制转换
          • 语法说明
            • 答案(2)
          • 语法说明
            • 答案(1)
          • 示例5 异步函数错误处理
            • 语法说明
              • 答案(2)
            • 示例6 异步函数作为范围
              • 语法说明
                • 答案 第一段(1) 第二段(2)
              • 示例7 闭包和this的绑定
                • 语法说明
                  • 答案 (4)
                • 示例8 ...展开运算符
                  • 语法说明
                    • 答案 (1)
                  • 示例9 null和对象
                    • 语法说明
                      • 答案 (3)
                    • 示例10 对象克隆
                      • 语法说明
                        • 答案 (4)
                    • 总结
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档