一道面试题让你与JS更近一步

这是一道面试题, 请先思考,在看讲解 :)

var param = 1;

function main()
{
    console.log(param);
    var param = 2;
    console.log(this.param);
    this.param = 3;
}

//下面两条语句分别会在控制台打印什么?
main();
var m = new main();

讲解如下:

1. main() , 打印的结果为: undefined1

a. >  来看第一个打印的值为什么是 undefined。 在js中,方法和变量的声明都是会提前的。也就是说不管你在何处声明的方法或者变量,在js解析时,都会将其提前,具体看代码

demo(); //此处能正常弹出 similar

function demo()
{
    alert("similar");
}

按照js的语句执行顺序,应该是从上自下依次执行的。 也就是说会先执行demo(), 然而这个时候demo()还没有声明,并不存在,应该报错才对,为什么还能正常弹出similar呢?这就前面说的方法声明在js解析时会提前。所以上面的代码,经过解析之后,就相当于

function demo()
{
    alert("similar");
}

demo(); //此处能正常弹出 similar

所以才会正常弹出 similar。 那么对于变量的声明也是一样的,会提前。 我们上面的代码,经过解析之后实际上等同于下面的代码

var param; //声明提前
param = 1;

function main()
{
    var param; //声明提前
    console.log(param); //因为此时 param 只是进行了声明,并未赋值,所以 打印的是 undefined
    param = 2;
    console.log(this.param);
    this.param = 3;
}

这里你或许会感到疑惑。我们在main()方法外面不是已经赋值为1了吗?  这是因为,我们在main()方法里面也定义了一个同名的 param。 就近原则,js会先查找自己有没有这个变量,如果有,就用自己的,如果没有就向上级查找,上级还有没有就到上上级去查找,如此循环,在哪找到,就在哪停止。如果全都没有,就返回undefined。 【这里涉及到一个知识点: js作用域链及变量查找, 之后我会写一篇于此相关的讲解文章】

b. > 现在我们再来看看第二打印的值为什么是1。 我将代码再做一次等价转换,这样或许大家就更容易明白缘由了,转换后代码如下

window.param = 1; //全局变量 param

// 全局方法 main()
window.main = function () {
    console.log(param);
    var param = 2;
    console.log(this.param);  //此时的this指代的就是 window, 因此 this.param = window.param = 1
    this.param = 3;
}
//调用全局方法main()
window.main(); 

看到这里,大家是否有些明白了呢?因为 main() 方法和 main() 方法外面的 param 都是定义在最外层的(没有包裹在其他对象里面),因此他们都是全局对象window下的成员。 当我们调用 main() 方法时, 实际上就是调用的 window.main();  而通过这样的方式调用时, this 指代的就是全局对象 window。 所以第二个打印的值为 1。【这里涉及到一个知识点: js中让人迷糊的this,之后我会写一篇于此相关的讲解文章】

2. var m = new main(), 打印的结果为: undefinedundefined

a. > 第一个打印的值为 undefined 的原因和上面的原因是一样的,都是因为变量声明提前导致的。

b. > 那么第二个打印的值也为 undefined 的原因是什么呢? Js也是支持面向对象式编程的语言,然而js中却没有类的概念,而是使用基于原型(prototype)的继承。 因此呢,js中的构造函数也很特别,一般情况下它和普通方法没什么区别,只有通过 new 关键字来调用的时候才能体现出其作为构造函数的功能。 而此处正是把 main() 和 new 关键字一起使用,说明此时的main()是一个构造函数。而构造函数中的 this 指代的就是新创建的对象,那么也就是 m 。

var param = 1;

function main()
{
    var param; //声明提前
    console.log(param); //因为此时 param 只是进行了声明,并未赋值,所以 打印的是 undefined
    param = 2;
    console.log(this.param); //构造函数中的this指代的是新创建的对象,我们这里新创建的对象是 m , 所以 this.param = m.param , 而此时 this.param 尚未赋值,所以打印的是 undefined (此处我自己也有一个疑问: 构造函数中的属性的声明会提前吗?也就是 this.param 的声明会提前吗? 求解)
    this.param = 3;
}

var m = new main();

说到底这里还是一个关于 js 中 this 的理解的问题,掌握了this , 此问题就很好理解了。现在都知道各中缘由了,是不是有种豁然开朗的感觉,哈哈...

时间: 2025-01-05 23:29:00

一道面试题让你与JS更近一步的相关文章

读完这几本Java书,离高手更近一步

首先说一下我个人的认识吧,我觉得高手应该是这样的: (1)精通Java基础知识与基础理论,熟悉JDK的发展史. (2)熟悉JVM,熟悉内存调试 (3)深刻理解Java的线程与并发包,以及背后的内存实现原理 (4)精通eclipse的使用,明白其中的插件的开发原理.深刻理解findbugs的缺陷模式. (5)熟悉SSH框架,并对源代码有足够的兴趣和研究. (6)熟悉数据缓存的原理与实现,MemCached客户端源码,mybatis源码都要涉猎. (7)了解足够的异步处理,定时处理,消息等知识. (

PC版微信真的来了,让沟通更近一步吧!

原文地址:PC版微信真的来了,让沟通更近一步吧 昨日晚间,微信正式推出Windows版本,抢占PC端口,至此QQ开始失去最后一个独占领地,与微信展开厮杀.一直以来,QQ作为公司与用户之间的主要联系方式,在公司与用户.公司之间的办公领地占据主要优势,随着微信在PC端的入侵,这种优势正在消失. 1月27日晚间,微信 PC 版正式上线 1.0 beta 公测版 ,包含网页版的聊天.传文件等基本功能,去年12月份,微信曾进行过小范围内测. Windows版微信相对于QQ界面更加简洁,在登录方式上也进行了

Dart更近一步,Sky会一统江湖吗?

从接触编程到现在,除了搞过几天JQuery,几乎没怎么写过Javascript,刚刚看了两篇介绍 ECMAScript6 的文章,突然觉得没写过JS也没什么好遗憾的. ES6 In Depth: An Introduction ES6 In Depth: Iterators and the for-of loop ES6 好像从2009年就开始制定了,现在终于支持 forEach.for-in等操作,也支持Map.Set等数据类型,而且为了考虑兼容性问题居然引入了一个 for-of,不过看到 G

一道面试题: C能申请的最大全局数组大小?

一道面试题: C能申请的最大全局数组大小?第一反应好像是4GB,但明显不对,代码和数据都要占空间,肯定到不了4GB.但是又想内存可以和硬盘数据交换,那到底是多少?应该是32位系统是理论上不能超过4GB(因为地址宽度4bytes,寻址的限制),实际中由于OS实现的细节会更少(比如Linux 1GB给了内核),而64位系统不超过2^64-1:内存大小最好大于数组长度,否则导致和磁盘交换数据,性能下降如果是局部变量,分配在栈上,空间会更小,取决于编译器 参考:http://stackoverflow.

送上今年微软的一道笔试题

这里送上一道微软的笔试题,具体题目如下: Time Limit: 10000msCase Time Limit: 1000msMemory Limit: 256MB Description Consider a string set that each of them consists of {0, 1} only. All strings in the set have the same number of 0s and 1s. Write a program to find and outp

从一道面试题(死循环里分配内存)阐述Linux的内存管理

题目: int cnt = 0; while(1) { ++cnt; ptr = (char *)malloc(1024*1024*128); if(ptr == NULL) { printf("%s\n", "is null"); break; } } printf("%d\n", cnt); 这个程序会有怎样的输出呢? 结果在Linux32位机是 is null 3057 为嘛是3057?? 因为用户态虚拟内存地址空间是3G. 3057M 大

一道面试题:说说进程和线程的区别

一道面试题:说说进程和线程的区别 在理解进程和线程概念之前首选要对并发有一定的感性认识,如果服务器同一时间内只能服务于一个客户端,其他客户端都再那里傻等的话,可见其性能的低下估计会被客户骂出翔来,因此并发编程应运而生,并发是网络编程中必须考虑的问题.实现并发的方式有多种:比如多进程.多线程.IO多路复用. 多进程 进程是资源(CPU.内存等)分配的基本单位,它是程序执行时的一个实例.程序运行时系统就会创建一个进程,并为它分配资源,然后把该进程放入进程就绪队列,进程调度器选中它的时候就会为它分配C

火柴棍移动的一道面试题

最近有朋友找工作,面试某公司,遇到一个火柴棍移动的面试题,感觉有点意思,在此抛砖引玉. 题目大致是这样的: 一个三个数的式子,移动其中一根火柴,使等式成立,用程序或实现(可以用伪码),输出能成立的等式. 注:"+"可以移走一根火柴变成"-" 例如: 废话不说,直接上代码,哪位网友有更好的方法,请分享一下,多谢 #include <stdio.h> /* 定义操作符号,"+"或"-" */ #define SYMBO

有关java类、对象初始化的话题,从一道面试题切入

最近在整理东西时,刚好碰到以前看的一道有关java类.对象初始化相关题目,觉得答案并不是非常好(记忆点比较差,不是很连贯).加上刚好复习完类加载全过程的五个阶段(加载-验证-准备-解析-初始化),所以如果周志明大大诚不我欺的话,无论是类加载过程.还是实例化过程的顺序我都已经了然于心了才对. 一道面试题 标题:2015携程JAVA工程师笔试题(基础却又没多少人做对的面向对象面试题) 地址:https://zhuanlan.zhihu.com/p/25746159 该题代码如下: public cl