本系列内容为本人平时项目实践和参照MDN,MSDN,《javascript语言精粹》,《Effective Javascript》等资料,而且整理本身EverNote的平常积累整理所写,时间太长有一些代码样例来源不可考。本系列不容许任何形式的转载,谢谢。 from yeanzhijavascript
JavaScript中的运算符有如下几种java
本文咱们只对几个重要或者有特殊技巧的运算符进行介绍,着重简介特殊运算符(操做符)node
逻辑运算符一般用于布尔型(逻辑)值;这种状况,它们返回一个布尔型值。然而,&&和||运算符实际上返回一个指定操做数的值,所以这些运算符也用于非布尔型,它们返回一个非布尔型值。
技巧:正则表达式
在条件中使用逻辑与或express
var foo = 10; foo == 10 && doSomething(); //等同于if (foo == 10) doSomething(); foo == 5 || doSomething(); //等同于if (foo != 5) doSomething();逻辑或还可用来设置默认值,好比函数参数的默认值。
arg1 = arg1 || 10;
数组
JavaScript有下列特殊运算符:浏览器
1,条件运算符(惟一的三目运算符)
condition ? val1 : val2
2,逗号操做符
逗号操做符(,)对两个操做数进行求值并返回第二个操做数的值。它经常用在for循环中,在每次循环时对多个变量进行更新。好比:闭包
for (var i = 0, j = 9; i <= 9; i++, j--) expression
关于循环技巧app
var sum = 0; for (var i = 0, len = arrayNumbers.length; i < len; i++) { sum += arrayNumbers[i]; } //还有一种写法 for (var i = 0, item; item = a[i++];) { // Do something with item } //这里咱们使用了两个变量。 //for 循环中间部分的表达式仍然用来判断是否为真—若是为真,那么循环继续。 //由于i每次递增 1,这个数组的元素会被逐个传递给 item 变量。 //当遇到一个假值元素(如undefined)时,循环结束。
这里并不推荐for in,若是有人向 Array.prototype 添加了新的属性,使用这样的循环这些属性也一样会被遍历:框架
for (var i in a) { // Do something with a[i] }
3,delete
删除操做符删除一个对象的属性.它不会触及原型链中的任何属性
注意:
3.1,在严格模式中,若是属性是一个不可配置(non-configurable)属性,删除时会抛出异常,非严格模式下返回 false。其余状况都返回 true。
3.2,delete 操做符与直接释放内存(只能经过解除引用来间接释放)没有关系
3.3,一些对象的属性不能被delete.ECMA262规范中把这些属性标记为DontDelete
x = 42; // 隐式声明的全局变量 var y = 43; // 显式声明的全局变量 myobj = new Number(); myobj.h = 4; // 添加属性h myobj.k = 5; // 添加属性k delete x; // 返回 true (隐式声明的全局变量能够被删除) delete y; // 返回 false (显式声明的全局变量不能被删除,该属性有DontDelete标记) delete Math.PI; // 返回 false (内置对象的内置属性不能被删除, 该属性有DontDelete标记) delete myobj.h; // 返回 true (用户定义的属性能够被删除) with(myobj) { delete k; // 返回 true (至关于delete myobj.k) } delete myobj; // 返回 true (隐式声明的全局变量能够被删除)
3.4,不能删除一个对象从原型继承而来的属性(不过能够从原型上直接删掉它).
function Foo(){} Foo.prototype.bar = 42; var foo = new Foo(); delete foo.bar; // 无效的操做 alert(foo.bar); // alerts 42, 继承的属性 delete Foo.prototype.bar; // 直接删除原型上的属性 alert(foo.bar); // alerts "undefined",已经没有继承的属性
3.5,删除数组元素
当删除一个数组元素时,数组的 length 属性并不会变小。例如,若是删除了a[3], a[4]仍然是a[4], a[3]成为undefined.
当用 delete 操做符删除一个数组元素时,被删除的元素已经彻底不属于该数组。下面的例子中, name[3] 被使用delete完全删除。
var name = ["ye","an","z","h","i"]; delete name[3]; console.log(name);//[ 'ye', 'an', 'z', , 'i' ] console.log(name[3]);//undefined console.log(name.length);//5 for(var v in name){ console.log(v);//0 1 2 4 }
若是你想让一个数组元素的值变为 undefined 而不是删除它,可使用 undefined 给其赋值而不是使用 delete 操做符。
数组元素删除应使用splice函数。
4,函数表达式
function 关键字可用来在一个表达式中定义一个函数。上一篇在闭包的地方有函数表达式的例子
函数表达式(function expression)很是相似于函数声明(function statement),而且拥有几乎相同的语法。函数表达式与函数声明的最主要区别是函数名称,在函数表达式中可忽略它,从而建立匿名函数。
匿名函数建立递归技巧
匿名函数能够经过arguments.callee 的属性来完成递归调用。这个属性一般指向当前的(调用)函数,所以它能够用来进行递归调用:var charsInBody = (function(elm) { if (elm.nodeType == 3) { // TEXT_NODE return elm.nodeValue.length; } var count = 0; for (var i = 0, child; child = elm.childNodes[i]; i++) { count += arguments.callee(child); } return count; })(document.body);5,get,set操做符
get,set语法将对象属性绑定到该属性查找时将调用的函数。var log = ['test']; var obj = { get latest () { if (log.length == 0) return undefined; return log[log.length - 1] }, set current (str) { log[log.length] = str; } } obj.current = 'fa'; console.log (obj.latest);//输出 "test".7,in
若是指定的属性存在于指定的对象中,则 in 运算符会返回 true。// 数组 var trees = new Array("ye", "an", "zhi"); 0 in trees // true 6 in trees // false "bay" in trees // false (必须使用索引号,而不是数组元素的值) "length" in trees // true (length是一个数组属性)使用delete运算符和将属性赋值为undefined
var name = ["ye","an","z","h","i"]; delete name[3]; 3 in name; // 返回false8,instanceof
instanceof 运算符能够用来判断某个构造函数的prototype属性是否存在另一个要检测对象的原型链上。
这个运算符将在《对象与原型》中讲解
9,let 操做符
在上一篇变量做用域中有讲解
10,new 操做符
这个运算符将在《对象与原型》中讲解
11,this操做符
JavaScript函数中的this关键字的行为相比起其余语言有不少不一样。在JavaScript的严格和非严格模式下也略有区别。在绝大多数状况下,函数的调用方式决定了this的值。this不能在执行期间被赋值,在每次函数被调用时this的值也可能会不一样。ES5引入了bind方法来设置函数的this值,而不用考虑函数如何被调用的。
11.1 Global context 全局上下文
在全局运行上下文中(在任何函数体外部),this 指代全局对象,不管是否在严格模式下。this===window //true
11.2 Function context 函数上下文
在函数内部,this的值取决于函数是如何调用的。
非严格模式下,this的值是一个对象且默认是全局对象
function f1(){ return this; } f1() === window; // global object
严格模式下 上面应该返回 undefined ,可是这个并无在浏览器中的到普遍的支持,通常会返回一个window 对象
11.3As an object method 做为对象方法
函数以对象里的方法的方式进行调用时,它们的this由调用该函数的对象进行设置。
var o = { prop: 37, f: function() { return this.prop; } }; console.log(o.f()); // logs 37
11.4 As a constructor 做为构造函数
所谓构造函数,就是经过这个函数生成一个新对象(object)。这时,this就指这个新对象。
var x = 2; function test(){ this.x = 1; } var o = new test(); alert(x); //2 alert(o.x); //1
11.5 apply调用
apply()是函数对象的一个方法,它的做用是改变函数的调用对象,它的第一个参数就表示改变后的调用这个函数的对象。所以,this指的就是这第一个参数。也就是说js里面的this是能够改变的
var val = hi; function Test(hello){ this.val = hello; } Test.prototype.printval = function(){ console.log(this.val); } var o = new Test('hello'); o.printval();//hello o.printval.apply();//0 o.printval.apply(o);//hello
apply()的参数为空时,默认调用全局对象。
最开始输出hello 证实 this为对象o的
而后输出hi 证实this是 全局变量
最后输出hello 证实this被重置为对象o的
另外
apply有一个孪生兄弟 call,call 和 apply 都是为了改变某个函数运行时的 context 即上下文而存在的,换句话说,就是为了改变函数体内部 this 的指向。由于 JavaScript 的函数存在「定义时上下文」和「运行时上下文」以及「上下文是能够改变的」这样的概念。
两者的做用彻底同样,只是接受参数的方式不太同样。
JavaScript 中,某个函数的参数数量是不固定的,所以要说适用条件的话,当你的参数是明确知道数量时,用 call,而不肯定的时候,用 apply,而后把参数 push 进数组传递进去。当参数数量不肯定时,函数内部也能够经过 arguments 这个数组来遍历全部的参数。
var x = 0;
function test(){
alert(this.x);
}
var o={};
o.x = 1;
o.m = test;
o.m.apply(); //0
12,typeof 操做符
typeof操做符返回一个字符串,表明一个未被求值的操做对象(unevaluated operand)的类型。
这个在js的反射中用的比较多
值得一说的是 typeof null的值是object而typeof undefined 的值是undefined
并且一下也是须要注意的
typeof Math.LN2 === 'number'; typeof Infinity === 'number'; typeof NaN === 'number'; // 尽管NaN是"Not-A-Number"的缩写,意思是"不是一个数字" typeof Number(1) === 'number'; // 不要这样使用! // 下面的容易使人迷惑,尽可能不要用 typeof new Boolean(true) === 'object'; typeof new Number(1) ==== 'object'; typeof new String("abc") === 'object';
注意
1,正则表达式字面量在某些浏览器中不符合标准
typeof /s/ === 'function'; // Chrome 1-12 ... // 不符合 ECMAScript 5.1 typeof /s/ === 'object'; // Firefox 5+ ... // 符合 ECMAScript 5.1
2,原型链中的任何属性都会产生值
typeof flight.toString // function typeof flight.constructor// function
咱们有两种方法去掉这些不须要的属性,一是在程序中作检测,丢掉值为函数的属性,由于咱们一般项目编码中须要的是数据而不是函数,第二是使用hasOwnProperty()方法,若是是对象拥有独有的属性,会返回true
13,void 操做符
void 运算符会对它的操做数表达式进行求值,而后忽略掉求值的结果,直接返回 undefined
常常会有人用 void(0) 或者 void 0 来代替 undefined 变量来表示 undefined 值,由于他们担忧本身拿到的 undefined 这个变量的值可能不是 undefined
常常会有人用 void(0) 或者 void 0 来代替 undefined 变量来表示 undefined 值,由于他们担忧本身拿到的 undefined 这个变量的值可能不是 undefined
void function iife() { var bar = function () {}; var baz = function () {}; var foo = function () { bar(); baz(); }; var biz = function () {}; foo(); biz(); }();
当用户点击一个以 javascript: 协议开头的 URI 时,浏览器会对冒号后面的代码进行求值,而后把求值的结果显示在页面上,这时页面基本上是一大片空白,这一般不是咱们想要的。只有当这段代码的求值结果是 undefined 的时候,浏览器才不会去作这件傻事,因此咱们常常会用 void 运算符来实现这个需求。像下面这样:
<a href="javascript:void(0);"> 这个连接点击以后不会作任何事情,若是去掉 void(), 点击以后整个页面会被替换成一个字符 0。 </a> <a href="javascript:void(document.body.style.backgroundColor='green');"> 点击这个连接会让页面背景变成绿色。 </a>
注意,虽然这么作是可行的,但利用 javascript: 伪协议来执行 JavaScript 代码是不推荐的,推荐的作法是为连接元素绑定 click 事件。
14,yield 操做符
说道yield就不得不提到generator 函数,在ECMAScript 6 引入了generator函数,做用就是返回一个内部状态的遍历器,主要特征是函数内部使用了yield语句。
当调用generator函数的时候,该函数并不执行,而是返回一个遍历器(能够理解成暂停执行)。之后,每次调用这个遍历器的next方法,就从函数体的头部或者上一次停下来的地方开始执行(能够理解成恢复执行),直到遇到下一个yield语句为止,并返回该yield语句的值。
ECMAScript 6草案定义的generator函数,须要在function关键字后面,加一个星号。而后,函数内部使用yield语句,定义遍历器的每一个成员。
function* helloWorldGenerator() { yield 'hello'; yield 'world'; } var hw = helloWorldGenerator(); hw.next() // { value: 'hello', done: false } hw.next() // { value: 'world', done: false } hw.next() // { value: undefined, done: true } hw.next() // Error: Generator has already finished
yield有点相似于return语句,都能返回一个值。区别在于每次遇到yield,函数返回紧跟在yield后面的那个表达式的值,而后暂停执行,下一次从该位置继续向后执行,而return语句不具有位置记忆的功能。
上面代码定义了一个generator函数helloWorldGenerator,它的遍历器有两个成员“hello”和“world”。调用这个函数,就会获得遍历器。我会在后期《特殊性质与技巧》中使用一个篇幅来介绍yield,它是koa框架实现最核心的理念“减小回调金字塔”必不可少的工具。接下来,咱们将进入次日学习《javascript函数》。