JS基础之基本概念2

相等操作符

最早的ECMAScript中的相等和不相等操作符会在执行比较之前,先将对象转换成相似的类型。后来,有人提出了这种转换到底是否合理的质疑。最后ECMAScript的解决方案就是提供两组操作符:相等和不相等-先转换再比较,全等和不全等-仅比较而不转换。

在转换不同的数据类型时,相等和不相等操作符遵循下列基本规则:
1.如果有一个操作数是布尔值,则在比较相等性之前现将其转换为数值-false 转换为0,true 转换为1。
2.如果一个操作数是字符串,另一个操作数是数值,在比较相等性之前先将字符串转换为数值。
3.如果一个操作数是数值,另一个操作数不是,则调用对象的valueOf方法,用得到的基本类型值按照前面的规则进行比较;
基于第三点比较规则来说话,这两个操作符在进行比较时则要遵循下列规则:
a:nullundefined是相等的
b:要比较相等性之前,不能将nullundefined转换成其他任何值
c:如果有一个操作数是NaN,则相等操作符也返回false,而不相等操作符返回true重要提示:即使两个操作数都是NaN,相等操作符也返回false,因为按照规则,NaN不等于NaN
d:如果两个操作数都是对象,则比较它们是不是同一个对象。如果两个操作数都指向同一个对象,则相等操作符返回true,否则,返回false

break/continue/ return语句

break用于完全结束一个循环,跳出循环体。不管是哪种循环,一旦在循环体中遇到break,系统将完全结束循环,开始执行循环之后的代码。break不仅可以结束其所在的循环,还可结束其外层循环。
continue语句会立即退出当前循环,然后继续执行后面的循环,直到循环结束。而break则是完全中止循环。
return关键字并不是专门用于跳出循环的,return的功能是结束一个方法。 一旦在循环体内执行到一个return语句,return语句将会结束该方法,循环自然也随之结束。与continuebreak不同的是,return直接结束整个方法,不管这个return处于多少层循环之内。
以下是三段代码来表示三者的区别:

//break
var num = 0;
for(var = 1 ; i < 10 ; i++){
  if(i%5 == 0){
    break;  
  }
  num++;
}
alert(num);  //4
//continue
var num = 0;
for(var = 1 ; i < 10 ; i++){
  if(i%5 == 0){
    continue;  
  }
  num++;
}
alert(num);  //8
//return
function test(i){
    if(i == 3){
        return 
    }
    console.log(i)
}
for (var i = 0; i < 10 ; i++ ){
  test(i)
} // 0 1 2 4 5 6 7 8 9 
width语句

width语句在开发中很少会用到,本来不想写它,后来想了想,其特殊的语法形式,也有必要写下来。
width语句的作用是将代码的作用域设置到一个特定的环境中。定义width语句的目的主要为了简化多次编写同一个对象的工作。如下:

var qs = location.search.substring(1);
var hostName = location.hostname;
var url = location.href;

上面代码块多次用到location这个对象,如果使用width语句可以写成如下所示:

width(location){
  var qs = serarch.substring(1);
  var hostName = hostname;
  var url = href;
}

使用width语句,从写法上来说变的复杂了,将简单的取值赋值语句包在了函数写法中。再看一下以下的写法:

width(window){
  var qs = window.location.serarch.substring(1);
  var hostName = window.location.hostname;
  var url = window.location.href;
}

这样,就好理解width语句真正的作用。
从运行环境上来说,width语句的代码块内部,每个变量首先被认为是一个局部变量,而如果在局部环境中找不到该变量的蒂尼,就会查询location对象中是否有同名属性。如果发现了同名属性,则以location对象属性的值作为变量的值。
大量使用width语句会导致性能下降,也会让调试代码变得困难,而且在严格模式下不允许使用width语句,否则将会视为语法错误。

理解函数的参数

在给一个函数传递参数时,我们可以显式的传参,也在不传参的情况下,用arguments这个对象来表示传入到函数中的参数。
函数传参有这么一条潜规则:你可以多传参数,函数体内部可以不用,但是你不可以少传参数,那函数体内部就会报错。
从函数接受参数的情况来看,函数接收到的参数在函数内部始终会用arguments这个对象来表示。arguments是一个类数组的对象,但它并不是Array的实例。你可以用数组的方法访问arguments对象中的每一项,arguments[0],arguments[1]......。所以arguments的长度是由传入的参数个数决定的,没有传入参数就会自动被赋予undefined值。

function test(a,b){
    console.log(typeof arguments)
}
test(1,2)  //'object'

另外还有一点,arguments的类型是object,这一点别忘了。
最后还有一点,arguments对象内部每一项的值都会与传入的参数一一对应,注意:是每一项的值。也就是说,传入的参数值与arguments中对应的值会保持同步,不过,由于arguments这个对象始终存在并作用于函数体内部,并且读取传入的参数值和读取对应arguments对象内部的值并不是访问相同的内存空间,他们的内存空间是独立的。

函数重载

首先理解什么是函数重载?
函数重载是函数的一种特殊情况,允许在同一范围中声明几个功能类似的同名函数,但是这些同名函数的[形式参数](指参数的个数、类型或者顺序)必须不同,也就是说用同一运算符完成不同的运算功能。这就是重载函数。重载函数常用来实现功能类似而所处理的数据类型不同的问题。不能只有函数返回值类型不同。
但是在js中,函数是无法重载的,例如:

function test(num){
  return num+100
}
function test(num){
  return num+200
}
var result = test(100); //300

不过,由于函数中有arguments这个对象,我们可以根据它的长度,类型或者顺序来实现函数重载。
这里说一个非常典型的案例:

我们现在有这样的一个需求,有一个people对象,里面存着一些人名,如下:

var people = {
  values: ["Dean Edwards", "Sam Stephenson", "Alex Russell", "Dean Tom"]
};

我们希望people对象拥有一个find方法,当不传任何参数时,就会把people.values里面的所有元素返回来;当传一个参数时,就把first-name跟这个参数匹配的元素返回来;当传两个参数时,则把first-name和last-name都匹配的才返回来。因为find方法是根据参数的个数不同而执行不同的操作的,所以,我们希望有一个addMethod方法,能够如下的为people添加find的重载:

addMethod(people, "find", function() {}); /*不传参*/
addMethod(people, "find", function(a) {}); /*传一个*/
addMethod(people, "find", function(a, b) {}); /*传两个*/

还有一个问题,就是这个全局的addMethod方法该怎么实现呢?如下所示

function addMethod(object, name, fn) {
  var old = object[name]; //把前一次添加的方法存在一个临时变量old里面
  object[name] = function() { // 重写了object[name]的方法
    // 如果调用object[name]方法时,传入的参数个数跟预期的一致,则直接调用
    if(fn.length === arguments.length) {
      return fn.apply(this, arguments);
    // 否则,判断old是否是函数,如果是,就调用old
    } else if(typeof old === "function") {
      return old.apply(this, arguments);
    }
  }
}

现在,我们一起来分析一个这个addMethod函数,它接收3个参数,第一个为要绑定方法的对象,第二个为绑定的方法名称,第三个为需要绑定的方法(一个匿名函数)。函数体的的分析已经在注释里面了。
OK,现在这个addMethod方法已经实现了,我们接下来就实现people.find的重载啦!全部代码如下:

//addMethod
function addMethod(object, name, fn) {
  var old = object[name];
  object[name] = function() {
    if(fn.length === arguments.length) {
      return fn.apply(this, arguments);
    } else if(typeof old === "function") {
      return old.apply(this, arguments);
    }
  }
}
 
 
var people = {
  values: ["Dean Edwards", "Alex Russell", "Dean Tom"]
};
 
/* 下面开始通过addMethod来实现对people.find方法的重载 */
 
// 不传参数时,返回peopld.values里面的所有元素
addMethod(people, "find", function() {
  return this.values;
});
 
// 传一个参数时,按first-name的匹配进行返回
addMethod(people, "find", function(firstName) {
  var ret = [];
  for(var i = 0; i < this.values.length; i++) {
    if(this.values[i].indexOf(firstName) === 0) {
      ret.push(this.values[i]);
    }
  }
  return ret;
});
 
// 传两个参数时,返回first-name和last-name都匹配的元素
addMethod(people, "find", function(firstName, lastName) {
  var ret = [];
  for(var i = 0; i < this.values.length; i++) {
    if(this.values[i] === (firstName + " " + lastName)) {
      ret.push(this.values[i]);
    }
  }
  return ret;
});
 
// 测试:
console.log(people.find()); //["Dean Edwards", "Alex Russell", "Dean Tom"]
console.log(people.find("Dean")); //["Dean Edwards", "Dean Tom"]
console.log(people.find("Dean Edwards")); //["Dean Edwards"]
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • [爱心]心在哪里,收获就在哪里。 人这一生能力有限,但是努力无限, 努力做一个善良的人, 做一个心态阳光的人, 做...
    爱心客站阅读 1,270评论 0 1
  • 分析暂时不介绍
    52_St阅读 3,811评论 0 0
  • 昨晚老公跟他朋友喝酒喝到凌晨两点到家,他把我叫醒,看他心情极差。因为儿子最近学业很苦,他打电话给前妻,希望对方来关...
    多多少少7阅读 2,047评论 0 3

友情链接更多精彩内容