函数对象

在javascript中,函数也可以被称之 "函数对象".我们可以为函数对象设置属性,赋值等操作.

//定义一个函数对象
function test(){}
//为函数对象设置任意属性,这里我们设置description(描述),用于描述该函数的作用
test.description = "这是一个测试函数"
//获取函数对象的描述属性
console.log(test.description);
//函数依然可以正常调用
test();

Prototype

在javascript编程中,所有的函数都有一个 prototype属性,该属性指向的是一个对象.我们称之为 原型对象.如下图

注意: 虽然每个函数都会有自己的原型对象,但是本课程中,我们只考虑构造函数的原型对象.

原型对象的作用

  • 共享属性和方法
  • 通过构造函数创建的实例对象,默认拥有该构造函数的原型对象的所有属性和方法
//定义一个构造函数
function Person(name,age){
    this.name = name;
    this.age = age;
}

//定义一个普通对象
var obj = {
    country:"中国",
    sayHi: function(){
        console.log("您好");
    }
}

//将Person构造函数的prototype属性指向obj,也就是将obj设置为Person构造函数的原型对象
Person.prototype = obj;

//创建Person的实例
var p1 = new Person("zmt",33);
//访问Person实例对象自带的属性
console.log(p1.name);
console.log(p1.age);
//访问原型对象的属性
console.log(p1.country);
p1.sayHi();

从上面的例子中,我们可以发现 当我们将Person构造函数的prototype属性指向obj对象的时候,通过Person构造函数创建出来的对象就默认拥有了obj对象的属性和方法了

多个构造函数的原型指向同一个对象

function Worker(){}
function Student(){}

var info = {
    country;"中国",
    play:function(game){
        console.log("玩"+game);
    }
}

Worker.prototype = info;
Student.prototype = info;

var w1 = new Worker();
w1.play("LOL");
console.log(w1.country);

var s1 = new Student();
s1.play("王者");
console.log(s1.country);

__proto__

每个非null实例对象,都默认拥有一个__proto__属性,该属性指向实例对象的构造函数的原型对象.

function Person(){}
var obj = {
    country:"中国"
}
Person.prototype = obj;
var p1 = new Person();

console.log(p1.__proto__);
console.log(Person);
console.log(p1.__proto__ === Person.prototype); //true

原型链

由于所有非null对象,都会有一个proto属性,当我们访问某个属性或者方法,如果在当前对象中没有该属性或方法,则会一直通过proto找到原型对象,如果原型对象也没有该属性和方法,则继续沿着原型对象的proto属性往上以及原型对象找,直到找到属性或者最终的对象为null时结束.在这个过程中,通过proto形成的线路,我们就称之为原型链.如下图

代码示例

function Person(name){
    this.name = name;
}
var obj = {
    country: "中国"
}
//将obj对象设置为Person构造函数的原型对象
Person.prototype = obj;
//创建Person实例
var p1 = new Person("zmt");
//访问p1对象的name属性
console.log(p1.name);
//访问原型对象的country属性
console.log(p1.country);
//访问一个p1对象和obj对象都不存在属性,得到结果为null
console.log(p1.cityname);
//查看obj的构造函数,得到结果是 ƒ Object() { [native code] }
console.log(obj.constructor);
//为obj的构造函数的原型对象新增一个cityname属性
obj.constructor.prototype.cityname = "深圳";
//再通过p1访问cityname
console.log(p1.cityname);

/*
根据原型链获取各自的原型对象
*/
console.log(p1.__proto__);//obj对象
console.log(p1.__proto__.__proto__);//Object对象
console.log(p1.__proto__.__proto__.__proto__);//最终结果为null

原型链在开发中的实际应用

  • 我们想要为数组新增一些功能,但是我们不能直接去修改JS源码,因此,可以通过网Array的构造函数的原型对象上新增函数的方式,为js数组进行扩展

  • 数组实现交集

    var front = ["html","css","js"];
    var back = ["java","mysql","spring","js"];
    Array.prototype.intersection = function(target){
     var _this = this;
     var rs = this.filter(function(item){
         return target.indexOf(item)>-1;
     })
     return rs
    }
    var result = front.intersection(back);
    console.log(result);
    
  • 实现并集
    var front = ["html","css","js"];
    var back = ["java","mysql","spring","js"];
    Array.prototype.union = function(target){
     var _this = this;
     //过滤target数组中的元素
     var rs = target.filter(function(item){
         return _this.indexOf(item)===-1
     })
     return  this.concat(rs);;
    }
    //直接通过front数组调用union函数
    var result = front.union(back);
    
  • 数组去重

    var arr1 = [1,2,4,3,4,1,2,3,5];
    //为数组构造函数的原型对象添加一个unique方法
    Array.prototype.unique = function(){
     /*
     用于存储已遍历过的元素,例如
     {
         1: true,
         2: true
     }
     */
     var rs = {}
     //将没有重复元素放到这个数组里
     var arr = []
     //this表示调用unique函数的数组
     this.forEach(function(item){
         if(!rs[item]){
             rs[item] = true;
             arr.push(item);
         }
     })
     return arr;
    }
    var result = arr1.unique();
    
  • 有时候我们要用到别人已经封装好的对象,但是功能不够,这时候我们虽然可以直接查看和修改该对象的源码.但是我们奉着不动别人代码一分一毫的原则,我们只能在该对象的构造函数的原型对象上动手脚了,代码如下

//假设这是你导入的别人封装好的对象,里面有很多方法,你不能直接在里面添加新的代码
var mtobj = {
    test:function(){
        console.log("测试");
    },
    print:function(){
        console.log("打印");
    }
}

//为mtobj对象的构造函数的原型对象添加新的函数
mtobj.constructor.prototype.sum = function(arr){
    var rs = 0;
    for(var i=0;i<=arr.length-1;i++){
        rs += arr[i];
    }
    return rs;
}
mtobj.__proto__.odd = function(arr){
    var rs = arr.filter(function(item){
        return item%2==1
    })
    return rs;
}
var result = mtobj.sum([1,2,3,4,5,6]);
console.log(result);

var result2 = mtobj.odd([1,2,3,4,5,6]);
console.log(result2);

results matching ""

    No results matching ""