JS函数解释

JS函数解释(内嵌、对象)

常用写法

function add(a, b) {
  return a + b;
}

add(1,2); // 3

匿名函数

var add = function(a,b) {
  return a+b;
}
add(1,2); // 3

这个代码和前面常用写法计算结果一致,但它更让你感觉到函数是一个对象,而且我们为这个对象指定了一个名称。如同var myVar = [1,2,3]语句一样。当我们指派一个这样的函数时,并不一定要求必须是匿名函数。

var add = function theAdd(a, b) { return a + b; }
add(1,2) // 3

使用匿名方式定义函数在面向对象编程中很有用,因为我们能使一个匿名函数成为一个对象的属性。

var myObject = new Object();
myObject.add = function (a, b) {return a+b;}
// 现在myObject有一个叫做"add"的方法
myObject.add(1,2); //3

函数对象

函数是JavaScript中的一种特殊形式的对象。我们能够为它增加属性

对象的创建

当我们定义一个函数时,JavaScript实际上创建一个对象,这个对象的名称就是<b>函数名本身</b>。这个对象的类型是<b>Function</b>

function Ball() { i = 1; }
console.log(typeof(Ball)); // function
属性添加

我们可以给Object添加属性,包括对象function。因为定义一个函数的实质是创建一个对象。

function Ball() { console.log('ball'); }
Ball.callsign = "The ball";
console.log(ball.callsign); // The ball
指针

为Function对象分配一个指针,如下:

function myFunction(message) {
  console.log(message)
}
var ptr = myFunction;
prt("Hello"); // Hello

我们运行这个函数,就好像这个函数名已经被指针代替类似。所以在上面,这行ptr("hello")和myFunction("hello")效果一致。指向函数的指针在面向对象编程中相当有用。例如:当我们有多个对象指向同一函数时,如下:

function myFunction() { console.log(myFunction.initalName); }
myFunction.initalName = "Adu03";
var ptr1 = myFunction;
var ptr2 = myFunction;
ptr1(); // Adu03
ptr2(); // Adu03
myFunction.initalName = 'new Adu03';
ptr1(); // new Adu03
ptr2(); // new Adu03

当我们在函数创建后重新分配它时,我们需要指向函数本身,而不是它的指针,如果我们需要保留它,我们可以在改变它之前给它分配一个指针。

function myFunction() { console.log("old"); }
var savefunction = myFunction;
myFunction = function() { console.log("new"); }
myFunction(); // new
savefunction(); // old
内嵌函数

你只有在内部调用嵌套函数。内嵌函数会被编译,但只有当你去调用它的时才会执行。

function calculate(n) { return n/3; }
function getHalfOf(n1, n2, n3) {
  function calculate(n) { return n/2; }
  var result = "";
  result += calculate(n1) + " ";
  result += calculate(n2) + " ";
  result += calculate(n3) + " ";
  return result;
}
var resultString = getHalfOf(10, 20, 30);
console.log(resultString); // 5 10 15

在上面的例子中,编译器首先会搜素局部内存地址,所以会找到内嵌的calculate函数,如果我们删除局部函数,这个代码会调用全局的calculate函数。

函数:数据类型及构造函数

我们来看函数的另一个特殊功能,这让它和其他对象截然不同。一个函数可以作为一个数据类型的蓝图。这个特性通常被用在面向对象编程中来模拟用户自定义数据类型(user defined data type)。使用用户自定义数据类型创建的对象通常被自定义对象(user defined object)

数据类型

在定义了一个函数后,我们也同时创建了一个新的数据类型。这个新的数据类型能够用来创建一个新对象。下面,我们创建一个叫做Ball的新数据类型

function Ball(message) {
  console.log(message)
}
var ball0 = new Ball("creating new ball");
// creating new ball
ball0.name = "adu03" // 给对象添加属性
console.log(ball0.name);

这样看来,ball0=new Ball()做了什么?new 关键字创建了一个类型为Object的新对象(叫做ball0)。然后它会执行Ball(),并将这个引用传给ball0(用于对象的调用)。
上面代码是下面代码的简写

function Ball(message) { console.log(message) }
var ball0 = new Object();
ball0.construct = Ball;
ball0.construct("creating new ball"); // 执行ball0.Ball
ball0.name = 'adu03';
console.log(ball0.name);
this关键字增加属性

使用this关键字,this调用函数的那个对象

function Ball(message, specifiedName) {
  console.log(message);
  this.name = specifiedName;
}
var ball0 = new Ball("creating new Ball", "Soccer Ball");
ball0.name;

请注意,是new关键字使构造函数被执行。上面例子中,它将会运行Ball("creating new Ball", "Soccer Ball");而this关键字将指向ball0,因此 this.name=specifiedName 变成了 ball0.name="Soccer Ball"。
函数也是一个对象。可以让一个函数作为一个对象的属性。下面我们添加两个函数getSalary和addSalary。

function Employee(name, salary) {
  this.name = name;
  this.salary = salary;
  this.addSalary = addSalaryFunction;
  this.getSalary = function() {
    return this.salary;
  }
}
function addSalaryFunction(addition) {
  this.salary = this.salary + addition;
}
var boss=new Employee("John", 200000); 
var boss2=new Employee("Joan", 200000); 
var boss3=new Employee("Kim", 200000);

当创建更多的实例时(boss2,boss3),每一个实例都有一份getSalary代码的拷贝;addSalary则指向同一个地方(即addSalaryFunction)
继续上面的代码,如下修改:

boss1.getSalary.owner = "boss1";
boss2.getSalary.owner = "boss2";
console.log(boss1.getSalary.owner); // boss1
console.log(boss2.getSalary.owner); // boss2
// 如果两个对象指向同一个函数对象,如给addSalary函数对象添加属性
boss1.addSalary.owner = "boss1";
boss2.addSalary.owner = "boss2";
console.log(boss1.addSalary.owner); // boss2
console.log(boss2.addSalary.owner); // boss2

上面代码得出的结论是:

  1. 需要更多的存储空间来存储对象(每个实例都有自己的getSalary代码)
  2. 需要更多的时间来构造这个对象
    针对两个问题,重写这个示例,如下:
    function Employee(name, salary) {
    this.name = name;
    this.salary = salary;
    this.addSalary = addSalaryFunction;
    this.getSalary = getSalaryFunction;
    }
    function getSalaryFunction() {
    return this.salary;
    }
    function addSalaryFunction(addition) {
    this.salary = this.salary +  addition;
    }

    这样将会节约空间和缩短构造时间。

    原型ProtoType

    每一个构造函数都有一个属性叫做原型(prototype)。这个属性非常有用,为一个特定的类声明通用的变量和函数。你不需要显式地声明一个prototype属性,因为在每一个构造函数都有它的存在

    function Test() {}
    console.log(Test.prototype) // Object

    如上,prototype是一个对象,因此,你能够给它添加属性。你添加给prototype的属性将会成为这个构造函数创建的对象的通用属性

    function Fish(name, color) {
    this.name = name;
    this.color = color;
    }
    Fish.prototype.livesIn = "water";
    Fish.prototype.price = 20;
    var fish1 = new Fish("mackeral", "gray");
    var fish2 = new Fish("goldfish", "orange");
    var fish3 = new Fish("salmon", "white");

    你看到所有的鱼都有livesIn和price属相,我们甚至没有为每一条不同的鱼声明这些属性。因为当一个对象被创建时,这个构造函数将会把它的属相prototype赋值给新对象的proto。这个proto被这个对象来查找属性。
    用prototype给对象添加函数

    function Employee(name, salary) {
    this.name = name;
    this.salary = salary;
    }
    Employee.prototype.getSalary = function getSalaryFunction() { return this.salary; }
    Employee.prototype.addSalary = function addSalaryFunction(addSalary) { return this.salary = this.salary+addSalary }
    boss1 = new Employee("Joan", 20000) // 20000
    boss2 = new Employee("Kim", 30000) // 30000

    这里每个对象实例都有一个内部属相proto,这个属性指向了它的构造器(Employee)的属性prototype。当你执行getSalary或者addSalray的时候,这个对象会在它的proto找到代码执行。

参考地址:https://www.jb51.net/article/97767.htm

转载于:https://blog.51cto.com/5890945/2346929

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值