js函数调用方式

函数对象

javascript中函数就是对象.对象是键值对的集合并拥有一个连接到原型对象的隐藏连接.
对象字面量产生的对象连接到Object.prototype.函数对象连接到Function.prototype

调用

除了声明时定义的形式参数,每个函数还接收两个附加的参数:thisarguments
this在面向对象编程中非常重要,它的值取决于调用的模式.在javascript中一共有4种调用模式:方法调用模式,
函数调用模式,构造器调用模式apply调用模式.这些模式在初始化关键参数this上存在差异.

方法调用模式(The method invocation pattern)

当一个函数被保存为对象的一个属性时,我们称它为一个方法.当一个方法被调用时,this被绑定到该对象.

//创建myObject对象.它有一个value属性和一个increment方法
var myObject = {
  value:0,
  increment:function(inc){
    this.value += typeof inc === 'number' ? inc : 1;
  }
}
myObject.increment();
console.log(myObject.value);//1
myObject.increment(2);
console.log(myObject.value);//3

方法可以使用this访问自己所属的对象,所以它能从对象中取值或对对象进行修改.this到对象的绑定发生在调用的时候.

函数调用模式(The function invocation Pattern)

当一个函数并非一个对象的属性时,那么它就是被当做一个函数来调用的.

function add(){
  var sum = 0;
  for(var i = 0, len = arguments.length; i < len; ++i){
    sum += arguments[i];
  }
  return sum;
}
add(1,2,3);

以此模式调函数时,this会被绑定到全局对象.这是语言设计上的错误.
倘若语言设计正确,那么内部函数被调用时,this应该仍然绑定到外部函数的this变量.
这个设计错误的后果就是方法不能利用内部函数来帮助它工作,因为内部函数的this被绑定了错误的值,所以不能共享该方法对对象的访问权.
幸运的是,有一个很容易的解决方案:如果该方法定义一个变量并给它赋值为this,那么内部函数就可以哪个变量访问到this.
按照约定,我把哪个变量命名为that.

myObject.double = function(){
  var that = this;  //解决方法
  var helper = function(){
    that.value = add(that.value,that.value);
  }
  helper();//以函数形式调用helper
}
//以方法调用double
myObject.double();
console.log(myObject.value);

构造器调用模式(The constructor invocation pattern)

javascript时一门基于原型继承的语言,这意味着对象可以直接从其他对象继承属性.
这偏离了当今编程语言的主流风格.当今大多数语言都是基于类的语言.尽管原型继承极富表现力,但它并未被广泛理解.
javascript对它原型本质也缺乏信心,所以它提供了一套和基于类继承语言的语法模糊了这门语言真实的原型本质,真是两边都不讨好.

如果在一个函数前面带上new来调用,那么会自动创建一个连接到该函数的prototype成员的新对象,同时this会被绑定到那个对象上.

//创建一个名为Que的构造器函数,它构造一个带有status属性的对象.
var Que = function(str){
  this.status = str;
}
Que.prototype.get_status = function(){
  return this.status;
}
//构造一个Que实例
var myQue = new Que("confused");

一个函数,如果创建的目的就是希望结合new前缀来调用,那它就被称为构造器函数.按照约定,它们保存在以大写格式命名的变量里.
如果调用构造函数时没有在前面加上new,可能会发生非常糟糕的事情,即没有编译时警告,也没有运行时警告,所以大写约定非常重要.

apply调用模式

因为javascript是一门函数式的面向对象编程语言,所以函数也可以拥有方法.
当使用 Function.prototype 上的call或者apply方法时,函数内的 this 将会被 显式设置为函数调用的第一个参数。
apply方法接收两个参数,第一个是要绑定给this的值,第二个是参数数组.
call方法参数,第一个是要绑定给this的值,之后是需要传入的参数

//构造一个包含status成员的对象
var statusObj = {
  status:"apply status"
};

Que.prototype.get_status.apply(statusObj,[1,2,3]);
Que.prototype.get_status.call(statusObj,1,2,3);
const EventEmitter = require('events');
const util = require('util');

//继承EventEmitter
function MyEmitter() {
  //通过new调用时this指向MyEmitter实例化对象
  EventEmitter.call(this);
  //EventEmitter函数的this也指向MyEmitter实例化对象
}
//继承EventEmitter的方法
util.inherits(MyEmitter, EventEmitter);

const myEmitter = new MyEmitter();
myEmitter.on('event', () => {
  console.log('an event occurred!');
});
myEmitter.emit('event');
var domain;

function EventEmitter() {
  EventEmitter.init.call(this);
}
module.exports = EventEmitter;
EventEmitter.prototype.domain = undefined;
EventEmitter.prototype._events = undefined;
EventEmitter.prototype._maxListeners = undefined;

EventEmitter.init = function() {
  this.domain = null;
  if (EventEmitter.usingDomains) {
    // if there is an active domain, then attach to it.
    domain = domain || require('domain');
    if (domain.active && !(this instanceof domain.Domain)) {
      this.domain = domain.active;
    }
  }

  if (!this._events || this._events === Object.getPrototypeOf(this)._events) {
    this._events = {};
    this._eventsCount = 0;
  }

  this._maxListeners = this._maxListeners || undefined;
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值