JavaScript 进阶小细节-2

1. 构造函数返回属性时,属性的值为?

        function Car(){
            this.mark = "L"
            return {mark: "M"}
        }
        const myCar = new Car()
        console.log(myCar.mark);
        // M

返回属性的时候,属性的值等于返回的值,而不是构造函数中设定的值。

2. 修改引入的模块会怎样?

// counter.js
let counter = 10;
export default counter;
// index.js
import myCounter from "./counter";

myCounter += 1;

console.log(myCounter);
// Error

引入的模块是只读的,不能修改,只有导出他们的模块才能修改其值。当我们给myCounter增加一个值的时候会抛出一个异常: myCounter是只读的,不能被修改。

3. delete操作符可以删除哪些?返回什么?

        const name = "L"
        age = 20
        console.log(delete name);
        console.log(delete age);
        // false
        // true

delete操作符返回一个布尔值:true指删除成功,false指删除失败。
delete不能删除由var、let、const声明的变量;name变量由const关键字声明,所以删除不成功:返回 false。
delete可以删除对象的属性,而我们设定age等于21时,我们实际上添加了一个名为age的属性给全局对象。对象中的属性是可以删除的,全局对象也是如此,所以delete age返回true。

4. Object.defineProperty() 的默认不可枚举性

        const person = {name: "L"}

        Object.defineProperty(person, "age", {value: 21})
        console.log(person);
        console.log(Object.keys(person));
        // {name: "L", age: 21}
        // ['name']

通过defineProperty方法,我们可以给对象添加一个新属性,或者修改已经存在的属性。而我们使用defineProperty方法给对象添加了一个属性之后,属性默认为 不可枚举(not enumerable). Object.keys方法仅返回对象中 可枚举(enumerable) 的属性,因此只剩下了"name".
用defineProperty方法添加的属性默认不可变。你可以通过writable, configurable 和 enumerable属性来改变这一行为。这样的话, 相比于自己添加的属性,defineProperty方法添加的属性有了更多的控制权。

5. JSON.stringify()的第二个参数是?

        const settings = {
            username: "lydiahallie",
            level: 19,
            health: 90
        };
        const data = JSON.stringify(settings, ["level", "health"])
        console.log(data);
        console.log(typeof data);
        // "{level: 19, health: 90}"
        // string

JSON.stringify()的第二个参数是 替代者(replacer)。替代者(replacer)可以是个函数或数组,用以控制哪些值如何被转换为字符串。
如果替代者(replacer)是个 数组 ,那么就只有包含在数组中的属性将会被转化为字符串。在本例中,只有名为"level" 和 “health” 的属性被包括进来, "username"则被排除在外。 data 就等于 “{“level”:19, “health”:90}”.
而如果替代者(replacer)是个 函数,这个函数将被对象的每个属性都调用一遍。 函数返回的值会成为这个属性的值,最终体现在转化后的JSON字符串中(译者注:Chrome下,经过实验,如果所有属性均返回同一个值的时候有异常,会直接将返回值作为结果输出而不会输出JSON字符串),而如果返回值为undefined,则该属性会被排除在外。

6. ES6的函数参数默认值

    const value = {number: 10}
    const multiply = (x = {...value}) => {
        console.log(x.number *= 2);
    }
    multiply()
    multiply()
    multiply(value)
    multiply(value)
    // 20
    // 20
    // 20
    // 40

在ES6中,我们可以使用默认值初始化参数。如果没有给函数传参,或者传的参值为 “undefined” ,那么参数的值将是默认值。上述例子中,我们将 value 对象进行了解构并传到一个新对象中,因此 x 的默认值为 {number:10} 。
默认参数在调用时才会进行计算,每次调用函数时,都会创建一个新的对象。我们前两次调用 multiply 函数且不传递值,那么每一次 x 的默认值都为 {number:10} ,因此打印出该数字的乘积值为20。
第三次调用 multiply 时,我们传递了一个参数,即对象value。 *=运算符实际上是x.number = x.number * 2的简写,我们修改了x.number的值,并打印出值20。
第四次,我们再次传递value对象。 x.number之前被修改为20,所以x.number * = 2打印为40。

7. reduce的参数,acc和cur?

   [1,2,3,4].reduce((x,y)=>{console.log(x,y)})
   // 1 2
   // undefined 3
   // undefined 4

reducer 函数接收4个参数:
Accumulator (acc) (累计器)
Current Value (cur) (当前值)
Current Index (idx) (当前索引)
Source Array (src) (源数组)
reducer 函数的返回值将会分配给累计器,该返回值在数组的每个迭代中被记住,并最后成为最终的单个结果值。
reducer 函数还有一个可选参数initialValue, 该参数将作为第一次调用回调函数时的第一个参数的值。如果没有提供initialValue,则将使用数组中的第一个元素。
在上述例子,reduce方法接收的第一个参数(Accumulator)是x, 第二个参数(Current Value)是y。
在第一次调用时,累加器x为1,当前值“y”为2,打印出累加器和当前值:1和2。
例子中我们的回调函数没有返回任何值,只是打印累加器的值和当前值。如果函数没有返回值,则默认返回undefined。 在下一次调用时,累加器为undefined,当前值为“3”, 因此undefined和3被打印出。
在第四次调用时,回调函数依然没有返回值。 累加器再次为 undefined ,当前值为“4”。 undefined和4被打印出。

8. import导入的模块会先运行吗?

// index.js
console.log('running index.js');
import { sum } from './sum.js';
console.log(sum(1, 2));
// 'running sum.js'
// 'running index.js'
// 3

// sum.js
console.log('running sum.js');
export const sum = (a, b) => a + b;

import命令是编译阶段执行的,在代码运行之前。因此这意味着被导入的模块会先运行,而导入模块的文件会后执行。
这是CommonJS中require()和import之间的区别。使用require(),您可以在运行代码时根据需要加载依赖项。 如果我们使用require而不是import,running index.js,running sum.js,3会被依次打印。

9. 异步函数的返回值总是?

    async function getData(){
        return await Promise.resolve("I made it!")
    }
    const data = getData()
    console.log(data);
    // Promise {<pending>}

异步函数始终返回一个promise。await仍然需要等待promise的解决:当我们调用getData()并将其赋值给data,此时data为getData方法返回的一个挂起的promise,该promise并没有解决。
如果我们想要访问已解决的值"I made it!",可以在data上使用.then()方法:
data.then(res => console.log(res))
这样将打印 “I made it!”

10. 没有设置默认值时,函数参数值为?

function sayHi(name) {
  return `Hi there, ${name}`
}

console.log(sayHi())

默认情况下,如果不给函数传参,参数的值将为undefined。 上述情况,我们没有给参数name传值。 name等于undefined,并被打印。
在ES6中,我们可以使用默认参数覆盖此默认的undefined值。 例如:
function sayHi(name =“Lydia”){…}
在这种情况下,如果我们没有传递值或者如果我们传递undefined,name总是等于字符串Lydia

11. 注意const、let的块级作用域

function checkAge(age) {
  if (age < 18) {
    const message = "Sorry, you're too young."
  } else {
    const message = "Yay! You're old enough!"
  }

  return message
}

console.log(checkAge(21))
// ReferenceError

const和let声明的变量是具有块级作用域的,块是大括号({})之间的任何东西, 即上述情况if / else语句的花括号。 由于块级作用域,我们无法在声明的块之外引用变量,因此抛出ReferenceError。

12. 函数有多个形参,后面参数的默认值可以为前一个参数?

function sum(num1, num2 = num1) {
  console.log(num1 + num2)
}

sum(10)
// 20

您可以将默认参数的值设置为函数的另一个参数,只要另一个参数定义在其之前即可。 我们将值10传递给sum函数。 如果sum函数只接收1个参数,则意味着没有传递num2的值,这种情况下,num1的值等于传递的值10。 num2的默认值是num1的值,即10。 num1 + num2返回20。

13. 箭头函数有prototype吗?

    function fn(){
        return "hi"
    }
    const test = ()=>{return "hello"}
    console.log(fn.prototype);
    console.log(test.prototype);
    // {constructor: f}
    // undefined

常规函数,例如fn函数,有一个prototype属性,它是一个带有constructor属性的对象(原型对象)。 然而,箭头函数,例如test函数,没有这个prototype属性。 尝试使用test.prototype访问prototype属性时会返回undefined。

14. ES6的剩余参数

function getItems(fruitList, ...args, favoriteFruit) {
  return [...fruitList, ...args, favoriteFruit]
}

getItems(["banana", "apple"], "pear", "orange")
// SyntaxError

… args是剩余参数,剩余参数的值是一个包含所有剩余参数的数组,并且只能作为最后一个参数。上述示例中,剩余参数是第二个参数,这是不可能的,并会抛出语法错误。

15. 此类等于彼类?

    class Person {
        constructor(){
            this.name = "L"
        }
    }
    Person = class AnotherPeron {
        constructor(){
            this.name = "X"
        }
    }
    const members = new Person()
    console.log(members.name);
    // X

我们可以将类设置为等于其他类/函数构造函数。 在这种情况下,我们将Person设置为AnotherPerson。 这个构造函数的名字是X,所以新的Person实例members上的name属性是X。

16. Symbol除了表示唯一的值,你还知道什么?

const info = {
  [Symbol('a')]: 'b'
}

console.log(info)
console.log(Object.keys(info))
// {Symbol('a'): 'b'}
// []

Symbol类型是不可枚举的。Object.keys方法返回对象上的所有可枚举的键属性。Symbol类型是不可见的,并返回一个空数组。 记录整个对象时,所有属性都是可见的,甚至是不可枚举的属性。
这是Symbol的众多特性之一:除了表示完全唯一的值(防止对象意外名称冲突,例如当使用2个想要向同一对象添加属性的库时),您还可以隐藏这种方式对象的属性(尽管不完全。你仍然可以使用Object.getOwnPropertySymbols()方法访问 Symbol。

17. 箭头函数返回一个对象,还需要加圆括号?

const getList = ([x, ...y]) => [x, y]
const getUser = user => { name: user.name, age: user.age }

const list = [1, 2, 3, 4]
const user = { name: "Lydia", age: 21 }

console.log(getList(list))
console.log(getUser(user))
// [1,[2,3,4]]
// undefined

getList函数接收一个数组作为其参数。 在getList函数的括号之间,我们立即解构这个数组。 您可以将其视为:
[x, …y] = [1, 2, 3, 4]
使用剩余的参数… y,我们将所有剩余参数放在一个数组中。 在这种情况下,其余的参数是2,3和4。 y的值是一个数组,包含所有其余参数。 在这种情况下,x的值等于1,所以当我们打印[x,y]时,会打印[1,[2,3,4]]。
getUser函数接收一个对象。对于箭头函数,如果只返回一个值,我们不必编写花括号。但是,如果您想从一个箭头函数返回一个对象,您必须在圆括号之间编写它,否则不会返回任何值!下面的函数将返回一个对象:
const getUser = user => ({ name: user.name, age: user.age })
由于在这种情况下不返回任何值,因此该函数返回undefined。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值