1:call,apply,bind
2:高阶函数--函数的使用方式
3:作用域和作用域链,预解析
4:闭包
5:沙箱
6:递归
1.1:call和apply都是改变this指向
对象.call(对象,值,值);
对象.apply(对象,[值,值]);
Call和apply并不在实例对象中,而是在Function的prototype里面
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!--call和apply可以改变this的指向-->
</body>
<script>
//函数,改变
// "use strict"
function f(x, y) {
console.log("结果是:" + (x + y) + this);
return "这是函数的返回值";
}
// f(10,20);
var obj = {};
//f函数是window对象的,但是传入obj之后,f函数此时就是object
// var r1 = f.apply(null,[1,3]);
var r1 = f.apply(obj, [1, 3]);
console.log(r1);
// 方法改变
// 方法.apply和方法.call
// call和apply到底是谁的
function ff() {
console.log("哈哈")
}
//对象调用方法,说明对象中有这个方法
// call和apply方法方法并不在函数的实例对象中,而是在Function的prototype中
ff.apply();
ff.call();
console.log(Function); //{ [native code] }
console.dir(Function.prototype);
</script>
</html>
1.2:bind
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script>
function f(x,y){
console.log((x+y)+"========>"+this);
}
function Person(){
}
var per = new Person();
var ff = f.bind(per,12,28); //复制一份的时候,把参数传入到f中,nukk就是this,默认就是window
// ff(12,18); //复制完之后,将参数传入
ff();
</script>
</body>
</html>
2.1高阶函数
函数作为参数使用
函数作为返回值使用
我们先来了解一下函数的几个属性
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script>
/*
* 函数中有个name属性 ---》函数的名字
* 函数中有一个arguments属性---》实参的个数
* 函数中有一个length属性---》形参的个数
*caller --》调用者
*
*
* */
function f(x, y) {
console.log(f.name);
console.log(f.arguments.length); //实参的个数
console.log(f.length); //形参的个数
console.log(f.caller) //调用者
}
f.name = "f2"//name属性是只读的,不能修改
// console.dir(f);
// f(2,6,8);
function f1() {
console.log("+++++++++++");
f(1, 2)
}
f1();
</script>
</body>
</html>
2.2函数作为参数使用
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script>
/*
* 函数作为参数使用
* 匿名函数
* 命名函数
*
* */
function f(fn) {
console.log("哈哈");
fn();
}
// 匿名函数作为参数
f(function () {
console.log("我是匿名函数作为参数输出")
})
// 命名函数作为参数输出
function fn() {
console.log("我是命名函数作为参数输出");
};
f(fn);
</script>
</body>
</html>
这里命名函数作为参数,需要的是他的代码,所以一个函数名。
2.3函数作为返回值使用
(function () {
function f() {
console.log("我是f");
return function () {
console.log("我是函数作为返回值来使用的")
}
}
var ff = f();
ff();
}())
函数作为返回值来使用,有返回值,需要来接收!切记
2.4--扩展
Typeof --用来获取数据类型--值类型
// typeof 只能判断值类型
console.log(typeof undefined); //undefined
console.log(typeof true); //boolean
console.log(typeof 123); //number
console.log(typeof "阿萨德"); //string
console.log(typeof null); //object
console.log(typeof []); //object
console.log(typeof {}); //object
console.log(typeof console.log); //function
当typeof遇到引用类型(数组,函数,对象),无法具体判断出来。
Instanceof 判断这个对象是哪个类型的 --返回布尔值
Var obj = {}
Console.log(obj instanceof Object) //true
获取某个对象的数据类型的样子
console.log(Object.prototype.toString.call([]));
console.log(Object.prototype.toString.call({}));
console.log(Object.prototype.toString.call(new Date()));
封装一个方法,获取某个对象的类型是不是你传入的类型
function getFun(type) {
return function (obj) {
return Object.prototype.toString.call(obj) == type;
}
}
var ff = getFun("[object Array]");
var result = ff([12, 45, 78]);
console.log(result);
2.5函数作为参数的具体例子
(function () {
var arr = ["asd","ads","fgh"];
arr.sort(function(a,b){
if (a > b) {
return 1; //从小到大
}
else if (a == b) {
return 0;
}
else {
return -1;
}
})
console.log(arr);
}());
(function () {
var arr = [12, 8, 5, 45, 100, 20, 30];
arr.sort(function (a, b) {
if (a > b) {
return 1; //从小到大,如果是-1,就是从大到小
}
else if (a == b) {
return 0;
}
else {
return -1;
}
})
console.log(arr);
}());
3.1作用域,作用域链,预解析
js没有块级作用域,一对大括号定义的变量,可以在大括号外面使用
但是函数中定义的变量是局部变量
函数有匿名函数,命名函数。不管是哪个,都有function!
预解析:在浏览器解析代码之前,将变量的声明和函数的声明提升到作用域的最上面
看个经典例子
// var ff;变量声明提前 ,undefined,undefined()不认可
ff(); //报错
var ff = function(){
console.log("你就比较牛逼了");
}
这个是函数表达式,和变量赋值一样,所以将变量提升。最后报错了哦!
3.2:闭包
概念:函数A中有函数B,函数B可以访问函数A的变量,此时形成了闭包
闭包的模式:函数模式,对象模式
闭包的作用,优缺点:缓存数据,延长作用域链
函数模式的闭包
(function () {
function A() {
var num = 10;
function B() { //B可以访问A里面的变量
console.log(num);
}
B();
}
A();
}());
//对象模式的闭包
function C() {
var num = 10;
var B = {
age: num
}
console.log(age);
}
A();
闭包案例
(function () {
// 闭包案例
function A() { //每一次都是重新开始,所以都是11
var num = 10;
num++;
console.log(num);
}
A(); //11
A();//11
A();//11
A();//11
}());
console.log("++++++++++++");
(function () { //函数B中有函数,函数访问B的属性,就会形成闭合函数,有数据缓存
function B() {
var num = 10;
return function () {
num++;
return num;
}
}
var b = B(); //这一步是将B的结果num =10给了b,
console.log(b());//每次调用b的时候,有数据缓存,所以每次的num都在变
console.log(b());
console.log(b());
console.log(b());
}());
闭包案例:产生多个相同的随机数
(function () {
function getMath() {
var num = parseInt(Math.random() * 10 + 1);
return function () {
console.log(num);
}
}
var ff = getMath();
ff();
ff();
ff();
ff();
}());
总结闭包:如果想要缓存数据,就把这个数据放在内层函数个外层函数的中间,
有点:缓存数据,缺点:不能及时的释放,延长作用域链
闭包:点赞案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>对自己狠点</title>
<style>
ul {
list-style-type: none;
}
li {
float: left;
margin-left: 10px;
}
img {
width: 200px;
height: 180px;
}
input {
margin-left: 30%;
}
</style>
<script>
</script>
</head>
<body>
<ul>
<li><img src="../../images/1.jpg" alt=""><br/><input type="button" value="赞(1)"></li>
<li><img src="../../images/2.jpg" alt=""><br/><input type="button" value="赞(1)"></li>
<li><img src="../../images/3.jpg" alt=""><br/><input type="button" value="赞(1)"></li>
<li><img src="../../images/4.jpg" alt=""><br/><input type="button" value="赞(1)"></li>
</ul>
<script>
//获取所有的按钮元素
function my$(tagName) {
return document.getElementsByTagName(tagName);
}
//闭包缓存数据
function getValue() {
var value = 2;
return function () {
//每一次点击的时候,都应当改变当前按钮的值 ,this.vlaue
this.value = "赞(" + (value++) + ")";
}
}
var objButton = my$("input");
for (var i = 0; i < objButton.length; i++) {
objButton[i].onclick = getValue();
}
</script>
</body>
</html>
4沙箱:避免命名冲突
var str = "小黑喜欢小白";
//沙箱
(function(){
var str = "小黑喜欢小白";
var str = str.substr(2);
console.log(str);
}())
var str = str.substr(2);
console.log(str);
5:递归:函数内部调用自己,并且有终止条件
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!--函数自己调用自己;必须要终止条件,否则就是死循环
递归轻易不要用,效率低
-->
<!--<script>-->
<!--var i = 0;-->
<!--function f() {-->
<!--i++;-->
<!--if(i<5){-->
<!--f();-->
<!--}-->
<!--console.log("哈哈")-->
<!--}-->
<!--f();-->
<!--</script>-->
</body>
<script>
/*
* 求n个数字的和
* */
// var sum = 0;
// for(var i = 0 ;i<5;i++){
// sum+=i;
// }
// console.log(sum);
//函数的声明
function getSum(n){
if(n==1){
return 1
}
return n+getSum(n-1);
}
// 函数的调用
console.log(getSum(100));
function getS(x){
if(x<10){
return x;
}
return x%10+getS(parseInt(x/10));
}
console.log(getS(123));
function fb(n){
if(n ==1||n==2){
return 1;
}
return fb(n-1)+fb(n-2);
}
console.log(fb(12));
</script>
</html>