javascript红宝书学习(三)函数

58 阅读5分钟

关于代理的简单demo

const target = {
    id ; '1'
}
const hander = {};
const proxy = new Proxy(target,hander);
console.log(target.id); // 1
console.log(proxy.id); // 1

关于函数

函数其实就是对象,下面是几种创建函数的方法

// 函数的声明
function sum_0(sum1,sum2){
    return sum1+sum2;
}
// 函数的表达式
let sum_1 = function(sum1,sum2){
    return sum1+sum2;
}
// 箭头函数
// 箭头函数虽然语法简洁,但也有很多场合不适用。箭头函数不能使用 arguments、super 和 new.target,也不能用作构造函数。此外,箭头函数也没有 prototype 属性
let sum_2 = (num1,num2) =>{
    return sum1+sum2;
}

理解参数学习
和我理解不同的是,在参数传递的时候,不用过于关注形参的参数具体传了多少,因为参数是通过arguments数组进行返回到方法内的,这个java非常不一样。但是在箭头(=>)的时候是不被允许的

function arg(){
    console.log(arguments[0]); // 11
    console.log(arguments[1]); // 22
}
// 当传递的方法有形参的时候,优先匹配对等参数的方法
function arg(n1,n2){
    console.log(arguments[0]); // 11
    console.log(arguments[1]); // 22
    console.log(n1); // 11
    console.log(n2); // 22
}
// 当两个方法名一样时,下面的方法就会覆盖上面的方法
arg(11,22);
// 使用箭头函数是不存在arguments数组对象的
let arg2 = () =>{
    console(arguments[0]); //  arguments is not defined
}
// 但是如果包装在函数里面是可以有arguments数组的
function arg2_new(){
    let arg2 = () =>{
    console.log(arguments[0]); //  11
    }
    arg2();
}
arg2_new(11);

关于默认参数值

// 在es5.1之前还需要去判断undefined进行三目运算,但是在es6之后就可以直接赋值
function defaultArg(name = 'zhangsan'){
    console.log(name); //当name没有值的时候,默认为zhangsan
}
defaultArg();

关于扩展操作符,其实就通过合并的方式拼接为一个数组,或者说求并集

const user1 = {
     name: 'Jen' , age: 22, };
  
const user2 = {
     name: "Andrew" , location: "Philadelphia" 
};
  
const mergedUsers = {...user1, ...user2};
console.log(mergedUsers) // {name: 'Andrew', age: 22, location: 'Philadelphia'}

javascript的执行是从上到下的,当执行函数声明的时候,是运行执行在方法上面,但是函数表达式不行

    test();  // 函数声明的执行
    test_2(); // Cannot access 'test_2' before initialization,也就是没有初始化
    function test(){
        console.log("函数声明的执行");
    }
    let test_2 = function(){
        console.log("函数表达式的执行");
    }

函数内部的属性包含:arguments,this,new.target(ES6新增)
关于this的使用学习
学习参考:www.jb51.net/article/157…
一般包含四种情况
1,默认绑定:在不指向任何对象的情况下,this指向windows
2,隐式绑定:就是调用位置是否有上下文对象,或者说是否被某个对象拥有或包含
3,显示绑定:借助于这些显式绑定方法,可以直接改变当前方法的this指向(主要有call、apply和bind三种)
4,new 绑定:new的调用又称为构造函数调用

// 默认绑定指向的就是windows
function test(){
    this.name = 'zhangsan';
    console.log(this.name); // zhangsan 指向windows
}
console.log(this.name);  // zhangsan 执行windows
// 关于隐式绑定,也就是被对象包含的。
var obj = {
    name : 'lisi',
    test_name : function(){
        console.log(this.name); // this指向的是obj
    }
}
obj.test_name(); // this指向的是obj所以打印lisi
console.log(this.name); // this指向的是windows,如果执行过this.name(例如在默认绑定执行过)那么this.name就为 zhangsan
// 显示绑定,利用call、apply和bind
function test(){
let obj = {
    name : 'lisi',
    test_name : function(){
        console.log(this.name); // this指向的是obj
    }
}
let obj_new = {
	name : 'wangwu'
}
obj.test_name.call(obj_new); // this的指向变成obj_new的name
obj.test_name.apply(obj_new);  // this的指向变成obj_new的name 和call的区别在于传入的参数要为数组(当有传参时)
obj.test_name.bind(obj_new)(); // this的指向变成obj_new的name 他返回的是函数
console.log(obj.test_name()); // this为obj对象
console.log(this.name);      // this为全局windows
// 关于new 对象的绑定
function obj(){
    this.name = 'zhaoliu';
}
let obj_new2 = new obj();
console.log(obj_new2.name); // zhaoliu this指向函数obj中的name
console.log(this.name);  // 指向全局的name

关于new.target(ES6新增)
其实就是判断是否调用了new的关键字。很简单。

function obj(){
    if(!new.target){
        console.log("没有调用new关键字");
    }else{
        console.log("调用new关键字");
    }
}
new obj(); // 调用new关键字
obj(); // 没有调用new关键字

理解闭包
闭包指的是那些引用了另一个函数作用域中变量的函数,通常是在嵌套函数中实现的。其核心的作用是用来隔离数据,防止数据被随意篡改

function persion(){
    let name = "张三";
    // 嵌套函数 ->链式作用域"
    function getName(){
        return name;
    }
}

并且闭包的内存是不释放的,也就是说父类函数执行完成后,子类函数的内容是不受影响的,所以在使用闭包的时候要考虑内存泄漏的相关问题
理解概念:zhuanlan.zhihu.com/p/21346046

// 关于闭包函数的this引用
// 每个函数创建的时候 都会产生this和arguments,内部函数永远不可能访问外部函数的两个对象
// 也就是说this.name 无法被访问只能去找全局的变量
window.name = 'zhangsan';
let persion = {
    name : 'lisi',
    getName(){
        return function(){
            return this.name;
        }
    }
}
console.log(persion.getName()()); // zhangsan
// 所以说当全部变量不存在时,name为undefined
let persion = {
    name : 'lisi',
    getName(){
        return function(){
            return this.name;
        }
    }
}
console.log(persion.getName()()); // undefined
// 当利用变量去给this赋值的话,则可以进行访问。
window.name = 'zhangsan';
let persion = {
    name : 'lisi',
    getName(){
        let that = this;
        return function(){
            return that.name;
        }
    }
}
console.log(persion.getName()()); // lisi
// 如果不用匿名函数,也就是闭包的话,那返回的this.name就为lisi
window.name = 'zhangsan';
let persion = {
    name : 'lisi',
    getName(){
        return this.name;
    }
}
console.log(persion.getName()); // lisi

立即调用函数表达式(IIFE)
学习参考:www.jianshu.com/p/c64bfbcd3…

// 常用该方法
(function(){
   // 块作用域--对外是不可见的
})();
// 这种也可以
(function(){
   // 块作用域
}());
// 在我们正常function中通过IIFE的这种立即调用函数方式会立刻执行,
function test(){
    (function(){
        console.log("立即调用函数表达式")
    })();
}
test(); // 立即调用函数表达式
// 最外层的"()"以可以传递局部变量执行当前内容
function test(){
	(function(a){
		console.log(a);
	})("---打印a变量---");
}
test();//---打印a变量---