赞
踩
代理的数据 = new Proxy(源数据, {
get(){
// 获取数据时候触发
},
set(){
// 设置数据的时候触发
}
})
什么是闭包
闭包在开发中的使用
闭包有哪些优缺点
函数
函数在定义阶段做的事件
function 函数名(){
// 一段代码
var a = 1
console.log(1)
console.log(2)
}
函数的调用阶段
函数的执行空间
函数在调用的时候会开辟一块空间 用于存储函数内部的定义的属性和方法,这个开辟的空间被称为函数的执行空间
函数调用结束之后,执行空间就会被自动销毁
闭包
(以下代码均为课程实例)
<script>
var arr = [1,2,3]
var arr01 = [,,]
var arr02 = new Array(10)
var arr03 = []
console.log(arr)
console.log(arr03)
console.log(arr01 === [])
console.log(arr03 === []) // 因为他们不是同一个地址
// 判断数组为空一般根据数组的长度
console.log(arr01.length === 0)
console.log(arr03.length === 0)
</script>
<script> var obj = { a:1, b:2, c:3 } var obj02 = {} var obj03 = new Object() // 对象里面没有length属性 console.log(obj) console.log(obj02) console.log(obj02 === {}) // 不是同一个地址 即使为空也是不相等 console.log(obj.length === 0) console.log(obj02.length === 0) // 把对象转换成json字符串 console.log(JSON.stringify(obj) === '{}') console.log(JSON.stringify(obj02) === '{}') console.log(JSON.stringify(obj03) === '{}') // console.log('{}' == '{}') // 利用for..in for(let key in obj){ // 如果对象有键值对 它至少会进来一次 console.log(1) } for(let key in obj02){ // 如果是一个空对象 一次都不会进来 console.log(2) } /* 封装一个判断对象是否为空的方法 */ function isEmptyObject(data){ let isEmpty = true // 默认为true for(let key in data){ isEmpty = false } // 需要返回值 return isEmpty } console.log(isEmptyObject(obj)) // false console.log(isEmptyObject(obj02)) // true // 利用Object.keys() es6 console.log(Object.keys(obj)) console.log(Object.keys(obj02)) function isEmptyObject02(data){ return Object.keys(data).length === 0 } console.log(isEmptyObject02(obj)) // false console.log(isEmptyObject02(obj02)) // true // 利用Object.getOwnPropertyNames() es5 console.log(Object.getOwnPropertyNames(obj)) console.log(Object.getOwnPropertyNames(obj02)) </script>
<script> var person = { username: 'jack', age: 18, gender: '男' } var person02 = { username1: 'jack', age: 18, gender: '男' } var person03 = { username2: 'jack', age: 18, gender: '男', score: undefined } /* 封装一个方法,判断对象里面是否有username 访问对象里面有这个key 返回的就是对应的value 访问对象里面一个不存在的key 返回的是undefined */ console.log(person.username) console.log(person02.username) function hasKey(obj,key){ // 获取这个对象的value 判断这个value是否为undefined // 如果是undefined 代表对象里面没有这个键 // 如果不是undefined 代表对象里面有这个键 return obj[key] !== undefined } console.log(hasKey(person, 'username')) // true console.log(hasKey(person02, 'username')) // false console.log(hasKey(person03, 'username')) // false console.log(hasKey(person03, 'age')) console.log(hasKey(person03, 'score')) // false // in属性 // 一个对象可以使用in来检测是否有这个键名 // 如果对象有这个键返回true // 如果对象没有这个键返回false // 用法 键名 in 对象 console.log('username' in person) // person有没有username这个键名 console.log('score' in person) // person有没有score这个键名 function hasKey(obj,key){ return key in obj } console.log(hasKey(person, 'username')) // true console.log(hasKey(person02, 'username')) // false console.log(hasKey(person03, 'username')) // false console.log(hasKey(person03, 'age')) console.log(hasKey(person03, 'score')) // true // hasOwnProperty console.log(person.hasOwnProperty('username')) console.log(person.hasOwnProperty('score')) function hasKey(obj,key){ return obj.hasOwnProperty(key) } </script>
<script> var person = { username: 'jack', age: 18, gender: '男' } // 对于对象person里面的username进行修改 Object.defineProperty(person, 'username', { // value: '哈哈哈', // 对于person里面username的值进行了修改 // writable: false, // person里面的username不允许被修改了 // enumerable: false, // person里面username不可以被遍历 // configurable: false // person里面的username不可以删除 // get: function(){ // // 该方法在对象访问username的时候会触发一次 // console.log('get方法触发了') // // 需要有一个返回值 这个返回值就是获取的value // // 如果没有返回值 得到的value是undefined // return 'rose' // }, set(newVal){ // 该方法是在设置username的时候会触发一次 // 该方法会有一个形参 这个形参就是要设置的值 console.log('set方法触发了') console.log(newVal) } }) console.log(person.username) person.username = '哈哈哈' console.log(person.username) // delete person.username // console.log(person) // person.username = 'rose' // console.log(person.username) // for(let key in person){ // console.log(key) // console.log(person[key]) // } /* // 访问 console.log(person.username) // 访问对象里面某个value // 遍历 for(let key in person){ console.log(key) console.log(person[key]) } // 修改 person.username = 'rose' console.log(person.username) // 删除 delete person.gender console.log(person) */ </script>
<script> var person = { username: 'jack', age: 18, gender: '男' } /* 利用Object.defineProperty保证对象正常使用的同时还可以知道对象的值什么时候被获取,什么时候被设置 */ var tmp = person.username Object.defineProperty(person, 'username', { get: function(){ // 获取person的username时候触发 console.log('get触发了') // 此时返回值又获取了username 又会调用get方法 这时候会出现死递归 // return person.username return tmp }, set: function(newVal){ console.log('set触发了') console.log(newVal) tmp = newVal } }) console.log(person.username) person.username = 'rose' console.log(person.username) </script>
<body> <div id="app"></div> <div class="red"></div> <script> var person = { age: 18, }; // 把数据显示到页面 document.getElementById("app").innerHTML = person.age; document.querySelector(".red").innerHTML = person.age; // 修改数据 setInterval(() => { person.age++; // 每一次数据修改都需要重新渲染页面 document.getElementById("app").innerHTML = person.age; document.querySelector(".red").innerHTML = person.age; }, 1000); </script> </body>
<body> <div id="app"></div> <div class="red"></div> <script> /* 双向数据绑定: 单向: 数据改变,视图自动更新把一个数据显示到页面 数据变化了 页面会自动更新 利用的是Object.defineproperty的set方法 */ var person = { age: 18, }; var tmp = person.age Object.defineProperty(person, 'age', { get:function(){ console.log('get被触发') return tmp }, set: function(newVal){ console.log('set被触发') console.log(newVal) // 修改person里面的age tmp = newVal // 除了改变数据之外还要去渲染视图 document.getElementById("app").innerHTML = newVal; document.querySelector(".red").innerHTML = newVal; } }) // 把数据显示到页面 document.getElementById("app").innerHTML = person.age; document.querySelector(".red").innerHTML = person.age; // 对于person的age进行拦截 知道它什么时候被设置 什么时候被获取 // 修改数据 setInterval(() => { // 只需要修改数据 无需再次更新页面 person.age = Math.random(); }, 1000); person.age++ </script> </body>
<body> <div id="app"></div> <div class="red"></div> <input type="text" id="input" /> <button id="change">改变</button> <script> /* 双向数据绑定: 数据改变,视图自动更新:把一个数据显示到页面 数据变化了 页面会自动更新 利用的是Object.defineproperty的set方法 视图更新 数据也会更新 */ var person = { age: 18, }; var tmp = person.age; Object.defineProperty(person, "age", { get: function () { console.log("get被触发"); return tmp; }, set: function (newVal) { console.log("set被触发"); console.log(newVal); // 修改person里面的age tmp = newVal; // 除了改变数据之外还要去渲染视图 document.getElementById("app").innerHTML = newVal; document.querySelector(".red").innerHTML = newVal; document.getElementById("input").value = newVal; }, }); // 把数据显示到页面 document.getElementById("app").innerHTML = person.age; document.querySelector(".red").innerHTML = person.age; document.getElementById("input").value = person.age; // 对于person的age进行拦截 知道它什么时候被设置 什么时候被获取 // 修改数据 // setInterval(() => { // // 只需要修改数据 无需再次更新页面 // person.age = Math.random(); // }, 1000); document.querySelector("#change").onclick = function () { person.age++; }; /* 视图变化数据更新 */ document.getElementById("input").oninput = function(){ // 获取到它的value值 赋值给person的age person.age = this.value } </script> </body>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> </head> <body> <div id="app"> <span>{{ message }}</span> <input type="text" v-model="message"> <button @click="changeMessage">添加</button> </div> <script> var app = new Vue({ el: "#app", data: { message: "Hello Vue!", }, methods: { changeMessage(){ this.message = '哈哈哈' } }, }); </script> </body> </html>
<body> <ul> </ul> <script> var person = { username: 'jack', age: 17, gender: '男', score: 100 } // 取出对象的所有的key 给每个key都添加get和set for(let key in person){ Object.defineProperty(person, key, { get(){ console.log('get触发了') }, set(){ console.log('set被触发了') } }) } console.log(person.score) person.gender = '女' // 无法支持新增的数据 person.aa = 1 var list = ['猪八戒', '孙悟空', '唐三藏', '沙和尚'] for(let i = 0;i<list.length;i++){ let li = document.createElement('li') li.innerText = list[i] document.querySelector('ul').appendChild(li) Object.defineProperty(list, i, { get(){ console.log('数组的get') }, set(){ console.log('数组的set') } }) } list[0] = '天蓬元帅' // 无法支持新增的数据 list.push('白骨精') list[list.length-1] = '咕咕' </script> </body>
<body> <script> var person = { username: 'jack', age: 18, gender: '男' } // 返回一个代理后的数据 var proxyPerson = new Proxy(person, { get(){ console.log('get触发了') }, set(){ console.log('set触发了') } }) console.log(proxyPerson) console.log(person == proxyPerson) // 只要修改和访问这个代理的数据 就会触发set和get // proxyPerson.username // proxyPerson.age // proxyPerson.gender // proxyPerson.username = 'rose' // proxyPerson.age = 19 // proxyPerson.gender = '女' // 新增一个数据 person.score = 100 proxyPerson.score proxyPerson.score = 200 console.log(person) console.log(proxyPerson) // 代理数组 var list = ['猪八戒', '孙悟空', '唐三藏', '沙和尚'] var proxyList = new Proxy(list, { get(){ console.log('数组get触发了') }, set(){ console.log('数组set触发了') } }) console.log(proxyList[0]) proxyList[1] = '哈哈哈' // 新增一个数据 list.push('李逵') console.log(proxyList[proxyList.length-1]) proxyList[proxyList.length-1] = '葵葵' </script> </body>
<script> var person = { username: 'jack', age: 18, gender: '男' } // 返回一个代理后的数据 var proxyPerson = new Proxy(person, { // get方法有 get(target, key, receiver){ // 需要有一个返回值 这个返回就是得到的属性值 console.log('get触发了') // console.log(target) // 原数组 // console.log(key) // 访问的key // console.log(receiver) // 代理后的数据 return target[key] // 取出源数据的属性值返回 }, set(target, key, newVal, receiver){ console.log('set触发了') // 设置的时候要设置源数据 target[key] = newVal } }) console.log(proxyPerson.username) // console.log(proxyPerson.age) // proxyPerson.age = 20 console.log(proxyPerson.age) </script>
<body> <div id="app"> <p class="username"></p> <p class="age"></p> <p class="gender"></p> <input type="text" id="input"> <button onclick="click()">按钮</button> </div> <script> var person = { username: 'jack', age: 18, gender: '男' } let proxyPerson = new Proxy(person, { get(target,key,receiver){ return target[key] }, set(target,key,val,receiver){ console.log('set触发了') target[key] = val // 修改数据的时候 更新视图 document.querySelector('.username').innerHTML = person.username document.querySelector('.age').innerHTML = person.age document.querySelector('.gender').innerHTML = person.gender document.getElementById('input').value = person.age } }) // 第一次渲染视图 document.querySelector('.username').innerHTML = person.username document.querySelector('.age').innerHTML = person.age document.querySelector('.gender').innerHTML = person.gender document.getElementById('input').value = person.age // 单向数据绑定 数据变化 视图会自动更新 function click(){ proxyPerson.username = 'rose' proxyPerson.age = Math.random() } // 视图更新 数据也会变化 document.getElementById('input').oninput = change function change(){ console.log('input...') console.log(this) proxyPerson.age = this.value } </script> </body>
<body> <div class="box"> Lorem ipsum dolor, sit amet consectetur adipisicing elit. Rem amet, praesentium recusandae aut, repellendus vel doloribus laudantium qui reprehenderit saepe eius odit corrupti fugit labore quo, autem enim. Consequatur, laboriosam. </div> <script> // 函数在定义的时候 函数体内不会执行 function getSum(){ var a = 1 console.log(a) console.log(2) console.log(3) } function fn(){} function foo(){} // fn和foo存储都是地址 console.log(fn == foo) var box = document.querySelector('.box') function doClick(){ console.log(1) } box.addEventListener('click', doClick) box.removeEventListener('click', doClick) </script> </body>
(13)函数调用阶段
<body> <div class="box"> Lorem ipsum dolor, sit amet consectetur adipisicing elit. Rem amet, praesentium recusandae aut, repellendus vel doloribus laudantium qui reprehenderit saepe eius odit corrupti fugit labore quo, autem enim. Consequatur, laboriosam. </div> <script> // 函数在定义的时候 函数体内不会执行 function getSum(){ var a = 1 function fn(){ console.log('fn被调用') } console.log(a) console.log(2) console.log(3) fn() } // 函数的调用阶段 // 会将之前存储的字符串代码 转换成 js代码执行 // 函数内的定义变量 定义方法需要有一个地方进行存储 // 函数在调用的时候会开辟一块空间 用于存储函数内部的定义的属性和方法,这个开辟的空间被称为函数的执行空间 // 这个执行空间在我们函数调用结束之后就会自动销毁 getSum() // 在getSum调用的时候会开辟一块执行空间 // getSum调用结束 调用结束执行空间就会自动销毁 </script> </body>
<script> function foo(){ var a = 1 // 闭包返回的是一个函数 // 函数是引用的数据类型 return function A(){ console.log(a) a++ } } var data = foo() // 会生成一个执行空间 在执行空间内部存储a // foo调用结束之后 执行空间被销毁了 a就消失了 // 闭包是实现在foo外面访问foo内部的a // data就是函数foo返回的函数A console.log(data) // 调用data其实就是调用A A函数内的代码就会执行 A函数用了一个变量a本身没有 就会自动往上一级作用域查找 // 上一级作用域foo 里面有一个变量a 用的就是foo里面的a data() data() data() data() function A(){ var a = 1 return function B(){ console.log(a) } } var data = A() data() </script>
<script>
// 当函数调用返回一个引用的数据类型
function foo(){
var obj = {
a:1
}
return obj
}
foo()
// 函数外部有一个变量使用着函数的返回值
var data = foo()
// 在foo调用结束之后 使用data data就是函数foo的返回值 其实就是obj obj存储在函数foo的执行空间里面
// 能用data.a 就说明函数foo在调用之后执行空间并没有被销毁
console.log(data.a)
</script>
<script> // 闭包是为了避免全局变量污染的问题 // 有一个变量需要在函数外部使用 但是如果把这个变量放在全局 有可能被别人覆盖 function foo(){ var a = 1 return function(){ console.log(a) a++ } } var data = foo() data() // 污染了a var a = '哈哈哈' data() data() </script>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。