那些必须要知道的Javascript
原文:那些必须要知道的Javascript

JavaScript是前端必备,而这其中的精髓也太多太多,最近在温习的时候发现有些东西比较容易忽略,这里记录一下,一方面是希望自己在平时应用的时候能够得心应手,另一方面也希望能给别人带来一点点的收获。

一、JavaScript的==和===,即相等运算符和等同运算符。

相等运算符,如果操作数有相同的类型,则判断其等同性,如果两个操作数的值相等,则返回true(相等),否则返回false(不相等);

如果类型不同,则按照这样的情况来判断:

null和undefined相等;数字与字符串字符比较,字符串转化为数字再比较;其中一个为true转化为1再做比较;如果一个值是对象,另一个是数字或者字符串,则将对象转化为原始值(通过toString()或者valueOf()方法),其他返回false。

等同运算符,如果操作数类型不一样,直接返回false,类型相同,如下判断:

1、都是数字,若值相同,则两者等同但是NAN除外,因为NAN与本身也不等,否则不相同;

2、都是字符串的情况:值不等则不等同,否则等同;

3、都是布尔值,均为true/false则等同否则不等同;

4、如果两个操作数引用同一对象(数组或函数)则等同,否则不等;

5、均为null/undefined则等同。

二、函数作用域

作用域在所有语言中都有体现,只是在Javascript脚本里有其特殊性-->Javascript中的作用域为函数体内有效,而无块儿作用域。在Java或者C#中,我们可以写出下面的循环:

public void method(string obj1,string obj2){
for(int i=0;i<obj1.length;i++){
//do  something
}
//此时的i为未定义
for(int i=0;i<obj2.length;i++){
//do another thing
}
}

View Code

而在Javascript中不同:

function func(){
for(var i = 0; i < array.length; i++){
//do something here.
}
//此时i仍然有值,及I == array.length
print(i);//i == array.length;
}

View Code

Javascript的函数是在局部作用域内运行的,在局部作用域内运行的函数体可以访问其外层的(可能是全局作用域)的变量和函数。JavaScript的作用域为词法作用域,所谓词法作用域是说,其作用域为在定义时(词法分析时)就确定下来的,而并非在执行时确定,如下例:

var str = "global";
function scopeTest(){
print(str);
var str = "local";
print(str);
}
scopeTest();

View Code

您觉得运行结果是什么呢?global local或者local  local 再或者其他?而正确的结果却是 undefined   local,没错,undefined  local!

因为在函数scopeTest的定义中,预先访问了未声明的变量str,然后才对str变量进行初始化,所以第一个print(str)会返回undifined错误。那为什么函数这个时候不去访问外部的str变量呢?这是因为,在词法分析结束后,构造作用域链的时候,会将函数内定义的var变量放入该链,因此str在整个函数scopeTest内都是可见的(从函数体的第一行到最后一行),由于str变量本身是未定义的,程序顺序执行,到第一行就会返回未定义,第二行为str赋值,所以第三行的print(str)将返回”local”。

三、数组操作

常用的对数组的操作:

contact() 连接两个或更过的数组,并返回结果

join() 把数组所有元素放入一个字符串,元素通过指定的分隔符进行分隔

pop() 删除并返回最后一个元素与push()对应,向数组末尾添加一个或更多元素,并返回新长度;类似于压栈和弹栈

reverse() 颠倒元素的顺序

shift() 删除并返回第一个元素

slice() 从已有数组返回制定数组

sort() 对数组元素排序,默认按字母排序,也可按数字大小排:array.sort(function(a,b){return a-b});

splice()删除元素,并添加新元素

unshift()向数组开头添加一个或更多元素,并返回新的长度

valueOf() 返回数组对象的原始值

四、JavaScript闭包特性

我们来看一个例子,如果不了解JavaScript的特性,很难找到原因:

var outter = [];
function clouseTest () {
var array = ["one", "two", "three", "four"];
for(var i = 0; i < array.length;i++){
var x = {};
x.no = i;
x.text = array[i];
x.invoke = function(){
print(i);
}
outter.push(x);
}
}
//调用这个函数
clouseTest();
print(outter[0].invoke());
print(outter[1].invoke());
print(outter[2].invoke());
print(outter[3].invoke());

View Code

运行的结果如何呢?0 1 2 3?这是很多人期望的答案,可是事实真的是这样吗?马上运行一下吧,是不是惊呆了?结果居然是4 4 4 4 !

其实,在每次迭代的时候,这样的语句x.invoke = function(){print(i);}并没有被执行,只是构建了一个函数体为”print(i);”的函数对象,如此而已。而当i=4时,迭代停止,外部函数返回,当再去调用outter[0].invoke()时,i的值依旧为4,因此outter数组中的每一个元素的invoke都返回i的值:4。如何解决呢,我们可以声明一个匿名函数,然后马上执行它。

function clouseTest2(){
var array = ["one", "two", "three", "four"];
for(var i = 0; i < array.length;i++){
var x = {};
x.no = i;
x.text = array[i];
x.invoke = function(no){
return function(){
print(no);
}
}(i);
outter.push(x);
}
}

View Code

这个例子中,我们为x.invoke赋值的时候,先运行一个可以返回一个函数的函数,然后立即执行之,这样,x.invoke的每一次迭代器时相当与执行这样的语句:

//x == 0
x.invoke = function(){print(0);}
//x == 1
x.invoke = function(){print(1);}
//x == 2
x.invoke = function(){print(2);}
//x == 3
x.invoke = function(){print(3);}

View Code

这样就可以得到正确的结果了。

可以根据Object.prototype.toString.Call(source)来判断给定对象的类型。另外还有两个地方需要注意:

1、如果变量作用域为函数内部则,则外部无法访问,如:

var person=function(){
var name="default";
return {
getName:function(){return name;},
setName:function(no){name=no}
}
}();
print(person.name)//undefined

View Code

2、引用

引用也是一个比较有意思的主题,JavaScript中的引用始终指向最终的对象,而并非引用本身,我们来看一个例子:

var obj = {};//空对象
var ref = obj;//引用
obj.name = "objectA";
print(ref.name);//ref跟着添加了name属性
obj = ["one", "two", "three"];//obj指向了另一个对象(数组对象)
print(ref.name);//ref还指向原来的对象
print(obj.length);//3
print(ref.length);//undefined

View Code

运行结果:

      objectA
      objectA
       3
      undefined

obj只是对一个匿名对象的引用,所以,ref并非指向它,当obj指向另一个数组对象时可以看到,引用ref并未改变,而始终指向那个后来添加了name属性的"空"对象”{}”。理解这个之后,下面这个例子就不难了:

var obj = {};//新建一个对象,并被obj引用
var ref1 = obj;//ref1引用obj,事实上是引用obj引用的空对象
var ref2 = obj;
obj.func = "function";
print(ref1.func);
print(ref2.func);

View Code

声明一个对象,然后用两个引用来引用这个对象,然后修改原始的对象,注意这两步的顺序,运行之:

     function
     function

     根据运行结果我们可以看出,在定义了引用之后,修改原始的那个对象会影响到其引用上,这一点也应该注意。

以上是最近发现的一些易错的地方,也希望您能将您遇到的易错问题分享出来,一起学习,共同进步!

posted on 2014-08-27 01:40 NET未来之路 阅读(...) 评论(...) 编辑 收藏

转载于:https://www.cnblogs.com/lonelyxmas/p/3938568.html

那些必须要知道的Javascript相关推荐

  1. 你必须要知道的JavaScript数据结构与面试题解答

    英文原文 | https://dev.to/educative/7-javascript-data-structures-you-must-know-4k0m 原文作者 | Ryan Thelin和A ...

  2. 5种你未必知道的JavaScript和CSS交互的方法

    随着浏览器不断的升级改进,CSS和JavaScript之间的界限越来越模糊.本来它们是负责着完全不同的功能,但最终,它们都属于网页前端 技术,它们需要相互密切的合作.我们的网页中都有.js文件和.cs ...

  3. 【译】5 个你需要知道的 JavaScript 小技巧

    JavaScript 是目前最流行的编程语言之一.就像其他任何编程语言一样,它也有很多小技巧,从今天开始你就可以使用它们 大多数程序员都应该每天训练这些小技巧,直到熟能生巧. 在这篇文章中,我们将一起 ...

  4. 每个JavaScript开发人员应该知道的33个概念

    每个JavaScript开发人员应该知道的33个概念 介绍 创建此存储库的目的是帮助开发人员在JavaScript中掌握他们的概念.这不是一项要求,而是未来研究的指南.它基于Stephen Curti ...

  5. 每一个JavaScript开发者都应该知道的10道面试题

    JavaScript十分特别.而且差点儿在每一个大型应用中起着至关关键的数据.那么,究竟是什么使JavaScript显得与众不同,意义非凡? 这里有一些问题将帮助你了解其真正的奥妙所在:   1.你能 ...

  6. 你需要知道的requestAnimationFrame

    你需要知道的requestAnimationFrame 随着前端的发展,css已经能够实现非常多的动画特效,但是仍然存在css无法完成的动画任务(比如页面滚动),通常的解决方案都是使用js中的setI ...

  7. 移动端适配(必须要知道的,亲测有效)

    关于移动端适配(必须要知道的,亲测有效) 一.各种单位概念理解 二.移动,web开发 三.移动端适配 1.视口(viewport)概念 2.视口(viewport)适配(代码) 3.rem单位适配 f ...

  8. css按钮居中_你不一定知道的CSS最小和最大(宽度/高度)知识点及优缺点

    通常,我们希望限制元素相对于其父元素的宽度,同时使其具有动态性.因此,有一个基础宽度或高度的能力,使其扩展的基础上,可用的空间.比如说,我们有一个按钮,它的宽度应该是最小的,不应该低于它的宽度.这就是 ...

  9. php要懂函数吗,九个你需要知道的PHP函数和功能

    9个你需要知道的PHP函数和功能 即使使用 PHP 多年,有些功能和特点我们也未必发现或未被充分利用,一旦被我们发现,就会发现它们非常有用.然而,并不是所有的人都已经从头至尾详读过 PHP 的手册和功 ...

最新文章

  1. 清华博士接亲被要求现场写代码,5 分钟做出一颗爱心
  2. metasploit 使用实例
  3. deepin系统引导_国产 Linux 发行版 深度操作系统 20 正式版发布
  4. 基于jquery的ajax聊天室系统,基于jQuery的Ajax聊天室应用毕业设计(含外文翻译)...
  5. mysql cmd链接不上数据库情况汇总
  6. why my SAP CRM One Order custom callback is not called
  7. php 如何调用redis,php如何调用redis
  8. mockito模拟依赖注入_使用Mockito模拟自动装配的字段
  9. mysql单表约束为_MySQL 表约束
  10. 谷歌开源 VR 应用
  11. Toml :设置策略配置文件
  12. PSPNet——Pyramid Scene Parsing Network
  13. 科学计算机怎么用10次方,一个数怎么用计算器开10次方
  14. 无剑100芯片平台的环境搭建
  15. 浅谈一个人做微信公众号是靠什么盈利的
  16. Ansible hosts文件写法
  17. Ubuntu 22.04 LTS 是史诗级的版本?
  18. activiti java service task 服务任务
  19. Altium Designer 制造输出 各文件后缀的含义
  20. SS7网络中的短消息服务(SMS): 使用模块化设备优化利润

热门文章

  1. [leetcode]746. 使用最小花费爬楼梯
  2. Unity3D实践2:控制物体移动与旋转
  3. Wannafly挑战赛9: D. 造一造(组合数)
  4. Stoer-Wagner无向图全局最小割(hduoj 3691 Nubulsa Expo)
  5. bzoj 3504: [Cqoi2014]危桥(最大流)
  6. [python] 字典:按key排序或按value排序
  7. Spark Standalone架构设计要点分析
  8. SpringMVC XXX-servlet.xml ApplicationContext.xml
  9. 迭代器、生成器、递归、二分法
  10. python装饰器@