技术码头

JS 函数

2020-01-07  本文已影响0人  石菖蒲_xl

函数

js的函数时参数化的:


函数的定义

函数使用 function关键字来定义:
1、函数定义表达式
2、函数声明语句

// 函数声明
function init () {
  //do something
}
// 函数定义表达式
var init = function () {
   // do something
}
init();
function init () { // }
init(); // 报错   init is not a function 
var init = function () {};
init(); // 成功调用

函数命名

函数调用

定义函数并不会执行,只有调用该函数时,它们才会执行,有4种方式调用:
1、作为函数
2、作为方法:保存在一个对象的属性里的js函数
3、作为构造函数
4、通过它们的call()apply()方法间接调用
任何函数只要作为方法调用实际上都会传入一个隐式的的实参——这个实参是一个对象,方法调用的母体就是这个对象。

var o = {
  m:function () {                  // 挂载在对象上的方法 m()
    var self = this;              //  将this的值保存至一个变量中
    console.log(this === o);     // => true this 就是当前这个对象 o
    f();
    function f () {             // 定义一个嵌套函数f()
      console.log(this);       // => Window
      console.log(this === o); // => false  this 的值是全局对象或者undefined
      console.log(self === o); // => true self 变量保存的是外部函数的this
    }
  }
}
var w = function () {
  console.log('w',this); // => 输出对象o
  console.log(o === this); // => true 
}
o.n = w;
o.n(); 
o.m();

构造函数调用
如果函数或者方法调用之前带有关键字new,它就构成构造函数调用

var o = new Object();
var o = new Object;  // 凡是没有形参的构造函数调用都可以省略括号
var o = {
  m:function (x) {                 // 挂载在对象上的方法 m()
    var self = this;              //  将this的值保存至一个变量中
    console.log(this);           // 输出的是对象d
    console.log(this.w);        // => undefined 对象d在调用构造函数的时候还未添加属性 w
    console.log(this === o);   // => false 此时this是调用构造函数创建的d
    this.x = x;                 // => 调用构造函数创建对象时添加的参数,给新创建对象指定 属性 x 并为其复制
    f();
    function f () {             // 定义一个嵌套函数f()
      console.log(this === o); // => false this的值是全局对象或者undefined
      console.log(self === o); // => false 对象 d
      console.log(this);       // => Window 对象
    }
  }
}
var d  = new o.m(1);        // 通过构造函数创建一个新对象
d.w = "scp"
console.log(d.x);           // => 1 调用构造函数时添加的属性值

实参列表(arguments)

init(1,2,3)
function init(){
  console.log(arguments[0]); // => 1
  console.log(arguments[1]); // => 2
  console.log(arguments[2]); // => 3
}
init(1,2,3);
function init () {
  console.log(arguments.length); // => 3 传入三个参数
}
max(1,2,3,100);
function max () {
  var max = Number.NEGATIVE_INFINITY; // 负无穷
  for (var i = 0; i < arguments.length; i ++) {
    if (arguments[i] > max) {
      max = arguments[i];
    }
  }
  return max;
}
// 
Math.max(1,2,3,100);
var init = function () {
  if (arguments.length < 2){
    arguments.callee(1,2)
  }
  console.log(arguments.length); // => 1   2
}
init(1);

闭包

首先回顾一下变量 作用域 和 作用域链

var a = 'global';   // 全局变量
function init () {
  var a = 'local';  // 同名的局部变量
  console.log(a); // => "local"
}
init();
var a = 'global';   // 全局变量
function init () {
  var a = 'local';  // 同名的局部变量

  console.log(a); // => local
  
  function n (){
    var a = 'n local';
    console.log(a); // => n local
  }
}
init();

函数作用域和声明提前

var a = 'global';    // 声明一个全局变量
function f () {
  console.log(a);  // => "undefined" 并没有输出“global”
  var a = 'local';    // 变量在这里声明并赋值,但是变量在函数体内任何地方都是有定义的
  console.log(a); // => "local"
}
// 如上 等价于
function f () {
  var a;                  //   在函数顶部声明了局部变量
  console.log(a);  //   变量存在,但是未赋值,所以值是undefined
  a = "local";        //   对局部变量进行赋值
  console.log(a); //   => "local"
}

作用域链
变量取值是到创建这个变量的函数作用域中取值,如果当前作用域没有取到值,就会到上一级作用域去查,直到查到全局作用域,这么一个查找的过程形成的链条就叫作用域链

var a = 1;
function i_a () {
  var b = 2;
  function i_b () {
    var c = 3;
    console.log(a + b + c);     // => 6
  }
  i_b(); 
}
i_a(); 

闭包

利用闭包实现私有属性的读写

function counter(){
  var n = 0;
  return {
    count:function(){
        return n++;
    },
    reset:function(){
        n = 0;
    }
  }
}
var c = counter();
console.log(c.count()); // => 0
console.log(c.count()); // => 1
c.reset(); // 重置变量
console.log(c.count());  // => 0

函数属性、方法和构造函数

length属性

function counter(x){
    var arg_length = arguments.length;
    var ex_length = arguments.callee.length;

    console.log("arg_length:",arg_length); // => 2 实际传入两个参数
    console.log("ex_length:",ex_length); // => 1 定义函数时定义了一个参数
}
counter(1,1);

prototype属性

每个函数都包含一个prototype属性,这个属性是指向一个对象的引用,这个对象称做“原型对象”,每个函数都包含不同的原型对象,当将函数做构造函数的时候,新创建的对象会从原型对象上继承属性。

方法的prototype属性
function counter () {
}
var c = new counter();

call()方法和apply()方法

var o = {
  name:"my name is o"
}
function f () {
  console.log(this);   // => {name: "my name is o"} 此时this指向调用者o
  console.log(this.name); // => "my name is o"
}
f.call(o);
f.apply(o); // 俩个调用结果是一样的
var o = {
    name:'my name is o'
}

function counter(){
    console.log(arguments.length); // => 2 传入两个参数
    console.log(this.name);  // => 'my name is o'
    console.log("my height is " + arguments[0] + 'cm'); // => 'my height is 180cm'
    console.log("my weight is " + arguments[1] + 'kg'); // => 'my weight is 70kg'
}
counter.call(o,180,70);
counter.apply(o,[180,70]);

bind()方法

bind()用来将函数绑定至某个对象。

function f() {
  return this.x + 1;
}
var o = {x:1};
f.bind(o)(); // => 输入2 会把f当做o的方法来调用

上一篇下一篇

猜你喜欢

热点阅读