版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
- call(),apply(),bind()三种方法
- call()和apply()方法都可以改变this的指向。
- call()用法:
函数名字.call(对象,参数1,参数2,...); 方法名字.call(对象,参数1,参数2,...);
- apply()用法:
函数名字.apply(对象,[参数1,参数2,...]); 方法名字.apply(对象,[参数1,参数2,...]);
- 代码:
function Person(age,name) { this.age=age; this.name=name; } Person.prototype.sayHi=function (x,y) { console.log("哈哈"+(x+y)+"===========>"+this.sex); }; function Student(sex,age,name) { this.sex=sex; Person.apply(this,[age,name]); } var per=new Person(10,"小明"); var stu=new Student("男",100,"小王"); per.sayHi.apply(stu,[10,20]);//哈哈30===========>男 per.sayHi.call(stu,10,20);//哈哈30===========>男 console.log("==========="); console.log(stu);
- bind()方法:
复制了一份的时候,把参数传入到了f1函数中,x===>10,y===>20,null就是this,默认就是window bind方法是复制的意思,参数可以在复制的时候传进去,也可以在复制之后调用的时候传入进去 apply和call是调用的时候改变this指向 bind方法,是复制一份的时候,改变了this的指向 函数名字.bind(对象,参数1,参数2,...);---->返回值是复制之后的这个函数 方法名字.bind(对象,参数1,参数2,...);---->返回值是复制之后的这个方法
代码:
// function Person(age) {
// this.age=age;
// }
// Person.prototype.eat=function () {
// console.log("吃了"+"==========>"+this.age);
// };
// function Student(age) {
// this.age=age;
// }
// var per=new Person(10);
// var stu=new Student(100);
// var ff=per.eat.bind(stu);
// ff();
function ShowRandom() {
this.numeber=parseInt(Math.random()*10+1);
}
ShowRandom.prototype.show1=function () {
var that=this;
window.setInterval(function () {
this.show2();
}.bind(that),1000);
};
ShowRandom.prototype.show2=function () {
console.log(this.numeber);
};
var num=new ShowRandom();
num.show1();//循环显示随机数7
num.show2();//7
- 函数中的几个成员
函数中有一个name属性----->函数的名字,name属性是只读的,不能修改
函数中有一个arguments属性--->实参的个数
函数中有一个length属性---->函数定义的时候形参的个数
函数中有一个caller属性---->调用(f1函数在f2函数中调用的,所以,此时调用者就是f2)
- 高阶函数作为参数使用
var arr = [1, 100, 20, 200, 40, 50, 120, 10];
//排序---函数作为参数使用,匿名函数作为sort方法的参数使用,那么此时的匿名函数中有两个参数,
arr.sort(function (obj1,obj2) {
if(obj1>obj2){
return -1;
}else if(obj1==obj2){
return 0;
}else{
return 1;
}
});
console.log(arr);//[1,10,20,40,50,100,120,200]
- 高阶函数作为返回值
function File(name, size, time) {
this.name = name;//电影名字
this.size = size;//电影大小
this.time = time;//电影的上映时间
}
var f1 = new File("jack.avi", "400M", "1997-12-12");
var f2 = new File("tom.avi", "200M", "2017-12-12");
var f3 = new File("xiaosu.avi", "800M", "2010-12-12");
var arr = [f1, f2, f3];
function fn(attr) {
//函数作为返回值
return function getSort(obj1, obj2) {
if (obj1[attr] > obj2[attr]) {
return 1;
} else if (obj1[attr] == obj2[attr]) {
return 0;
} else {
return -1;
}
}
}
var ff = fn("name");
//函数作为参数
arr.sort(ff);
for (var i = 0; i < arr.length; i++) {
console.log(arr[i].name + "====>" + arr[i].size + "===>" + arr[i].time);
}
- 作用域,作用域链和预解析
- 作用域:变量有局部变量(在函数中定义的是局部变量)和全局变量,作用域也有局部作用域和全局作用域。作用域就是变量的使用范围。
作用域链:变量的使用,从里向外,层层搜索,搜索到了就直接使用。搜到0级作用域时,如果还没有搜到就报错。
var num=10; //作用域链 级别:0
var num2=20;
var str = "abc";
function f1() {
var num2=20;
function f2() {
var num3=30;
console.log(num);
}
f2();
}
f1();//10
3.预解析:就是在浏览器解析代码的之前,将变量的声明和函数的声明提前到该作用域的前面。
//变量的提升
console.log(num);//100
var num=100;
//函数的声明被提前了
f1();//这个函数,执行了
function f1() {
console.log("这个函数,执行了");
}
var f2;
f2=function () {
console.log("好帅哦");
};
f2();//好帅哦
- 闭包
- 概念:函数A中,有一个函数B,函数B中可以访问函数A中定义的变量或者是数据,此时形成了闭包(这句话暂时不严谨)。如果想要缓存数据,就把这个数据放在外层的函数和里层的函数的中间位置。
- 作用:缓存数据.优点也是缺陷,没有及时的释放。
- 局部变量是在函数中,函数使用结束后,局部变量就会被自动的释放 。闭包后,里面的局部变量的使用作用域链就会被延长。
- 沙箱
概念:就是一个环境,黑盒,在一个虚拟的环境中模拟真实世界,做实验,实验结果和真实世界的结果是一样,但是不会影响真实世界.。之前的贪吃蛇案例就用到了沙箱。
作用:避免命名冲突。
(function () {
var str="小白喜欢小黑";
str=str.substr(2);
console.log(str);//喜欢小黑
}());
//沙箱
(function () {
var str="小明喜欢小红";
str=str.substr(2);
console.log(str);//喜欢小红
}());
var getTag = 10;
var dvObjs = 20;
var pObjs = 30;
//沙盒
(function () {
//根据标签名字获取元素
function getTag(tagName) {
return document.getElementsByTagName(tagName)
}
//获取所有的div
var dvObjs = getTag("div");
for (var i = 0; i < dvObjs.length; i++) {
dvObjs[i].style.border = "2px solid pink";
}
//获取所有的p
var pObjs = getTag("p");
for (var i = 0; i < pObjs.length; i++) {
pObjs[i].style.border = "2px solid pink";
}
}());
console.log(getTag);//10
console.log(dvObjs);//20
console.log(pObjs);//30
//沙盒里面的内容不影响外部环境
- 递归
- 概念:函数中调用函数自己,此时就是递归,递归一定要有结束的条件。
- 例子:
//求n个数字的和,5 计算1+2+3+4+5 var sum=0; for(var i=1;i<=5;i++){ sum+=i; } console.log(sum);//15 //递归实现:求n个数字的和 n=5---> 5+4+3+2+1 // 函数的声明 function getSum(x) { if(x==1){ return 1; } return x+getSum(x-1); } //函数的调用 console.log(getSum(5));//15
//斐波那契数列 function getSeries(x) { if (x===1||x===2){ return 1; } else { return getSeries(x-1)+getSeries(x-2); } } console.log(getSeries(12));
3.执行过程:
代码执行getSum(5)--->进入函数,此时的x是5,执行的是5+getSum(4),此时代码等待 此时5+getSum(4),代码先不进行计算,先执行getSum(4),进入函数,执行的是4+getSum(3),等待, 先执行的是getSum(3),进入函数,执行3+getSum(2),等待,先执行getSum(2),进入函数,执行 2+getSum(1);等待, 先执行getSum(1),执行的是x==1的判断,return 1,所以, 此时getSum(1)的结果是1,开始向外走出去 2+getSum(1) 此时的结果是:2+1 执行: getSum(2)---->2+1 3+getSum(2) 此时的结果是3+2+1 4+getSum(3) 此时的结果是4+3+2+1 5+getSum(4) 此时的结果是5+4+3+2+1 结果:15