上篇博客JavaScript面试时候的坑洼沟洄——数据类型总结了一下JavaScript数据类型几转换的相关知识,很多朋友可能和我一样,买了书后对数据类型啊、运算符啊、语句啊都是扫两眼或直接略过的,自己为搞定原型、闭包、作用域链就可以秒杀JavaScript笔试题,结果一次次死在毫不起眼的基础知识上,看似平淡无奇实则暗流涌动,一不小心就会栽倒。好了不扯淡了,回正题

神马是表达式

表达式是由数字、运算符、数字分组符号(如括号)、自由变量和约束变量等以能求得数值的有意义排列方法所得的组合。~~约束变量在表达式中已被指定数值,而自由变量则可以在表达式之外另行指定数值。一个表达式代表一个函数,其输入为自由变量的定值,而其输出则为表达式因之后所产生出的数值。 ——维基百科

看起来很不接地气的赶脚,表达式是JavaScript中的一个短语,JavaScript会将其计算出一个结果,常量如1、"hello"、null这些都是表达式;变量名也是表达式,JavaScript计算出的结果就是赋值给变量的值,这些都是简单的表达式,几个简单的表达式可以组合为复杂的表达式,[3,4,5,6]这也是一个表达式,计算结果是数组,我们也可以通过运算符将简单表达式组合位复杂表达式,8+9这样,JavaScript表达式有几种形式

  1. 原始表达式

    常量、变量、保留字

  2. 对象、数组初始化表达式

    var obj={a:1,b:2};
    var a=[1,2,3];

  3. 函数定义表达式

    var fn=function(){}

  4. 属性访问表达式

    Math.abs

  5. 调用表达式

    alert('hello');

  6. 对象创建表达式

    new object();

函数定义

我们想使用一个函数的时候通常有几种做法

  1. 函数表达式

    函数表达式中函数名称并不是必需的,所以我们经常这么使用
    var fn=function(n) { console.log(n) };

  2. 函数声明

    更常见的做法是这样
    function fn(n){ console.log(n);}

  3. 使用Function构造函数

    偶尔也会这样 var fn=new Function('n',"console.log(n);");

这几种做法都很好理解,但是如果函数表达式使用了名字呢,我们看个题目

var f = function g(){ console.log(g);};
f();//function g(){ console.log(g);};
typeof g();//g is not defined

不知道结果和同学们的预期是否一致,但看起来这种结果似乎互相矛盾,当我们使用函数声明的方式定义一个函数的时候,实际上声明了一个变量,在上面例子中就是f,并把函数赋值给这个变量,普通的函数表达式没有创建该变量,也就是我们所说的创建了一个匿名函数,但是如果函数表达式包含名称,也就是上面例子的g,那么函数的局部作用域将包含将包含该名称,并且把创建的函数绑定到该名称上,在上面例子中g变成了函数的局部变量,变量指向函数本身,所以我们调用f的时候会把其本身打印出来。但是g只作为函数的局部变量存在,我们在外部调用g的时候就会报错了。

命名函数表达式在创建的时候,会在当前作用域最前段添加一个新的对象
{func_name:refer_function_expression},然后,将作用域链添加到
函数表达式的[[scope]]中,接着在删除该对象。

看个题目

var x=1;
if(function f(){}){x+=typeof f;
}
console.log(x);//'1undefined'

是不是觉得自然就能想到答案了

立即执行函数

初学JavaScript的同学很容易被类似这样的东西唬住

(function(){})();

其实我们了解了表达式就能很清楚的看明白这是什么结构了

(函数定义表达式)函数调用表达式

也就是说先创建了一个匿名函数,然后不传入参数调用它,这就变成了“立即执行函数”,知道了这些看个传入参数调用的立即执行函数题目

(function f(f){return typeof f();// "number"
})(function(){return 1;});

这个题目事实上还涉及了一些其它的知识,立即执行函数不再是以空括号()来调用了,同事传入了一个function作为参数传入调用。再一个疑惑就是typeof f() 中的f究竟指谁,这个知识我们后面会介绍道,简单说一下,当函数执行有命名冲突的时候,函数依次填入 变量=》函数=》参数,所以最后被填入的参数f会覆盖函数定义f,typeof f()是对参数的调用,参数是立即执行函数传入的function参数,返回数字1,typeof 1是 "number"。

表达式返回值

表达式看明白了,我们却经常忽略其计算结果,也就是我们常说的返回值,对于原始表达式、对象数组初始化表达式、属性访问表达式很简单不会有什么问题。

函数定义表达式返回的是函数对象本身,我们在调用alert或者console.log的时候会调用其toString方法

console.log(function(){alert('a');}) //function (){alert('a');}

函数调用表达式自然是返回函数的return结果,但在JavaScript中并不是所有的函数都有return语句,对于没有return语句的function,其调用表达式返回undefined,对于只写个return的坑爹做法同样也是返回undefined

(function(){})(); //undefined
(function(){return;})();//undefined

对象创建表达式本来也应该很简单,返回new的对象就可以了

typeof new Date(); //"object"

但是总有特殊的,看个题目

function Test(){return new Date();
}
var test=new Test();
console.log(test instanceof Test);//false
console.log(test);//Sat Jan 18 2014 14:57:08 GMT+0800 (CST) 

很奇怪啊,new Test()没有返回Test的实例对象,返回的却是Date对象,这是为什么呢?是不是有返回值的function使用构造函数的时候就会返回return指令的结果呢?看个例子

function Test(){return new Date();
}
function Test2(){return 2;
}
typeof new Test();
new Test2() instanceof Test2;//true,竟然是true

刚才的推测明显不正确,Test2有返回值,new test2() 返回的是Test2的实例,但是我们已经可以看出一丝端倪了

当使用function的构造函数创建对象(new XXX)的时候,如果函数return基本类型或者没有return(其实就是return undefined)的时候, new 返回的是对象的实例;如果 函数return的是一个对象,那么new 将返回这个对象而不是函数实例。

这里千万别把构造函数(使用new)和普通函数调用混淆了,普通函数调用还是该返回什么返回什么的。看个题目

'foo' == new function(){ return String('foo'); }; //false
'foo' == new function(){ return new String('foo'); };//true

怎么样,答对没有?

正则表达式

关于表达式还有一个重点没有说——正则表达式,相关内容已经总结位单独博客,有兴趣同学可以看看

JavaScript 正则表达式上——基本语法

JavaScript正则表达式下——相关方法

运算符

JavaScript中运算符主要用于连接简单表达式,组成一个复杂的表达式。常见的有算数表达式、比较表达式、逻辑表达式、赋值表达式等,也有单目运算符,指操作原始表达式。大多数运算符都由标点符号组成(+、>=、!),也有关键字表示的运算符,如typeof、delete、instanceof等。

一些运算符可以作用于任何数据类型(typeof),但大部分操作符“希望”操作数是特定的类型,而且大部分操作符会计算出(我们也常说返回)一个特定类型的值(typeof返回的全是string)。在JavaScript中运算符通常会根据需要对操作数进行类型转换,乘法操作符 "" 希望操作数是数字,但是 "3""5"也是合法的,JavaScript会自动将其转换为数字计算,返回Number 15。

有些操作符对不同的数据类型有不同的含义,比如 "+"

console.log(2+4);//6
console.log("2"+"4");//"24"
console.log(2+"4");//"24"
console.log(2+new Date());//"2Mon Jan 20 2014 17:15:01 GMT+0800 (China Standard Time)"
console.log(+"4");//4 
  • 在两个操作数都是数字的时候,会做加法运算
  • 两个参数都是字符串或在有一个参数是字符串的情况下会把另外一个参数转换为字符串做字符串拼接
  • 在参数有对象的情况下会调用其valueOf或toString
  • 在只有一个字符串参数的时候会尝试将其转换为数字
  • 在只有一个数字参数的时候返回其正数值

运算符优先级与结合性

优先级什么意思大家都清楚,结合性是指多个具有同样优先级的运算符表达式中的运算顺序。有的运算符是左结合的,即运算从左到右执行,下面两个运算是一样的

w=x+y+z;
w=(x+y)+z;

有的运算符是右结合的

w=x=y=z;
w=(x=(y=z));
w=a:b:c?d:e?f:g;
w=a?b:(c?d:(e?f:g));

运算符的优先级《JavaScript权威指南》中有个表阐述的很好(我去掉了位运算部分),其中R/L代表结合性是右结合还是左结合,num->num表示操作符期望的数据类型和计算结果类型,lval指左值

运算符 操作 结合性 类型
++ 自增 R lval->num
-- 自减 R lval->num
- 求反 R num->num
+(一个操作数) 转换为数字 R num->num
~ 按位求反 R int->int
! 逻辑非 R bool->bool
delete 删除属性 R lval->bool
typeof 检测数据类型 R any->str
void 返回undefined R any->undefined

*、/、% 乘、除、求余 L num,num->num

+、- 加、减 L num,num->num
+ 字符串拼接 L str,str->str
、>= 数字大小或字母表顺序 L num/str,num/str->bool
instanceof 对象类型 L obj,function->bool
in 测试属性是否存在 L str,obj->bool

== 判断相等 L any,any->bool
!= 判断不等 L any,any->bool
=== 判断恒等 L any,any->bool
!== 判断非恒等 L any,any->bool

&& 逻辑与 L any,any->any
|| 逻辑或 L any,any->any
?: 条件运算符 R bool,any,any->any
=赋值 *=、/=、+=、-= 赋值 运算且赋值 R lval,any->any
, 忽略第一个操作数,返回第二个操作数 L any,any->any

有几个我们需要注意的地方

  • typeof的优先级相当的高,比加减乘除神马的都高,所以虽然是操作符,在在复杂表达式的时候我们还是习惯家括号,看个例子
typeof 2*3;//NaN
typeof (2*3);//"number"
typeof 2+3;// "number3"
  • ++、--是右结合的操作符(优先级最高的几个都是右结合),而且比加减乘除优先级高。同时自增、自减运算符的运算数得是左值(可以放在赋值符号左边的值),而不能是常数
4++; //ReferenceError: Invalid left-hand side expression in postfix operation
var a=0,b=0;
a+++b;//0
a;//1,++优先级比+高,所以相当于(a++)+b
b;//0
  • 赋值运算符的优先级相当的低
a=b==c;//等同于a=(b==c)
  • 逻辑非!也在优先级队列的前端,比加减乘除高,但逻辑与、逻辑或优先级很低,不如加减乘除
!2*0; //0, 等价于(!2)*0
  • 一个关于逻辑运算符的有意思地方是其“短路”功能,相信大家都有所了解,但有些题目不那么单纯,会结合表达式计算值来考察
1 && 3;
1 && "foo" || 0;
1 || "foo" && 0

了解了逻辑运算符的“短路”特点,在知道原始表达式的“返回值”就是本身,题目就很简单了

运算顺序

我们在运算符的优先级和“返回值”上关注了很多,一个经常被我们忽略的知识点就是运算顺序问题,复杂的表达式是由运算符和子表达式组成,优先级和结合性决定了表达式的运算顺序,但是却没有规定子表达式的运算顺序,在JavaScript中严格按照从左到右的顺序计算表达式,然后再按照优先级和结合性计算各个表达式和运算符作用结果。说的比较晦涩,看个例子

var a=1;
b=(a=3)+a++;

这个例子中运算顺序是这样的

  1. 计算b
  2. a=3
  3. a++(设为c)
  4. 计算a(这时候a变成了4已经,不是再最后才变得,但表达式使用的是a++的结果c,也就是a原来的值)
  5. 计算3+c
  6. 把3+c赋值给b

相等

我们知道可以使用"=="或"==="判断两个值的相等性,其中区别相信大家清楚,"==="是严格意义的相等,只需注意NaN和NaN不等就行了。而使用"=="的时候,javascript会帮我们做类型转换,造成一些匪夷所思的结果,那么使用"=="的时候会在哪些情况下做类型转换,又会换成什么样子?

  1. 如果两个值类型相同,则执行严格相等的运算
  2. 如果两个值的类型不同
    ******
  • 如果一个是null,一个是undefined,那么相等
  • 如果一个是数字,一个是字符串,先将字符串转为数字,然后比较
  • 如果一个值是true/false则将其转为1/0比较
  • 如果一个值是对象,一个是数字或字符串,则尝试使用valueOf和toString转换后比较
  • 其它就不相等了
null==undefined;
NaN==NaN
"1"==true

转载于:https://www.cnblogs.com/dolphinX/p/3524977.html

JavaScript面试时候的坑洼沟洄——表达式与运算符相关推荐

  1. JavaScript 面试中常见算法问题详解

    JavaScript 面试中常见算法问题详解,翻译自 https://github.com/kennymkchan/interview-questions-in-javascript.下文提到的很多问 ...

  2. 前端必备,JavaScript面试问题及答案

    前端必备,JavaScript面试问题及答案 1.使用 typeof bar === "object" 来确定 bar 是否是对象的潜在陷阱是什么?如何避免这个陷阱? 尽管 typ ...

  3. JavaScript面试的完美指南(开发者视角)

    2019独角兽企业重金招聘Python工程师标准>>> 摘要: 面试季手册. 原文:javascript 面试的完美指南(开发者视角) 作者:前端小智 Fundebug经授权转载,版 ...

  4. 如何在 JavaScript 面试中过五关斩六将?

    JavaScript 面试不容易.我觉得难,你也觉得不容易,大家的意见不谋而合.在 JavaScript 面试中被问问题的概率通常很高.那么该如何破解 JS 面试?突破口在哪儿?本文旨在通过学习基本概 ...

  5. 前端面试题汇总(JavaScript面试纯干货)

    前端面试题汇总(JavaScript面试纯干货) 1 闭包 闭包就是能够读取其他函数内部变量的函数 闭包是指有权访问另⼀个函数作⽤域中变量的函数,创建闭包的最常⻅的⽅式就是在⼀个函数内创建另⼀个函数, ...

  6. 70个JavaScript面试问题

    70个JavaScript面试问题 1.undefined 和 null 有什么区别? 在理解undefined和null之间的差异之前,我们先来看看它们的相似类. 它们属于 JavaScript 的 ...

  7. JavaScript面试大全

    JavaScript面试大全 1.求y和z的值是多少? var x = 1; var y = 0; var z = 0; function add(n){n=n+1;} y = add(x); fun ...

  8. 【笔记-面试】《imooc -前端跳槽面试技巧》、《imooc- 揭秘一线互联网企业 前端javaScript高级面试》、《imooc-前端javascript面试技巧》

    20190204:<imooc -前端跳槽面试技巧> 第01章 课程介绍 01-01 课程导学 一.一面知识点 1.面试技巧 页面布局类 2.css盒模型dom事件类 3.http协议类 ...

  9. JavaScript面试篇之正则表达式:“get-element-by-id”如何转化成驼峰,常用邮箱、身份证、QQ号等信息如何校验等等

    JavaScript面试篇之正则表达式:"get-element-by-id"如何转化成驼峰,常用邮箱.身份证.QQ号等信息如何校验等等 前言 一.简介 二.匹配规则 1.修饰符 ...

最新文章

  1. Python3 MySQL 数据库连接 - PyMySQL 驱动
  2. 【1863】畅通工程 (HDU)
  3. c语言解三元一次方程组_七年级下学期《8.3 一元一次不等式组》2020年高频易错题集...
  4. android studio创建构造方法,使用Android studio创建你的第一个项目
  5. 更快学习 JavaScript的6个思维技巧
  6. SAP License:决胜职场先决条件 白领们必须要懂得的人际经
  7. eclipse 集成svn客户端_SVN的介绍以及使用
  8. 伪标记是一种简单的半监督学习方法
  9. PHP文件中定义加载资源文件
  10. Atitit mq的AMQP 协议 STOMP2 、MQTT3 等协议  MQTT,XMPP,STOMP,AMQP,WAMP 目录 1. AMQP in a Nutshell 1 2. MQTT概述
  11. 多元梯度下降法(2)--学习率α machine learning
  12. 雨过天晴电脑保护系统 试用手记
  13. 放映机服务器型号,巴可Barco SP4K-20CS4激光系列智能影院放映机投影机
  14. 会议论文出版地和出版者
  15. 优秀的 Verilog/FPGA开源项目介绍(二十九)- 开源网站
  16. 2017校招中的流年回忆
  17. vscode中打开浏览器的快捷键_VSCode设置默认打开的浏览器的方法
  18. 求两个字符串的最大连续公共字串
  19. --go_out: protoc-gen-go: plugins are not supported问题处理
  20. Bilibili 视频下载 Python 实现

热门文章

  1. Java并发编程—说说Runnable与Callable
  2. RobotFramework系列(二):Robot 如何编写自定义关键字
  3. 怎么解决64位Access与32位不能同时安装的问题
  4. jQuery可放大预览的图片滑块
  5. html 新append后的元素如何注册click
  6. 网络namespace
  7. tomcat URL乱码问题
  8. (寒假CF)Choosing Symbol Pairs
  9. 杂谈--SQL SERVER版本
  10. Flex Accordion 和 TabNavigator组件浏览器跳转问题