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
上面代码得出的结论是:
- 需要更多的存储空间来存储对象(每个实例都有自己的getSalary代码)
- 需要更多的时间来构造这个对象
针对两个问题,重写这个示例,如下: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://blog.51cto.com/5890945/2346929