★04.表达式和运算符

表达式

原始表达式

  • 原始表达式通常指直接由直接量表示的表达式。
1.23
"hello"
/pattern/

true
false
null
this

i
sum
undefined

对象和数组的初始化表达式

  • 对象和数组初始化表达式 实际上是一个新创建的对象和数组,这些 初始化表达式 有时称做 对象直接量数组直接量
{}
{ topic: "JavaScript", fat: true }

[]
[1 + 2, 3 + 4]

函数定义表达式

  • 函数定义表达式 可称为 函数直接量
function plus1(x) { return x + 1; }

属性访问表达式

  • 属性访问表达式 运算得到一个对象属性或一个数组元素的值。
var o = {x: 1, y: {z: 3}};
var a = [o, 4, [5, 6]];
o.x
o.y.z
o["x"]
a[1]
a[2]["1"]
a[0].x

调用表达式

  • 调用表达式函数调用方法调用 两种, 函数调用 中的this指的是全局对象,而 方法调用this则代表着 方法 的对象。在 ES 5 中,通过严格模式定义的函数调用中,this的值为undefined
f(0)
Math.max(x, y, z)
a.sort()

对象创建表达式

  • 对象创建表达式 创建一个对象并调用一个函数初始化新对象的属性。
new Object()
new Point(2, 3)

// 不需要传入任何参数给构造函数时,可以省略括号
new Object
new Date

运算符

  • 大多数运算符都是符号,少数非符号的运算符有:deletetypeofvoidinstanceofin
  • JavaScript 总是严格按照从左至右的顺序来计算表达式。

算术运算符

  • 位运算符有

基本算术运算符

  • 基本的算术运算符有:+-*/%

加法算术运算符 —— +

  • 加法既可以做数字运算,也可以做字符串连接操作。
  • 加法计算规则:
    • 两个都是数字:加法运算。
    • 两个都是字符串:字符串连接操作。
    • 一个是数字,一个是字符串:数字转化为字符串,字符串连接操作
    • 一个是对象,另一个是字符串或数字,转换规则如下:
      1. Date类对象会使用toString()转换为字符串。
      2. Date类以外的其他对象会使用以下规则:
        1. 使用valueOf()转换为数字。
        2. 若没有valueOf(),则使用toString()转换为字符串。
        3. 若没有既没有valueOf()也没有toString(),【Todo】。
      3. 完成上述转换后,会有三种情况:
        1. 两个操作数都是字符串:字符串连接操作。
        2. 两个操作数都是数字:加法运算。
        3. 一个数字,一个字符串:数字转换为字符串,进行字符串连接操作。
    • 两个操作数都转换为数字或者NaN,然后进行加法操作。
  • 加法需要考虑结合性对运算顺序的影响:
1 + 2 + "blind mice"    // => "3 blind mice"

其他算术运算符 —— -*/%

  • 操作数尝试转换为数字,若无法转化为数字就转化为NaN值。
  • 如果操作数或转换结果是NaN值,运算结果也为NaN值。
  • JavaScript 的除法是浮点型的。
  • 除数为0-0时,运算结果为Infinity-Infinity
  • 0/0的结果是NaN
  • %的操作数通常都是整数,但也适用于浮点数。
  • %运算结果的符号与第一个操作数相同。

一元算术运算符 —— +-++--

  • 一元算术运算符有很高的优先级,且都是右结合性的,

位算术运算符 —— &|^~<<>>>>>

  • >>右移补零时,由操作数的符号相关。
  • >>>右移补零时,总是补0。

关系运算符

  • 关系运算符根据关系是否存在返回truefalse
  • 关系运算符包括:x

相等与不等运算符 —— =====!=!==

  • ==是相等运算符。
  • ===是严格相等运算符,也称恒等运算符。
  • !=称做不相等,!==称做不严格相等。
  • !=!==运算符的检测规则是==!==的运算符的求反。
  • JavaScript 对象比较的是引用,而不是值。
  • ===的比较过程没有任何类型转换,有以下重要的比较情况:
    • null === undefined返回false
    • NaN === x或者NaN === NaN,返回false。(若x !== x返回true,则可以判断xNaN
    • 0 === -0返回true
    • 如果两个字符串对应为上的16位数完全相等,则=====返回true,若两个字符串显示出来的字符完全一样,但是内部编码的16位数不一样,则=====返回false
    • 如果两个引用指向同一个对象、数组或函数,则===返回true,如果指向不同的对象、数组或函数,则===返回false,尽管两个对象、数组或函数具有完全一样的属性、元素或函数体。
  • =====类似,但是==不严格,有以下重要的比较情况:
    • 两个操作数的类型相同,则返回结果与===一致。
    • 如果两个操作数类型不同:
      • null == undefined返回true
      • 如果是布尔值,则先转换为数字再进行比较。true转换为1flase转换为0
      • 一个数字,一个字符串:字符串转换为数字,比较数字。
      • 如果一个是对象,另一个是数字或字符串,则使用以下转换规则:
        1. Date类对象会使用toString()转换为字符串。
        2. Date类以外的其他对象会使用以下规则:
          1. 使用valueOf()转换为数字。
          2. 若没有valueOf(),则使用toString()转换为字符串。
          3. 若没有既没有valueOf()也没有toString(),【Todo】。
        3. 完成上述转换后,会有三种情况:
          1. 两个操作数都是字符串:比较字符串。
          2. 两个操作数都是数字:比较数字。
          3. 一个数字,一个字符串:字符串转换为数字,比较数字。
      • 对于其他不同类型的操作数,==返回false

比较运算符 —— <><=>=

  • 比较操作符的操作数可能是任意类型,但是只有数字和字符串才能真正执行比较操作。
  • <=>的取反,>=<的取反,只有一个例外,操作数有NaN时,返回值为false
  • 比较规则:
    • 两个都是数字:
      • 0-0是相等的。
      • Infinity比任何值(除了自身)以外都大。
      • -Infinity比任何值(除了自身)以外都小。
      • 其中一个是NaN的话,返回false
    • 两个都是字符串:比较两个由16位值组成的序列。注意Unicode定义的字符编码中文不是按照拼音顺序的,英文则是所有大写字母小于小写字母。可以采用String.localCompare()解决问题。
    • 一个是数字,一个是字符串:字符串转换为数字,比较数字。
    • 转换规则如下:
      • 如果操作数是对象,则按照如下转换规则:
        1. Date类对象会使用toString()转换为字符串。
        2. Date类以外的其他对象会使用以下规则:
          1. 使用valueOf()转换为数字。
          2. 若没有valueOf(),则使用toString()转换为字符串。
          3. 若没有既没有valueOf()也没有toString(),【Todo】。
        3. 完成上述转换后,会有三种情况:
          1. 两个操作数都是字符串:比较字符串。
          2. 两个操作数都是数字:比较数字。
          3. 一个数字,一个字符串:字符串转换为数字,比较数字。

in运算符

  • 左操作数是一个字符串或可以转换为字符串,右操作数是一个对象。
  • 如果右操作数对象有一个名为左操作数的属性名,表达式返回true
var point = {x : 1, y : 1};

"x" in point            // true
"z" in point            // false
"toString" in point     // true

var data = [7, 8, 9];
"0" in data             // true
1 in data               // true
3 in data               // false

instanceof运算符

  • 左操作数是对象,右操作数是标识类的函数。
  • 如果左操作数不是对象,返回false,如果右操作数不是函数,抛出一个 类型错误异常
var d = new Date()
d instanceof Date;      // true
d instanceof Object;    // true
d instanceof Number;    // false

var a = [1, 2, 3];
a instanceof Array;     // true
a instanceof Object;    // true
a instanceof RegExp;    // false

逻辑运算符 —— &&||!

  • C语言 的短路规则。

赋值运算符 —— =+=-=

  • 带操作的赋值运算符有:+=-=*=/=%=<<=>>=>>>=&=|=^=

表达式计算 —— eval()

  • eval()只有一个参数,如果传入的参数不是字符串,它直接返回这个参数。
  • eval()如果参数是字符串,它会把字符串当作 JavaScript 代码编译,如果编译失败则抛出一个 语法错误异常 。如果编译成功,则开始执行这段代码。
  • eval()的返回值为这个字符串最后一个表达式或语句的值,如果最后一个表达式或语句没有值,则最终返回undefined
  • 如果执行的字符串抛出异常,这个异常会传递给eval()
  • eval()使用了调用它的变量作用域环境,如下代码示例:
x = 1;
eval("x = 2")       // 改变局部变量x的值
  • 如果在再最顶层代码中调用eval(),当然它会作用于全局变量和全局函数。
  • 以下代码是错误的:
var foo = function(a) {
    eval(a);
};
foo("return; ");    // eval()的上下文环境就是函数调用的环境,即全局环境,在全局上下文中使用return会报错
  • 直接eval :直接调用eval()
  • 间接eval :通过别名来间接调用eval()
  • ES3
    • 直接eval :在调用它的上下文作用域中执行,也叫 局部eval()
    • 间接eval :禁止使用 间接eval ,若使用会抛出一个 EvalError异常
  • ES5
    • 直接eval :在调用它的上下文作用域中执行,也叫 局部eval()
    • 间接eval :使用全局对象作为其上下文作用域,并且无法读、写、定义局部变量和函数,也叫 全局eval()
  • ES5 严格模式:
    • 直接eval :可以查询和更改局部变量,但是不能定义新的变量或函数。
    • 间接eval : 禁止使用 间接eval ,若使用会抛出一个 EvalError异常
var geval = eval;
var x = "global", y = "global";
function f() {
    var x = "local";
    eval("x += 'change';");     // 此x是局部x
    return x;
}

function g() {
    var y = "local";
    geval("y += 'changed';");   // 此y是全局y
    return y;
}

console.log(f(), x);
console.log(g(), y);
  • 通常不用eval(),如果真的要用,更可能是用 全局eval() 而不是 局部eval()

其他运算符

typeof()运算符

  • 接受一个任意类型的操作数,返回一个表示操作数类型的字符串。
  • switch语句中非常有用。
x typeof(x)
undefined "undefined"
null "object"
true或false "boolean"
任意数字或NaN "number"
任意字符串 "string"
任意函数 "function"
任意内置对象(非函数) "object"
任意宿主对象 由编译器各自实现的字符串

delete运算符

  • delete用来删除对象的属性或者数组元素。
  • C++ 中的delete完全不同。
  • delete删除数组元素后,数组长度依旧不变。
  • delete返回值:
    • 若操作数不是左值,不进行任何操作并返回true
    • 若操作数是左值,如果删除成功返回true,删除失败返回false
  • 不能使用delete删除的有:
    • 内置核心和客户端属性。
    • 使用var声明的变量。
    • 函数。
    • 函数参数。
  • ES5 严格模式:非法的delete会报错。
var o = {x : 1, y : 2};
delete o.x;
o.y = undefined
"x" in o                    // false
"y" in o                    // true

var a = [1, 2, 3];
delete a[2];
2 in a;                     // false
a.length                    // 3:依旧是3

void运算符

  • 忽略表达式的计算结果并返回undefined
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,001评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,210评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,874评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,001评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,022评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,005评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,929评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,742评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,193评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,427评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,583评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,305评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,911评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,564评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,731评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,581评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,478评论 2 352

推荐阅读更多精彩内容