js面向对象学习笔记

1.函数的定义方式
第一种定义方式
function fn1() {
        alert("fn1");
    }
alert(fn)
函数就是一个特殊的对象,是一个Function类的实例,其实在内存中存储的操作是通过一个键值对来存储的
由于函数是一个对象,所以可以通过如下方式定义
以下是通过函数的拷贝来完成赋值,两个引用并没有指向同一个对象
var fn2 = fn1;
    fn2(); // fn1
两个值虽然相等但是指向的是不同的空间、
两者是如下图引用的:
所以,此时改变fn1,fn2的值不会改变:
如:
fn1 = function() {
        alert("fnn1");
    }
fn2();//fn1
fn1();//fnn1

 所以函数虽然是一个对象,但是却和对象有一些区别,对象是通过引用的指向完成对象的赋值的,而函数却是通过对象的拷贝来完成的。

所以fn1虽然变了,并不会影响fn2。
而对于对象而言,是通过引用的指向来完成赋值的,如下例子,此时修改o1或者o2会将两个值都完成修改。
因为o1和o2指向了同一块空间,当修改o2的值的时候,o1也会被修改
var o1 = new Object();
    var o2 = o1;
    o2.name = "Leon";
    alert(o1.name);//Leon

再说一遍:函数就是对象。
2.函数的重载
首先看下面的案例
function sum(num1,num2) {
         return num1+num2;
    }
 
    function sum(num1) {
         return num1+100;
     }
     alert(sum(10));//110
     alert(sum(10,20));//110
下面两个参数的并没有调用上面的还是调用的第二个,
现在用变量的方式重写下:
var sum = function(num1,num2) {
        return num1+num2;
    }
var sum = function(num1) {
        return num1+100;
    }
也就是说,此时sum所指向的空间已经从有两个参数的函数变化到只有num1的函数中。在调用的时候就只会调用只有num1的函数。特别指出:函数的参数和调用没有关系,如果函数只有一个参数,但是却传入了两个参数,仅仅只会匹配一个,
所以在js中函数不存在重载,只存在覆盖,后面定义的会覆盖前面定义的。
函数有如下一种定义方式:
var fn = new Function("num1","num2","alert('fun:'+(num1+num2))");
这种定义方式等于定义了一个
 function fn(num1,num2){
     alert(num1+num2);
   }
所以通过上面的例子,充分的说明函数就是一个对象。也就是说可以改变名字,可以把函数作为参数传到函数中。

3.函数的传值
由于函数是对象,所以可以直接把函数通过参数传递进去。如下调用案例:
    function callFun(fun,arg) {
        //第一个参数就是函数对象
        return fun(arg);
    }
    
    function sum(num) {
        return num+100;
    }
    
    function say(str) {
        alert("hello "+str);
    }
    //var say = xxx
    //调用了say函数
     callFun(say,"eve");//hello eve
    //调用了sum函数
    alert(callFun(sum,20));//120
    
    function fn1(arg) {
        var rel = function(num) {
            return arg+num;
        }
        return rel;//此时返回的是一个函数对象
    }
    //此时f是一个函数对象,可以完成调用
    var f = fn1(20);
    alert(f(20));//40
    alert(f(11));//31
如排序sort默认是按照字符串排序的,如果想要排序一个有字符串的数组时候也是把排序函数作为参数传进去。
function sortByNum(a,b) {
            return parseInt(a)-parseInt(b);//当进行减法的时候,会自动完成字符串转换
     }
var as = [1,2,"11px",33,"12px",190];
as.sort(sortByNum);
 console.log(as);//1, 2, "11px", "12px", 33, 190]
如果测试对象来排序
    function Person(name,age) {
            this.name = name;
            this.age = age;
        }
        var p1 = new Person("Leno",39);
        var p2 = new Person("John",23);
        var p3 = new Person("Ada",41);
        var ps = [p1,p2,p3];
        ps.sort(sortByAge);
       // p1.name,p1["name"];
        function sortByName(obj1,obj2) { //根据姓名排序
             if(obj1.name>obj2.name) return 1;
             else if(obj1.name==obj2.name) return 0;
             else return -1;
          }
        function sortByAge(obj1,obj2) {//根据年龄排序
            return obj1.age-obj2.age;
            }
        function show() {
            var p = document.getElementById("person");
            for(var i=0;i<ps.length;i++) {
                p.innerHTML+=ps[i].name+","+ps[i].age+"<br/>";
            }
        }
        show();

 使用以上方法来处理排序,带来的问题是需要为每一个属性都设置一个函数,如果有五十个属性呢,显然不灵活  ,但是如果通过函数的返回值调用就不一样了。
ps.sort(sortByProperty("name"));
function sortByProperty(propertyName) {
    var sortFun = function(obj1,obj2) {
    if(obj1[propertyName]>obj2[propertyName]) return 1;
    else if(obj1[propertyName]==obj2[propertyName])return 0;
    else return -1;
     }
        return sortFun;
 }
这样就通过返回函数来灵活的实现了函数的排序功能。

4.函数的属性

arguments:不定参,通过这个属性可以获取相应的参数值,这个属性 返回值 是一个数组,其实就是传递进来的参数。在不知道函数到底有几个参数的时候用次属性。如下方式调用,

function say(num) {
        alert(arguments.length);//1
        for(var i=0;i<arguments.length;i++) {
            alert(arguments[i]);//5
        }
        alert(num);//5
}
say(5);

在arguments这个对象中有一个callee的方法,arguments.callee(arg)可以反向的调用。 

  1. arguments.callee 在 ES5 strict模式中禁止被使用。
function factorial(num) {
 if(num<=1) return 1; 
   //此时和函数名耦合在一起
   // else return num*factorial(num-1);
  //以下就实现了函数名的解耦合,在js中通常都是使用这种方式做递归
  else return num*arguments.callee(num-1);
         
}
但是这个解决方案并不好,在这种方式下用函数表达式实现尾递归十分困难,另一个主要问题是这样的递归调用会产生新的 this 引用。

this

当需要创建一个类的时候,设置类的属性和方法需要通过this关键字来引用但是特别注意:this关键字在调用时会根据不同的调用对象变得不同

/*** 创建了一个类,有一个color的属性和一个show的方法*/
function Circle(color) {
    this.color = color;
    this.showColor = showColor;
}
    
var c = new Circle("yellow");
//使用c来调用showColor方法,等于调用了showColor()方法
//此时的this是c,所以color就是yellow
c.showColor();//yellow
//此时调用的对象等于是window,showColor的this就是window,所以就会找window中color
showColor();//red

原文地址:https://www.cnblogs.com/eveblog/p/5360432.html