OurJS


OurJS-我们的JS, 我们的技术-IT文摘; 专注JS相关领域;
我们热爱编程, 我们热爱技术;我们是高大上, 有品味的码农;

欢迎您订阅我们的技术周刊


我们会向您分享我们精心收集整理的,最新的行业资讯,技术动态,外文翻译,热点文章;
我们使用第三方邮件列表向您推送,我们不保存您的任何个人资料,注重您的隐私,您可以随时退订,

欢迎分享您的观点,经验,技巧,心得

让我们一起找寻程序员的快乐,探索技术, 发现IT人生的乐趣;


本网站使用缓存技术每次加载仅需很小流量, 可在手机中流畅浏览;
如果您发现任何BUG,请即时告知我们: ourjs(at)ourjs.com

JavaScript中怪异的地方


分享到
分类 JS学习   关键字 JavaScript   发布 1518409521  1408807630369
注意 转载须保留原文链接,译文链接,作者译者等信息。  

经历语言奇怪特性的旅程


在这篇文章中我想总结一下我们在1月YYCJS聚会讨论的一些事情。这都是关于JavaScript的怪异的部分。你可以在Youtube上找到这个视频, 在yycjs.com/the-weird-parts 找到一些幻灯片,在 JSBin 找到在线编码的部分。


非常感谢@alexisabril的完整性检查, Assembly提供图像。另外,感谢审查这个Minko Gechev的博客(同名)谈论了一些其他的怪异的地方。


热身


进入我们所谈论的内容。我们可以使用(点)或[](方括号)操作符访问对象和对象属性,点操作符只接受有效的JavaScript变量名而方括号可以采用任何字符串:

var person = {
 name: 'david',
 '&weird property': 'YYCJS'
}

var prop = 'name';

person.name // -> David
person['name'] // -> David
person["name"] // -> David
person[prop] // -> David

person['&weird property'] // -> YYCJS

// ERROR
person.&weird property

给字符串使用单引号或双引号没有真正区别。保持一致是有意义,大家似乎普遍偏好单引号(在大多数键盘上少按一些键)。


函数实参


在一个函数中, arguments是一个特殊的类数组变量,它包含所有传递给它的参数:

function sum() {
  var sum = 0;
  for(var i = 0; i < arguments.length; i++) {
    sum += arguments[i];
  }
  return sum;
}
sum(1, 2, 3, 4); // -> 10

一个函数通过不同数量的参数调用时,arguments通常用于模拟函数重载。

arguments不是一个真正的数组,它只是一个类数组对象拥有长度属性和索引。如果你想使用数组方法如push或pop,您可以使用jQuery.toArray()或这样的来转换他:

var args = Array.prototype.slice.call(arguments, 0);


真值和假值

在JavaScript中, 在一个逻辑表达式中除了实际的布尔值可以评估为真(真值)或假(falsy)。下列值将被视为falsy:

false
null
undefined
0
'' // empty string
person.undefinedPropertys
例如, 他们可以在一个if语句中判断
var person = { name: 'David' }
if(person.name) {
 // Do stuff if property exists and is not falsy
}

注意:这并不适用于未声明的变量名。如果你想看看一个变量是否存在(而不是没有定义),使用typeof运算符:

if(typeof  myvar !== 'undefined') {}

一个逻辑表达式的结果并不总是真实的布尔值。使用| |(或)将返回第一个真值或表达式的最后一个值。这通常用于将默认值分配给一个对象或一个函数的默认参数:

person.meetup = person.meetup || defaults.meetup || 'YYCJS';
function sum(first, second) {
 first = first || 0;
 second = second || 0;
 
 return first + second;
}
sum() // -> 0 instead of NaN
sum(1) // -> 1 instead of NaN

注:我建议重新分配函数参数变量设置默认值, 如果它在任何其他方式将改变请使用局部变量。


等式

真值和假值是等式比较。基本的= =(等于)和!=(不等于)操作符只有比较值(不比较类型),例如:

1 == 1 // -> true
1 == ‘1' // -> true
1 == 2 // -> false

// 下面的就奇怪了
'' == false // -> true
[] == false // -> true, [] not falsy though
null == undefined // -> true

= = =(三重等于)和!= =(三重不等于?)操作符比较值和类型:

1 === 1 // -> true
1 === '1' // -> false
1 === parseInt('1') // -> true
[] === false // -> false
null === undefined // -> false
对象总是比较他们的引用,所以如果它实际上是相同的对象,这些表达式只会是真。
var person = { name: 'David' };
var otherPerson = person;
person === { name: 'David' } // -> false, created new object
person === otherPerson // -> true, same reference
为达到一致性和避免遇到很麻烦的错误总是使用= = =和! = =。有时这可能意味着编写更多的代码 (如转换字符串如果你期望得到一个数字),但它会让事情更容易和更可预测。

范围

JavaScript只知道函数范围。这意味着块或for和while循环不引入一个新的变量范围,有效地让它和在这个函数开始的地方声明每个变量一样。
函数里的其他函数可以访问他们父范围(关闭)的变量而其他的方式不能访问。
var x = 'outer';
function count() {
  for(var i = 0; i < 10; i++) {
    var x = 'testing';
    var inner = function() {
      var i = 42;
      // -> x === 'testing'
      // -> i === 42
    }
    inner();
    // -> i === current count   } } // -> x === 'outer'
有时你会看到所有的变量被声明在函数的开始部分。这主要是一个风格的问题,不是必须的,如果变量名只是描述性的或者函数很小。

闭包

让我们看看下面的jQuery代码片段,这段代码创建十个按钮,添加一个单击处理器并将它们附加到body。
for(var i = 0; i < 10; i++) {
  var button = $('<button>Button #' + i + '</button>');
  button.click(function() {
    alert(i);
  });
  $('body').append(button);
}

然而点击任何按钮不会按你期望的弹出这个按钮的数字,而是每个按钮都弹出数字10。
原因仍然是变量作用域。单击处理函数从他的父作用域访问相同的变量,因为它总是在循环完成后执行,它不管在哪都将具有相同的值。
这里的窍门是通过包装器函数引入一个新的范围,用当前计数调用它。它将被复制到一个新的变量计数器:

for(var i = 0; i < 10; i++) {
  var button = $('<button>Button #' + i + '</button>');
  var wrapper = function(counter) {
    button.click(function() {
      alert(counter);
    });
   }
  wrapper(i);   $('body').append(button); }
只有原始值(字符串、布尔值、数字)将被复制。如果你传递一个对象,你会得到同样的对象引用,重要的是要知道你是否打算修改该对象。

全局变量

在浏览器环境中,没有var声明的变量将自动成为全局性的,在Node中将成为模块的全局变量:
function test() {
 var local = 42;
 global = 'global';
}
test();
这可能是总是无意的。在Node和新生浏览器中避免意外的全局变量泄漏的好方法是使ECMAScript 5严格模式可用,将:

'use strict';

用在一个函数或JavaScript文件的开头。一个全局变量泄漏将抛出一个ReferenceError引用错误。
如果你需要全局变量, 可以明确地通过这个全局对象(在浏览器中是Window,在Node中是global)添加和访问它们:
function test() {
  var local = 42;
  window.global = 'global';
}
test();

this是什么?

在任何函数,this是一个保留字,指的是函数的所有者。例如当调用一个定义在一个对象中的函数,它将是对象本身:
var person = {
 name: 'David',
 sayHi: function() {
  return 'Hello ' + this.name;
 }
}
person.sayHi(); // -> 'Hello David'

this也用在事件处理程序函数中,它指触发这个事件的一个或多个元素:

document.getElementById('mybutton').addEventListener('click',   
  function() {
   this.innerHTML = 'Button clicked';
  });

三位一体的this

能够改变一个函数的所有者可能会导致一些混淆,this当前指的到底是什么,但只有三个规则可以说明this指什么:
1.     对象,当函数在这个对象里被调用(使用“.”或[ ]操作符)
2.  新创建的对象,当一个函数被new操作符创建的对象调用
3.  被调用者设置为call,apply或bind

var person = {

 name: 'David',

 sayHi: function() {

   return 'Hello ' + this.name;

 }

};



function Dog(name) {
 this.name = name;
}

var otherPerson = { name: 'Eric' };

// 1) The object, when the function is called on an object
person.sayHi(); // -> 'Hello David'
person['sayHi'](); // -> 'Hello David'
// 2) The new object when a function is called with new
var goofy = new Dog('Goofy');

goofy.name // -> 'Goofy'


// 3) The owner has been set with call, apply or bind
person.sayHi.call(otherPerson); // -> 'Hello Eric'

var hi = person.sayHi.bind(otherPerson);

hi(); // Hello Eric
否则this在严格模式下将是全局或未定义的对象:

var ownerless = person.sayHi;
ownerless() // "Hello " (or window.name or ReferenceError)

this
callback

回调用于任何类型的异步操作。一个常见的陷阱是忘记在任何新的回调过程中你可能会失去原来的this。保持引用您将需要将其存储在一个新的变量里,这样它就可以被引用(通过闭包):

$('button').click(function() {
 // Store the old this reference (the clicked button)
 var self = this;
 $.getJSON('someFile.json', function(data) {
   // Set the button content
   $(self).html(data.text);
 });
});

总结

这绝对是一个不完整的JavaScript缺陷列表,尤其是刚开始使用JavaScript你可能会被很多事情绊倒。在后续的帖子我想谈谈JavaScript中的继承 (这也会发布在meetup上)。 

 

 

原文地址: 点此
社区评论 ( Beta版 )
OnceDoc 您自己的企业内容管理系统——文档、流程、知识库、报表、网盘All In One

访问404页面,寻找丢失儿童
 热门文章 - 分享最多
  1. OurJS-免费开源的博客引擎,论坛系统,网站模板和轻量级的CMS
  2. 痛苦的Java程序员
  3. JavaScript构建(编绎)系统大比拼:Grunt vs. Gulp vs. NPM
  4. JavaScript中的继承,构造函数以及new关键字的作用
  5. TJ Holowaychuk将Express维护权移交给StrongLoop
  6. Google官方支持的NodeJS访问API,提供后台登录授权
  7. 微软Azure云推出基于JSON的NoSQL数据库DocumentDB
  8. 有可能将CSS应用到一个字符的一半吗?
  9. Amazon云增长过快,吓坏股东
  10. fibjs 比 nodejs 快五倍
  11. AirJD-简单好用的免费建站工具

 相关阅读 - JS学习
  1. 前置逗号是不好的JavaScript代码书写习惯吗?
  2. 在node.js响应流中设置多个Set-Cookie header属性
  3. JavaScript:世界上误解最深的语言
  4. 告别Node.js
  5. Node.js手册:require是如何工作的
  6. JavaScript最大堆栈的数量
  7. 7个步骤:让JavaScript变得更好
  8. 在JavaScript数组中找到最小元素的位置
  9. 在JavaScript中创建命名空间的几种写法
  10. JavaScript中NaN的秘密

 关键字 - JavaScript
  1. 如何用CSS将select/option文本居中或居右对齐
  2. 用原生HTML5控件实现输入框自动提示(下拉列表补全)功能
  3. JavaScript中怪异的地方
  4. 在JavaScript中创建命名空间的几种写法
  5. JavaScript中的继承,构造函数以及new关键字的作用
  6. 纽约时报使用Html5 WebRTC记录访问者IP地址
  7. 正则中test、exec、match的简单区别,以及括号的用法
  8. NativeScript的工作原理:用JavaScript调用原生API实现跨平台
  9. 2015年的JavaScript:Angular之类的框架将被库取代
  10. 少年,不要滥用箭头函数啊:JS中lambda表达式的优缺点和使用场景

 欢迎订阅 - 技术周刊

我们热爱编程, 我们热爱技术; 我们是高端, 大气, 上档次, 有品味, 时刻需要和国际接轨的码农; 欢迎您订阅我们的技术周刊; 您只需要在右上角输入您的邮箱即可; 我们注重您的隐私,您可以随时退订.
加入我们吧! 让我们一起找寻码农的快乐,探索技术, 发现IT人生的乐趣;


 关注我们

我们的微信公众号: ourjs-com
打开微信扫一扫即可关注我们:
IT文摘-程序员(码农)技术周刊

ourjs官方微信号