• Welcome to Journal web site.

我是 PHP 程序员

- 开发无止境 -

Next
Prev

第13章 0401-闭包,访问器,类与解构

Data: 2018-04-19 06:34:08Form: JournalClick: 1

问题集合:

1.  类中的私有变量只能在类中访问吗

答:是

2.  如果要在外面访问是不是  console.log(类名.私有变量)?

答:外部不可见,名称都看出来,私有

image.png


demo1:闭包

// 自由变量

        let x = 10;
        let fn = function(a, b) {
            let c = 3;
            // 这个函数中,可以访问到哪些变量?

            // 这个时候,属性于函数自身的变量有2类
            // 1. 参数变量: a, b
            // 2. 私有变量: c

            console.log(x);

            // x: 不是函数内部的变量,是外部的,全局的
            // x: 自由变量
        };

        fn(1, 2);

        // 闭包的条件
        // 1. 父子函数
        // 2. 子函数中调用父函数中的变量
        // 3. 返回一个函数

        fn = function(a) {
            // 子函数
            let f = function(b) {
                return a + b;
            };
            // 返回这个子函数
            return f;
        };

        let f = fn(10);
        // fn()调用完成,但是它内部的a被子函数f引用,所以fn()创建的作用域不能消失
        console.log(typeof f);
// typeof 作用为返回该值数据类型
        console.log(f(20));
        console.log(fn(10)(20));

        // 闭包应用之: 偏函数(高阶函数的一种)
        fn = function(a, b, c) {
            return a + b + c;
        };
        console.log(fn(1, 2, 3));

        fn = function(a) {
            return function(b, c) {
                return a + b + c;
            };
        };
        console.log(fn(1)(2, 3));

        fn = function(a) {
            return function(b) {
                return function(c) {
                    return a + b + c;
                };
            };
        };
        console.log(fn(1)(2)(3));

        // 参数逐个传入:柯里化

        fn = a => {
            return b => {
                return c => {
                    return a + b + c;
                };
            };
        };

        fn = a => b => c => a + b + c;
        console.log(fn(10)(20)(30));

        // 闭包的反模式: 消除闭包, "纯函数"

        let a1 = 10;

        // a1 在函数fn中是自由变量,fn就是一个闭包
        fn = (a, b) => a + b + a1;

        // 将自由变量a1,通过参数传入函数中就可以
        fn = (a, b, a1) => a + b + a1;
        // 此时,fn中,a, b, a1全是自有变量
// 闭包
function fn() {
var arr = [];
for(var i=0;i<5;i++) {
arr[i] = function() {
return i;
}
}
return arr
}
var list = fn()
for(var i =0;i
console.log(list[i]());
}
// 大家猜猜,执行结果是什么?对,就是打印5个5。
咱们细品:首先执行fn函数,for循环给每个arr[i]赋予了function() {return i;},
循环下来得到五组函数function() {return i;},并且此时i = 5;
继续执行最下面for循环,list[i]()相当于执行function() {return i;},不过i此时是5,
而list中有5个这样的函数,所以打印5个5.
 
闭包的作用:
1.延长了局部变量的作用域范围。
2.使函数外部可读取到函数内部的数据。
 
闭包的缺点:
1.函数执行完后,函数内的局部变量没有释放,占用内存时间会变长
2.容易造成内存泄漏
demo2:访问器属性
// 访问器属性
        let user = {
            // 常规属性
            data: {
                name: '猪老师',
                age: 18,
            },
            // 获取年龄
            getAge() {
                return this.data.age;
            },
            // 设置年龄
            setAge(age) {
                if (age >= 18 && age <= 120) {
                    this.data.age = age;
                } else {
                    console.log('非法数据');
                }
            },
        };
        console.log(user.getAge());
        user.setAge(80);
        console.log(user.getAge());

        // 对于用户来说,获取年龄,习惯性会用这种方式来获取
        // console.log(user.age);
        // console.log(user.data.age);

        user = {
            // 常规属性
            data: {
                name: '猪老师',
                age: 18,
            },
            // 将传统的方法,修改一个伪装成属性的方法
            get age() {
                return this.data.age;
            },
            // 设置年龄,将之前的设置方法修改成了一个属性
            // 方法 -> 属性: 伪装成方法的属性,  "访问器属性"
            set age(age) {
                if (age >= 18 && age <= 120) {
                    this.data.age = age;
                } else {
                    console.log('非法数据');
                }
            },
        };

        console.log(user.age);
        user.age = 150;
        console.log(user.age);

        // 访问器属性,本质上还是方法,调用时,用的属性访问的语法
 
拓展知识:
1.什么是get和set方法。
get是获得属性的一种方法。
set是设置属性的一种方法。
get负责查询,不带任何参数。
set负责设置,是通过参数的形式传递。
2.get和set的使用方法。
get和set是方法,所以可以进行判断。
get一般是得到,需要返回。
set是创建,不需要返回。
每一个对象都有一个get和set方法。
如果调用的是对象内部的属性,命名格式是变量名前面添加。
3.get和set的定义。
在对象初始化时定义。
在对象定义后定义。
//在对象初始化时定义。
        var obj = {
            a: 1,
            b: 2,
            set c(x) {
                console.log('c被赋值', x);
                c = x;
            },
            get c() {
                console.log('c被取出', c);
                return c
            }
        };
        obj.c = 7  //c被赋值 7
        obj.c  //c被取出 7
        //对象初始化之后可以这样添加属性  
        var obj = {
            a: 1,
            b: 2
        };
        obj.__defineGetter__('c', function () {
            return c
        });
        obj.__defineSetter__('c', function (x) {
            c = x
        });
        //或者使用  
        Object.defineProperty(obj, c, {
            set: function (x) {
                console.log('c被赋值', x);
                c = x
            },
            get: function () {
                console.log('c被取出', c)
                return c
            }
        })
        obj.c = 3  //c被赋值 3
        obj.c  //c被取出 3
例子:
        var person = {
            _name: "lisi",
            _age: 18,
            //_name的只读。
            get name() {

                return this._name;
            },
            //_age的读写。

            set age(Age) {
                this._age = Age;
            },
            get age() {
                return this._age;
            }
        };

        console.log(person._name + " " + person._age);//lisi 18
        person.name = 'lily';
        person.age = 21;
        console.log(person.name + " " + person.age);//lisi 21
        console.log(person._name + " " + person._age);//lisi 21
        //因为_name只读不写,所以name不会发生改变。
demo3:类与对象
// 类: 构造函数,创建对象专用
        // function User(name, email) {
        //     this.name = name;
        //     this.email = email;
        // }

        // function User(name, email) {
        // 1. 创建一个新对象
        // let this = new User;

        // 2. 给这个刚刚创建的新对象this,添加新属性,并赋值
        // this.name = name;
        // this.email = email;

        // this.getInfo = function() {
        //     return `name: ${this.name}, email: ${this.email}`;
        // };

        // 3. 将这个新对象返回
        // return this;
        // }

        // let obj = new User('admin', 'admin@php.cn');
        // console.log(obj);
        // console.log(obj.getInfo());

        // let obj1 = new User('admin', 'admin@php.cn');
        // console.log(obj1);
        // console.log(obj1.getInfo());

        // 应该将对象中的公共成员,挂载到构造器函数的原型属性对象上
        // console.log(User.prototype);

        // 创建新对象,并完成属性初始化
        // function User(name, email) {
        //     this.name = name;
        //     this.email = email;
        // }

        // 将公共方法,挂载到构造函数的原型对象上
        // User.prototype.getInfo = function() {
        //     return `name: ${this.name}, email: ${this.email}`;
        // };

        // es6, class

        class User {
            // 私有变量

            // 静态变量,不能用对象访问,只能用类来访问,可以被所有对象共享
            static ok = 'hello';

            // 对象构造函数
            constructor(name, email) {
                // 属性初始化
                this.name = name;
                this.email = email;
            }

            // 方法
            getInfo() {
                return `name: ${this.name}, email: ${this.email}`;
            }
        }

        let obj = new User('张老师', 'zhang@php.cn');
        console.log(obj.getInfo());
        console.log(obj.ok);
        console.log(User.ok);
demo4:解构赋值
const user = ['朱老师', 'zls@qq.com'];
        console.log(user);
        // 为数组中的每一个成员,绑定一个变量
        let username = user[0];
        let useremail = user[1];
        console.log(username, useremail);

        // es6
        // 1. 数组解构
        // 模板 = 数组
        let [name, email] = ['朱老师', 'zls@qq.com'];
        // let name = '朱老师';
        // let email = 'zls@qq.com'
        console.log(name, email);
        [name, email] = ['张老师', 'zhang@qq.com'];
        console.log(name, email);

        // 参数不足: 默认值
        [name, email, age = 20] = ['张老师', 'zhang@qq.com'];
        console.log(name, email, age);

        // 参数过式: 剩余参数 ...
        [name, email, ...arr] = ['张老师', 'zhang@qq.com', 30, 34567];
        console.log(name, email, arr);

        // 对象解构
        // 模板 = 对象

        let obj = {
            id: 1,
            lesson: 'js',
            score: 80,
        };
        console.log(obj.id);
        // console.log(id);
        console.log(obj.score);
        // console.log(score);

        let {
            id,
            lesson,
            score
        } = {
            id: 1,
            lesson: 'js',
            score: 80,
        };
        console.log(id);
        console.log(lesson);
        // 更新报错
        // 使用圆括号 ,包含完整的赋值表达式,不能只包左边的模板
        ({
            id,
            lesson,
            score
        } = {
            id: 2,
            lesson: 'node',
            score: 90,
        });

        console.log(id, lesson);

        // 没用解构
        function getUser(obj) {
            return `id: ${obj.id}, lesson: ${obj.lesson}, score: ${obj.score}`;
        }
        console.log(getUser(obj));

        // 将函数的参数转为对象的一个模板,进行解构
        function getUser({
            id,
            lesson,
            score
        }) {
            // 这样的话,在函数中, 就可以直接使用解构后的变量来访问对象的属性了
            return `id: ${id}, lesson: ${lesson}, score: ${score}`;
        }
        console.log(getUser(obj));
demo5:获取dom元素
<ul class="list">
        <li class="item">item1</li>
        <li class="item">item2</li>
        <li class="item">item3</li>
        <li class="item">item4</li>
        <li class="item">item5</li>
    </ul>

    <script>
        // 1. 将所有的li.item 变成红色
        console.dir(document);
        // querySelectorAll(selector):返回一组元素
        console.dir(document.querySelectorAll('.item'));
        const items = document.querySelectorAll('.item');

        for (let i = 0; i < items.length; i++) {
            // console.log(items[i]);
            items[i].style.color = 'red';
        }

        // items.forEach(item => (item.style.color = 'green'));

        // 2. 将第一个改为蓝色
        // querySelector: 返回一组元素中的第一个,只返回一个,而不是一组
        const firstItem = document.querySelector('.item');
        // console.log(firstItem);
        firstItem.style.color = 'blue';

        console.log(document.querySelector('body'));
        console.log(document.body);
        console.log(document.head);
        console.log(document.title);

        // 获取html
        console.log(document.documentElement);
    </script>
Name:
<提交>