这是第14篇笔记!
让学习“上瘾”,成为更好的自己!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Function_type</title>
<script>
/*
函数实际上是对象,每个函数都是Function类型的实例,而且具有属性和方法
函数名是一个指向函数对象的指针,不会与某个函数绑定
定义函数的方式:
a, 函数声明语法
b, 函数表达式
c, 使用Function()构造函数 【不推荐!!】--> 影响性能
“函数是对象,函数名是指针”
1,没有重载
(见下!)
2,函数声明和函数表达式
区别:
函数声明:解析器会率先读取函数声明,并使其在执行任何代码之前可以访问
函数表达式:必须等到解析器执行到他所在的代码行,才会真正被解释执行
3,作为值的函数
(见下)
4,函数内部的属性
a, 函数内部,2个特殊对象:
arguments:类数组的对象,包含传入函数中的所有参数
callee属性:一个指针,指向拥有这个arguments对象的函数
this:1,指向函数执行时的当前对象,跟执行环境有关,与声明环境无关
2,当没有明确执行时的当前对象时,this指向全局对象window,
或者说当网页的全局作用域中调用函数时,this对象引用的就是window
b, (ECMAScript 5)函数对象的属性: caller --> 保存着调用当前函数的函数的引用
如果是在全局作用域中调用当前函数,他的值是null
c, 严格模式下, arguments.callee会错误
arguments.caller(ECMAScript 5)会错误(非严格为undefined)
5,函数的属性和方法
每个函数都包含2个属性: length --> 函数希望接收的命名参数的个数
prototype --> (第6章详解) 保存引用类型实例所有实例方法
每个函数都包含2个非继承而来的方法:在特定的作用域中调用函数,等同于设置函数体this对象的值
apply() -->
call() -->
(ECMAScript 5)bind() --> 创建一个函数的实例,其this值会被绑定到传给bind()函数的值
*/
// 定义函数
// way 1:
// function sum(num1, num2){
// return num1 + num2;
// }
// ===========way1 and way2 等价书写===================
// // way 2:
// var sum = function(num1, num2){
// return num1 + num2;
// };
// // way 3:
// var sum = new Function('num1','num2','return num1 + num2'); // 不推荐!!
// 函数名与包含对象指针的其他变量没有什么不同
// function sum(num1, num2){
// return num1 + num2;
// }
// console.log(sum(12,2));
// var anotherSum = sum;
// // sum = null;
// console.log(anotherSum(21,3));
// console.log(sum); // 使用不带圆括号的函数名是访问“函数指针”,而非调用函数
// 1,没有重载(将函数名理解为指针)
var addSomeNumber = function(num){
return num + 100;
}
addSomeNumber = function(num){
return num + 200;
}
// console.log(addSomeNumber(200));
// 没有重载? --> 在创建第二个函数时,实际上覆盖了引用第一个函数变量addSomeNumber
// 2,函数声明和函数表达式
// alert(sum(10,10)); // 不会报错
// function sum(n1, n2){
// return n1 + n2;
// }
// 在代码执行之前,解析器通过“函数声明提升”,读取并将函数声明添加到执行环境中
// 对代码求值时,Js引擎在第一遍会声明函数并将他们放到源代码树的顶部
// alert(sum(10,10)); // 会报错
// var sum = function(n1, n2){
// return n1 + n2;
// }
// 3, 作为值的函数 --> 函数名
// 通用函数: 无论第一个参数中传递进来的是什么函数,都有返回执行第一个参数后的结果
function callSomeFunction(someFuction, someArguments){
return someFuction(someArguments);
}
// 例子:
function add10(num){
return num + 10;
}
var result = callSomeFunction(add10, 10);
// console.log(result);
// 一个函数中返回另一个函数【有用的技术】
// 例如,假设有一个对象数组,根据某个对象属性对数组进行排序
function createComparionFunction(propertyName){
return function(object1, object2){
var value1 = object1[propertyName];
var value2 = object2[propertyName];
if(value1 < value2){
return -1;
}else if(value1 > value2){
return 1;
}else{
return 0;
}
}
}
// 使用
var data = [
{
name:'kai',
age:23
},
{
name:'lilce',
age:34
},
{
name:'cili',
age:43
}
]
// data.sort(createComparionFunction('name'));
// console.log(data[0].name)
// data.sort(createComparionFunction('age'));
// console.log(data[0].name)
// 4,函数内部的属性
// callee
function factorial(num){
if(num <= 1){
return 1;
}else {
return num * factorial(num - 1);
// 函数的执行与函数名factorial紧紧耦合在一块
}
}
function factorial(num){
if(num <= 1){
return 1;
}else {
return num * arguments.callee(num - 1);
// 无论引用函数时使用什么名字,都可以保证正常完成递归调用,消除耦合状态!!
}
}
var trueFatorial = factorial;
factorial = function(){
return 0;
}
// console.log(trueFatorial(5)); // 120
// console.log(factorial(5)); // 0
// this: 指向函数执行时的当前对象,跟执行环境有关,与声明环境无关
// why? --> 函数的名字仅仅是一个包含指针的变量而已!!
// window.color = 'red';
// var o = {color: 'blue'};
// function sayColor(){
// console.log(this.color);
// }
// sayColor(); // 'red'
// o.sayColor = sayColor;
// o.sayColor(); // 'blue'
var someone = {
name: "Bob",
showName: function(){
alert(this.name);
}
};
var other = {
name: "Tom",
showName: someone.showName
};
// other.showName(); //Tom
// this关键字虽然是在someone.showName中声明的,但运行的时候是other.showName,
// 因为this指向other.showName函数的当前对象,即other,故最后alert出来的是other.name
// caller
// function outer(){
// inner();
// }
// function inner(){
// // alert(inner.caller);
// alert(arguments.callee.caller); // 实现松散耦合
// }
// outer(); // 显示outer()函数的源代码,inner.caller指向outer()
// function inner(){
// return 1;
// }
// inner();
// console.log(inner.caller); // null
// 函数属性和方法
// function sayName(num1, num2){
// return num1 + num2;
// }
// console.log(sayName.length); // 2
// apply(): 第一个参数为运行函数的作用域(常为this)
// 第二个参数可以是Array实例,或者arguments对象
function sum(num1, num2){
return num1 + num2;
}
function callSum1(num1, num2){
console.log(this); // window
return sum.apply(this, arguments); // arguments对象
}
function callSum2(num1, num2){
return sum.apply(this, [num1, num2]); // Array实例
}
// console.log(callSum1(10, 10));
// console.log(callSum2(10,10));
// call(): 第一个参数为运行函数的作用域,变量对象表示(常为this)
// 其余参数必须都列举出来传递给函数
// function sum(num1, num2){
// return num1 + num2;
// }
// function callSum(n1, n2){
// return sum.call(this, n1, n2);
// }
// console.log(callSum(20, 20));
// apply() and call() 最强大的地方: 能够扩充函数赖以运行的作用域
// window.color = 'red';
// var o = {color:'blue'};
// function sayColor(){
// console.log(this.color);
// }
// sayColor(); // red
// sayColor.call(this); // red
// sayColor.call(window); // red
// sayColor.call(o); // blue --> 函数的执行环境改变了
// bind() --> 创建一个函数的实例,其this值会被绑定到传给bind()方法的对象
window.color = 'red';
var o = {color:'blue'};
function sayColor(x, y){
console.log(x + y);
console.log(this.color);
}
var objectSayColor = sayColor.bind(o, 3, 5);
objectSayColor();
// objectSayColor(); // blue
// sayColor()调用bind()并传入对象o, 创建了objectSayColor()函数,objectSayColor()函数的this值等于o
// bind and call
// bind: 改变函数的this,并且返回一个新函数(不调用函数)
// call: 改变函数的this,且直接调用函数
</script>
</head>
<body>
</body>
</html>