function a (){
}
函数
函数实际上是对象
参数
-
ECMAScript中,参数在内部是使用一个数组来表示,所以,参数可以传多个也没有问题,什么类型都可以
-
可以通过arguments对象,来访问这个参数数组
-
arguments对象,不是Array, 但可以有length, 使用argument[index]来访问
-
它的值与对应命名的参数的值保持同步
function a(num1, num2) { arguments[1] = 10; console.log(num2);//10 } a(1, 2)
没有重载
-
ECMAScript 定义了两个名字相同的函数, 该名字属于后定义的函数, 后一个函数,会覆盖前面同名的
function a() { return arguments[0] + 100 } function a() { return arguments[0] + 200 } console.log(a(1))//201
函数名实际也是一个指向函数对象的指针
函数声明与函数表达式
//函数声明
function sum(){
}
//函数表达式
var sum = function(){
}
-
解析器会率先读取函数声明, 并使其在执行任何代码之前可用
-
函数表达式,必须等到解析器执行它所在的代码行,才会真正被解释执行
-
函数声明提升
// sum... 函数声明提升到顶部 console.log(sum(10,10))//20, 函数 function sum(num1,num2){ return num1+num2 } //如果是表达式,会报错 console.log(sum(10,10)); var sum = function(){ }
函数本身就是变量
- 函数可以作为值来使用
- 函数可以用于传递参数,返回结果
函数内部属性
-
arguments
-
callee 指针,指向拥有arguments对象的函数, 作用,无论函数名 如何修改,都可以正常使用
function a(num){ return num * arguments.calle(num-1) } //等于 function a(num){ return num * a(num-1) }
-
-
this
-
this引用的就是函数执行的环境对象
-
全局作用域中,this就是window
window.color='red' var o = {color:'blue'} function sayColor(){ alert(this.color) } sayColor();//red o.sayColor = sayColor; o.sayColor(); //'blue'
-
-
caller
- 指向调用当前函数的函数的引用, 全局就是null
-
length 参数的个数
-
prototype 原型链
- 保存所有的实例方法
- 不可被枚举, for-in不会发现prototype属性
函数的非继承而来的方法
用于设置函数体内this对象的值,则设置函数的执行环境
-
apply
-
两个参数,函数作用域,参数数组(可以是Array实例,也可以是arguments)
function sum(num1,num2){ return num1+num2 } function callSum1(num1,num2){ return sum.apply(this,arguments) }
-
-
call
-
作用和apply一样,但是call方法,第一个参数是this值,其它参数依次传入
function callSum(num1,num2){ return sum.call(this,num1,num2) }
-
-
bind() ecmascript5
-
绑定this到某个值
window.color = 'red'; var o = {color:'blue'}; function sayColor(){ console.log(this.color) } var a = sayColor.bind(o); a()//blue
-
用武之地:扩充函数运行的作用域, 解除耦合
window.color = 'red';
var o = {color:'blue'};
function sayColor(){
console.log(this.color)
}
//扩充
sayColor.call(this); // red
sayColor.call(window) // red
sayColor.call(o) //blue
var a = sayColor.bind(o);
a()//blue
闭包
闭包是指有权访问另一个函数作用域中的变量的函数
创建方式
function a() {
const a = 'ddd';
return function () {
console.log(this.a);//作用域链包含了外部作用域
}
}
var aF= a();
aF();//ddd
理解
- 当某个函数被调用时,会创建一个执行环境,及相应的作用域链
- 使用arguments和其它命名参数的值来初始化函数的活动对象
- 作用域链中,外部函数的活动对象处于第二位,外部函数的外部函数的活动对象处于第三位,直至作为作用域终点的全局执行环境
- 作用域链本质上是一个指向变量对象的指针列表
- 一般来讲,当函数执行玩后,局部活动对象会被销毁,内存中仅保存全局作用域(全局执行环境的变量对象)
1.创建compare()函数时,会创建一个预先包含全局变量对象的作用域链,这个作用域链保存在内部的[[scope]]属性中
2.调用compare()函数时,会为函数创建一个执行环境,通过复制函数的[[scope]]属性中的对象构建执行环境的作用域链。
3.然后,有一个活动对象被创建推入执行环境作用域链的前端。
function compare(value1,value2){
if(value1<value2){
return -1;
}
}
var result = compare(5,10);
闭包有所不同
function a() {
const a = 'ddd';
return function () {
console.log(this.a);//作用域链包含了外部作用域
}
}
var aF= a();
aF();//ddd
- 当闭包的匿名函数的作用域链在外部函数a执行完后,a的活动对象没有被销毁,因为匿名函数还引用着这个活动对象
- a函数返回后,其执行环境的作用域链会被销毁,但它的活动对象仍然留在内存中,被内部匿名函数引用着。
闭包与变量
- 闭包只能包含函数中任何变量的最后一个值(现在执行,不存在这个问题,有待考究)
function createFunctions() {
var result = new Array();
for (let i = 0; i < 10; i++) {
result[i] = function () {
return i;
};
}
return result;
}
const result = createFunctions();
console.log(result[7]());//7
function createFunctions1() {
var result = new Array();
for (let i = 0; i < 10; i++) {
result[i] = function (num) {
return function () {
return num;
}
}(i);
}
return result;
}
const result = createFunctions1();
console.log(result[7]());//7
闭包的作用域链中保存着一个HTML元素,那么该元素就无法被销毁
function assignHandler(){
var element = document.getElementById('someElement');
element.onclick = function(){
console.log(element.id)
}
}
模仿块级作用域
利用匿名函数
经常用于全局作用域中被用在函数外部,限制向全局作用域中添加过多的变量和函数
(function(){
//这里是块级作用域
})();
私有变量
任何函数中定义的变量,都可以认为是私有变量,包括函数的参数,局部变量,和在函数内部定义的其他函数
- 特权方法,有权访问私有变量和私有函数的公有方法,可以隐藏那些不应该被直接修改的数据
function add(num1,num2){
var num=1;
function privateF(){
return false;
}
//特权方法
this.publicMethod= function(){
num++;
return privateF();
}
}
静态私有变量
(function () {
var name = ""
//声明没有使用var, 创建一个全局变量,能够在私有作用域外被使用
Person = function (value) {
name=value;
}
Person.prototype.getName=function () {
return name;
}
Person.prototype.setName=function (value) {
name = value;
}
})();
var person1 = new Person('Nicholas');
console.log(person1.getName());//'Nicholas'
person1.setName('Greg')
console.log(person1.getName());//'Greg'
var person2 = new Person('Michael');
console.log(person1.getName());//'Michael'
console.log(person2.getName());//'Michael'
//name变成了一个静态的,由所有实例共享的属性
模块模式与单例
- javascript以对象字面量的方式创建单例对象
模块模式通过单例模式添加私有变量和特权方法
var singleton = function(){
//私有变量和私有函数
var privateVariable =10;
function privateF(){
return false;
}
//特权/公有方法和属性
return {
publicP:true,
publicM:function(){
privateVariable++;
return privateF();
}
}
}();
增强的模块模式
适合单例必须是某种类型的实例
var application = function(){
//私有变量和函数
var components = new Array();
//初始化
components.push(new BaseComponent());
//创建application 的一个局部副本
var app = new BaseComponent();
//公共接口
app.getComponentCount = function(){
return components.length;
}
return app;
}