写出下题的输出

1、函数的实参与形参length

var length = 10;
function fn() {
console.log(this.length);
}
var obj = {
length: 5,
method: function(fn) {
fn();
arguments[0]();
}
};
console.log(obj.method(fn, 1));  // 0 2

我们都知道,[1, 2, 3].length可以得到3,"123".length可以得到3,那么函数的length得到什么呢?

function test(a,b,c) {}
test.length // 3
function test(a,b,c,d) {}
test.length //

可以看到,函数的length似乎返回了参数的个数,那么对于形参和实参有没有区别呢?答案是有。

function test() { console.log( arguments.length );}
test(1,2,3); // 输出 3
test(1,2,3,4); // 输出 4

可以看到,在函数中,用arguments.length取到的是函数的实际参数的个数。

另外,我们要知道var length = 10 这样写是不行的,因为length是JavaScript内置的属性,不能用作变量名或函数名。戳这里http://www.runoob.com/js/js-reserved.html查看JavaScript有哪些保留关键字、内置属性等。

所以,当执行fn()时,this.length打印的是fn这个函数的形参的个数,为0;而执行arguments[0]()时,实际上是obj.method()这个方法的arguments调用了fn函数,this.length的this指向的是arguments,他的实际参数个数为2。

2、函数的解析与预解析过程(变量提升)

function fn(a) {
console.log(a); // function a() {alert(1)}
var a = 2;
function a() {alert(1)}
console.log(a); //
}
fn(1);

这道题还是挺吊炸天的。。我也想了半天。。下面我来讲一下,涉及到函数的解析和预解析过程。

首先遇到function fn这样的函数声明,会进行函数预解析这么个过程,什么是函数预解析?通俗的说就是,从函数体里找变量和函数声明的过程,找到的变量(遇到var就找到了变量)不会去读具体的值,只会赋为undefined;找到的函数声明会赋值为整个函数体,这里有个知识点就是,如果找到的变量和声明同名,那么声明会覆盖变量(我的理解是,毕竟函数体比undefined的强嘛)。

比如此例中,预解析时找到了变量a,并且赋值为undefined,找到了声明function a(){alert(1)},为整个函数体;两者同名,所以声明覆盖了变量a的值,a不再是undefined的,而是函数体。

预解析完成后调用了方法,开始一步一步走方法。首先console.log(a),这时打印出的是函数体;接着var a = 2,a的值从函数体被改成了 2 ;接着是个function a(){}函数声明,注意,声明不能改变变量的值,所以走完这一句,a的值还是2,接着打印出了2。

有人肯定有这样的疑惑,为什么a=1传进去没起作用呢?这里有一个原则,就是局部变量优先,基于这个原则,我们再来分析一下a的变化过程。预解析中,a=undefined,a=function(){alert(1)},此时参数有值等于1,本应该将a赋值为1,但却没有,原因是此时的a已经等于局部函数声明function(){alert(1)},所以外部传进来的参数1并没有取代a的值;假如本例没有function(){alert(1)}这一句,打印出的将是1,  2。

局部变量优先原则,原理同下:

var a = 5;
function fn(){
  var a = 10;
  console.log(a)  // 10,局部变量优先,在局部找到a后,不会再向外查找
}

3、变量提升、window的变量

if('a' in window) {
var a = 10;
}
console.log(a);  // 10

首先,if(){}的花括号并不像function(){}的花括号一样,具有自己的块级作用域,if的花括号还是全局的环境。根据JavaScript的变量提升机制,var a会被js引擎解释到第一行,如下:

var a;
if ('a' in window) {
a = 10;
}

接着有个知识点,全局变量是window对象的属性,所以'a'  in  window会返回true,答案就很直白了。

这道题我在做的时候踩了个坑,我在代码编辑器里写了如下代码:

window.onload = function(){
if('a' in window){
    var a = 10;
}
 console.log(a)  // undefined
}

这时候,a这个变量是定义在匿名函数function(){}里的,属于该函数的局部变量,所以a不再是window的对象。大家一定要注意细节。

4、基本类型无属性

var a = 10;
a.pro = 10;
console.log(a.pro + a);  // NaN
var s = 'hello';
s.pro = 'world';
console.log(s.pro + s)  // undefinedhello

变量a与s都是基本类型,无法给他们添加属性,所以a.pro和s.pro都是undefined。

undefined + 10 得到NaN(not a number)。

undefined + 'hello' 得到undefinedhello,其中undefined被转化为字符串类型。

如果实在想给字符串添加属性,我们需要将字符串定义为对象类型的字符串,如下:

var a= new String('objectString')
a.pro = "aaaaaaa"
console.log(a.pro) // aaaaaaa

5、async与await的执行

async function sayHello() {
console.log('Hello')
await sleep(1000)
console.log('world!')
}
function sleep(ms) {
 return new Promise(resolve => {
  console.log("666666");
  setTimeout(resolve, ms);
  console.log("888888")})
}
sayHello()  // hello 666666 888888 world!

async 表示这是一个async函数,await只能用在这个函数里面。

await 表示在这里等待promise返回结果了,再继续执行。

首先打出hello,到了await,会等待promise的返回,所以“world”不会立刻打出,接着进入sleep函数,打出666,接着开了一个1秒的定时器,虽然js是单线程的,但setTimeout是异步的,在浏览器中,异步操作都是被加入到一个称为“events loop”队列的地方,浏览器只会在所有同步代码执行完成之后采取循环读取的方式执行这里面的代码,所以resolve被加入任务队列,先打印了888,一秒后执行了resolve,表示promise成功返回,打出了world。

以上每道题都是本渣自己的想法和理解,如有不正确的地方烦请读者指正,大佬轻喷~

中高级JavaScript易错面试题的更多相关文章

  1. JavaScript易错知识点

    JavaScript易错知识点整理1.变量作用域上方的函数作用域中声明并赋值了a,且在console之上,所以遵循就近原则输出a等于2. 上方的函数作用域中虽然声明并赋值了a,但位于console之下 ...

  2. JavaScript易错知识点整理

    前言 本文是我学习JavaScript过程中收集与整理的一些易错知识点,将分别从变量作用域,类型比较,this指向,函数参数,闭包问题及对象拷贝与赋值这6个方面进行由浅入深的介绍和讲解,其中也涉及了一 ...

  3. JavaScript 易错知识点整理

    本文是我学习JavaScript过程中收集与整理的一些易错知识点,将分别从变量作用域,类型比较,this指向,函数参数,闭包问题及对象拷贝与赋值这6个方面进行由浅入深的介绍和讲解,其中也涉及了一些ES ...

  4. JavaScript易错点转载

    前言 本文是我学习JavaScript过程中收集与整理的一些易错知识点,将分别从变量作用域,类型比较,this指向,函数参数,闭包问题及对象拷贝与赋值这6个方面进行由浅入深的介绍和讲解,其中也涉及了一 ...

  5. 《java入门第一季》之面向对象(一个易错面试题)

    这个面试题有点难度,有一些饶.不明白可以在下面讨论.还是值得搞懂的. / * 看程序写结果: A:成员变量的问题 int x = 10; //成员变量x是基本类型 Student s = new St ...

  6. JavaScript易错知识点整理[转]

    前言 本文是我学习JavaScript过程中收集与整理的一些易错知识点,将分别从变量作用域,类型比较,this指向,函数参数,闭包问题及对象拷贝与赋值这6个方面进行由浅入深的介绍和讲解,其中也涉及了一 ...

  7. JavaScript易错点

    JavaScript知识点1.变量作用域   var a = 1;function test() {    var a = 2;     console.log(a); // 2} test();   ...

  8. 10道C++输出易错笔试题收集

    下面这些题目都是我之前准备笔试面试过程中积累的,大部分都是知名公司的笔试题,C++基础薄弱的很容易栽进去.我从中选了10道简单的题,C++初学者可以进来挑战下,C++大牛也可以作为娱乐玩下(比如下面的 ...

  9. JavaScript易错点 -- 数组比较

    记得当初初学JavaScript时尝试用“==”或“===”比较两个数组是否相等, var a = [1,2,3] var b = [1,2,3] if(a == b){ //false //do s ...

随机推荐

  1. 作为一个C#程序员, 你应该上手Kotlin

    Kotlin最近火了, 在Google IO大会 Kotlin宣布Kotlin将会成为Android官方开发语言之后, Kotlin这样一个JVM上的新*(其实从诞生到现在已经有5年历史的)语言. 终 ...

  2. GCD之死锁体会

    1.先看下几句代码 1 2 3 4 5 6 7 dispatch_queue_t serialqueue=dispatch_queue_create("serialqueue", ...

  3. 关于离线底图和离线shp文件的加载

    首先底图是我自己用百度地图18级别的瓦片图在armap中制作的TPK文件,shp图层是我用同样的百度地图18级别的瓦片图矢量化的,二者在arcmap中的空间参考是一致的,所以我以为在移动端加入的时候二 ...

  4. 关于xamarin.forms 中 list 的loadmore

    前言 最近几天在研究上拉加载啊,下拉刷新啊什么的.然而坑爹的事情总是那么多.在xamarin.forms中,list自带的,并没有上拉加载的这个属性(难道当初他们封装方法时,就不会想到数据多了会咋整吗 ...

  5. 聊聊Java语言中的单例

    package com.xinke.mybatis.test; public class TestSingleton { private static TestSingleton ts = null; ...

  6. 配置zabbix agent向多个server发送数据

    1.背景: agent 端:dba-test-hzj02  172.16.59.197 server端:172.16.59.197  ,172.16.59.98 2.方式: 配置多个server,se ...

  7. 玩转INotifyPropertyChanged和ObservableCollection

    转载:   http://www.cnblogs.com/Jax/archive/2009/10/13/1582128.html 本文的代码都是基于WPF的,对于Silverlight,这些技术也同样 ...

  8. 使用beanstalkd实现定制化持续集成过程中pipeline

    持续集成是一种项目管理和流程模型,依赖于团队中各个角色的配合.各个角色的意识和配合不是一朝一夕能练就的,我们的工作只是提供一种方案和能力,这就是持续集成能力的服务化.而在做持续集成能力服务化的过程中, ...

  9. opencv-python:win7下,搭建python2.7.5环境,配置opencv3.1.0准备开工-OpenCV步步精深

    我的个人博客:点这里 搭建python2.7.5环境 下载python2.7.5 64位:https://www.python.org/ftp/python/2.7.5/python-2.7.5.am ...

  10. 广州图书馆借阅抓取——httpClient的使用

    欢迎访问我的个人网站,要是能在GitHub上对网站源码给个star就更好了. 搭建自己的网站的时候,想把自己读过借过的书都想记录一下,大学也做过自己学校的借书记录的爬取,但是数据库删掉了==,只保留一 ...