那些必须要知道的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=;i<obj1.length;i++){
//do something
}
//此时的i为未定义
for(int i=;i<obj2.length;i++){
//do another thing
}
}
而在Javascript中不同:
function func(){
for(var i = 0; i < array.length; i++){
//do something here.
}
//此时i仍然有值,及I == array.length
print(i);//i == array.length;
}
Javascript的函数是在局部作用域内运行的,在局部作用域内运行的函数体可以访问其外层的(可能是全局作用域)的变量和函数。JavaScript的作用域为词法作用域,所谓词法作用域是说,其作用域为在定义时(词法分析时)就确定下来的,而并非在执行时确定,如下例:
var str = "global";
function scopeTest(){
print(str);
var str = "local";
print(str);
}
scopeTest();
您觉得运行结果是什么呢?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());
运行的结果如何呢?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);
}
}
这个例子中,我们为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);}
这样就可以得到正确的结果了。
可以根据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
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);//
print(ref.length);//undefined
运行结果:
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);
声明一个对象,然后用两个引用来引用这个对象,然后修改原始的对象,注意这两步的顺序,运行之:
function
function
根据运行结果我们可以看出,在定义了引用之后,修改原始的那个对象会影响到其引用上,这一点也应该注意。
以上是最近发现的一些易错的地方,也希望您能将您遇到的易错问题分享出来,一起学习,共同进步!
那些必须要知道的Javascript的更多相关文章
- [译] 你该知道的javascript作用域 (javascript scope)(转)
javascript有一些对于初学者甚至是有经验的开发者都难以理解的概念. 这个部分是针对那些听到 : 作用域, 闭包, this, 命名空间, 函数作用域, 函数作用域, 全局作用域, 变量作用域( ...
- 5种你未必知道的JavaScript和CSS交互的方法
随着浏览器不断的升级改进,CSS和JavaScript之间的界限越来越模糊.本来它们是负责着完全不同的功能,但最终,它们都属于网页前端技术,它们需要相互密切的合作.我们的网页中都有.js文件和.css ...
- 你应该知道的JavaScript中NaN的秘密
NaN,不是一个数字,是一种特殊的值来代表不可表示的值,使用typeof或其他任何与之比较的处理方式,‘NaN’则会引起一些混乱, 一些操作会导致NaN值的产生.这里有些例子: Math.sqrt(- ...
- Web程序员应该知道的Javascript prototype原理
有同事问了我几个和Javascript的类继承的小问题,我在也不太理解的情况下,胡诌了一通. 回来以后有些内疚, 反省一下, 整理整理Javascript的prototype的原理, 自己清楚点, 也 ...
- 今天才知道的JavaScript的真实历史~[转]
JavaScript真的继承自Cmm吗?JavaScript与Java有多少关系?JavaScirpt最初的设计是怎样的?这个文章是从一个叫编程人生的网站上看到的.不知道出处在哪.在许多资料,Java ...
- 你需要知道的 JavaScript 类(class)的这些知识
作者: Dmitri Pavlutin译者:前端小智来源:dmitripavlutin 点赞再看,养成习惯 本文 GitHub https://github.com/qq44924588... 上已经 ...
- 7种你应该知道的JavaScript常见的错误
转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 原文出处:https://blog.bitsrc.io/types-of-native-errors-in- ...
- 对于JavaScript的函数.NET开发人员应该知道的11件事
(此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 昨天小感冒今天重感冒,也不能长篇大论.如果你是.NET开发人员,在进入前端开发领域的时候,对 ...
- 每一个JavaScript开发者都应该知道的10道面试题
JavaScript十分特别.而且差点儿在每一个大型应用中起着至关关键的数据.那么,究竟是什么使JavaScript显得与众不同,意义非凡? 这里有一些问题将帮助你了解其真正的奥妙所在: 1.你能 ...
随机推荐
- android 更新实现自己主动
其主要原理是: 在应用程序启动.取server在版本 , 以下这个是获取当前应用的版本号信息 private void getCurVersion() { try { PackageInfo pInf ...
- SQL入门学习3-数据更新
4-1 数据的插入(INSERT语句的使用方法) 使用INSERT语句可以向表中插入数据(行).原则上,INSERT语句背刺执行一行数据插入. CREATE TABLE 和INSERT 语句,都可以设 ...
- 准确率和召回率(precision&recall)
在机器学习.推荐系统.信息检索.自然语言处理.多媒体视觉等领域,常常会用到准确率(precision).召回率(recall).F-measure.F1-score 来评价算法的准确性. 一.准确率和 ...
- 基于hadoop的电影推荐结果可视化
数据可视化 1.数据的分析与统计 使用sql语句进行查询,获取所有数据的概述,包括电影数.电影类别数.人数.职业种类.点评数等. 2.构建数据可视化框架 这里使用了前端框架Bootstrap进行前端的 ...
- Rational Rose 2007使用小结
1.Rose怎样隐藏类的属性和操作? 右击类,选Options->Suppress Attributes/Suppress Operations 2.Rose怎样表示类的约束? 在工具箱中选AB ...
- 【剑指offer】:Q44:直扑克
def IsContinuous(seq, num = 5): zeros = 0; d = 0 seq = sorted(seq) for i in range(num - 1): if seq[i ...
- neu1458 方格取数 dp解法
题意: 有N * N个格子,每一个格子里有正数或者0,从最左上角往最右下角走,仅仅能向下和向右,一共走两次(即从左上角走到右下角走两趟),把全部经过的格子的数加起来,求最大值SUM,且两次假设经过同一 ...
- Ubuntu 中查看内核版本和系统版本的三个命令
一.查看内核版本:cat /proc/version 二.查看内核版本:uname -a 三.查看系统版本:lsb_release -a 四.查看发行版类型:cat /etc/issue
- Do a “git export” (like “svn export”)?(转)
Probably the simplest way to achieve this is with git archive. If you really need just the expanded ...
- /proc/mtd 各参数的含义 -- linux内核
经/proc虚拟文件系统读取MTD分区表:cat /proc/mtd mtd .name = raspi, .size = 0x00400000 (4M) .erasesize = 0x0001000 ...