ES5数组新增方法、函数、闭包
ES5新增方法
ES5数组新增了filter、map、some、every这几个方法
字符串新增了trim()去除空白的方法,返回一个新的字符串
筛选数组filter方法
filter()方法创建一个新的数组,新数组中的元素时通过检查数组中符合条件的元素,主要用于筛选数组
- 筛选出数组中的偶数
<script>
var array=[1,2,3,4,5,6];
array.filter((value, index, array1) => {
return value%2===0;
})
for (let number of numbers) {
console.log(number);
}
</script>
some()
some方法用于检测数组中的元素是否满足指定条件(查找数组中是否有满足条件的元素)
返回值是boolean值,如果找到满足条件的元素返回true,找不到返回false
- 查找元素中是否有偶数
<script>
var array=[1,2,3,4,5,6];
let b = array.some((value, index, array1) => {
return value%2===0;
});
console.log(b);
</script>
商品查询案例
如果查询数组中唯一的元素,用some()方法更合适,因为它找到和这个元素,就不在进行循环,效率更高
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
table {
width: 400px;
border: 1px solid #000;
border-collapse: collapse;
margin: 0 auto;
}
td,
th {
border: 1px solid #000;
text-align: center;
}
input {
width: 50px;
}
.search {
width: 600px;
margin: 20px auto;
}
</style>
</head>
<body>
<div class="search">
按照价格查询: <input type="text" class="start"> - <input type="text" class="end">
<button class="search-price">搜索</button>
按照商品名称查询: <input type="text" class="product">
<button class="search-pro">查询</button>
</div>
<table>
<thead>
<tr>
<th>id</th>
<th>产品名称</th>
<th>价格</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<script>
var data = [{
id: 1,
pname: '小米',
price: 3999
}, {
id: 2,
pname: 'oppo',
price: 999
}, {
id: 3,
pname: '荣耀',
price: 1299
}, {
id: 4,
pname: '华为',
price: 1999
},];
let tBody = document.querySelector('tbody');
let searchPrice = document.querySelector('.search-price');
let searchPro = document.querySelector('.search-pro');
let startPrice = document.querySelector('.start');
let endPrice = document.querySelector('.end');
let product = document.querySelector('.product');
setData = (array) => {
tBody.innerHTML = ``;
array.forEach(value => {
var tr = `
<tr>
<td>${value.id}</td>
<td>${value.pname}</td>
<td>${value.price}</td>
</tr>
`;
tBody.insertAdjacentHTML('beforeend', tr);
})
}
setData(data);
searchPrice.addEventListener('click', function () {
let nArray = data.filter(value => {
let price = value.price;
return price >= startPrice.value && price <= endPrice.value;
});
setData(nArray);
});
searchPro.addEventListener('click',function () {
var nArray=[];
data.some(value => {
if (value.pname===product.value){
nArray.push(value);
//记得return true 把循环结束掉
return true;
}
})
setData(nArray);
})
</script>
</body>
</html>
Object.defineProperty
Object.defineProperty:往对象中添加或者属性或修改原有属性
如果属性没有则新加,如果有则修改
<script>
var obj={name:'daga'};
Object.defineProperty(obj,'age',{
value:25
});
console.log(obj);
</script>
<script>
var obj={name:'daga'};
Object.defineProperty(obj,'age',{
value:25
});
Object.defineProperty(obj,'age',{
//不允许修改值
writable:false
})
console.log(obj);
</script>
Object.keys
获取对象的属性名,返回值为对象属性名的数组
<script>
var obj={name:'daga',age:25};
let strings = Object.keys(obj);
for (let string of strings) {
console.log(string);
}
</script>
delete obj.name(删除属性名)
<script>
var obj={name:'daga',age:25};
delete obj.name;
let strings = Object.keys(obj);
for (let string of strings) {
console.log(string);
}
</script>
bind
改变函数内this指向, js提供了三种方法 call() apply() bind()
bind()方法不会调用函数,但是能改变函数内部this指向,返回由指定的this值和初始化参数改造的原函数的拷贝
<script>
var o={name:'andy'};
function fn() {
console.log(this);
}
let fn1 = fn.bind(o);
//新的拷贝函数
fn1();
</script>
如果有的函数我们不需要立即调用,但是又想改变这个函数内部的this指向此时的bind
- 案例
有一个按钮,当我们点击了之后就禁用这个按钮,3秒之后开启这个按钮
<script>
window.onload=function () {
let button = document.querySelector('.button');
button.addEventListener('click',function () {
this.disabled=true;
setTimeout(function () {
this.disabled=false;
}.bind(this),3000); //这个this指向的是button
});
}
</script>
call apply bind总结
相同点:都可以改变函数内部的this指向
区别点:call和apply会调用函数,并且改变函数内部this指向
call和apply传递的参数不一样,call传递参数,apply必须以数组形式
bind不会调用函数,可以改变函数内部this指向
- 应用场景
call经常做继承
apply经常跟数组有关系,比如借助于数学对象实现数组最大值最小值
<script>
var array=[25,36,8,98,0,36];
let number = Math.max.apply(Math,array);
alert(number);
</script>
bind不调用函数,但是还想改变this指向,比如改变定时器内部的this指向,并且返回值是一个函数
高阶函数
高阶函数:高阶函数是对其他函数进行操作的函数,它接受函数昨晚参数或将函数作为返回值输出
- 函数作为参数(应用于回调函数)
<script>
function fn1(callback) {
callback&&callback();
}
fn1(function () {
alert('hi')
})
</script>
- 函数作为返回值(应用于闭包)
<script>
function fun() {
return function (){};
}
fun();
</script>
闭包
定义:指有权访问另一个函数作用域中变量的函数
简单理解就是,一个作用域可以访问另外一个函数内部的局部变量,闭包就是函数
内部函数访问外部作用域函数变量的时候,只有当闭包函数被调用完毕,该变量才会被销毁,否则将一直存放在闭包函数中(闭包对象)
<script>
function f1() {
var a=5;
return function () {
console.log(a);
}
}
let f = f1();
f();
</script>
闭包的主要作用:延伸了变量的作用范围
闭包应用一
点击li输出当前li的索引号
立即执行函数也称为小闭包,因为立即执行函数里面的任何一个函数都可以使用它的i变量
<script>
window.onload=function () {
let lis = document.querySelector('.nav').querySelectorAll('li');
for (var i = 0; i < lis.length; i++) {
(function (i) {
lis[i].onclick=function () {
console.log(i);
}
})(i);
}
}
</script>
</head>
<body>
<ul class="nav">
<li>榴莲</li>
<li>臭豆腐</li>
<li>鲱鱼罐头</li>
<li>大猪蹄子</li>
</ul>
闭包应用二
3秒后,打印li元素的内容
<script>
window.onload=function () {
let lis = document.querySelector('.nav').querySelectorAll('li');
for (var i = 0; i < lis.length; i++) {
(function (i) {
setTimeout(function () {
console.log(lis[i].innerHTML);
},3000)
})(i);
}
}
</script>
</head>
<body>
<ul class="nav">
<li>榴莲</li>
<li>臭豆腐</li>
<li>鲱鱼罐头</li>
<li>大猪蹄子</li>
</ul>
闭包应用三
计算打车价格
<script>
// 闭包应用-计算打车价格
// 打车起步价13(3公里内), 之后每多一公里增加 5块钱. 用户输入公里数就可以计算打车价格
// 如果有拥堵情况,总价格多收取10块钱拥堵费
var car= (function () {
//起步价
var start=13;
//总价
var total=0;
return {
//正常的总价
price:function (n) {
if (n <= 3) {
total=start;
}else {
total=start+(n-3)*5;
}
return total;
},
//拥堵之后的费用
yd:function (flag) {
return flag?total+10:total;
}
}
})();
console.log(car.price(5));
console.log(car.yd(true));
</script>
思考题
思考题1产生了闭包,思考题2没有产生闭包
<script>
// 思考题 1:
var name = "The Window";
var object = {
name: "My Object",
getNameFunc: function() {
return function() {
return this.name; //this指向window
};
}
};
console.log(object.getNameFunc()())
var f = object.getNameFunc();
// 类似于
var f = function() {
return this.name;
}
f();
// 思考题 2:
// var name = "The Window";
// var object = {
// name: "My Object",
// getNameFunc: function() {
// var that = this;
// return function() {
// return that.name;
// };
// }
// };
// console.log(object.getNameFunc()())
</script>
闭包总结
闭包是一个函数(一个作用域可以哦访问另外一个函数的局部变量)
闭包的主要作用是延伸变量的作用范围(可以通过闭包保存外部变量)
递归
如果一个函数在内部可以调用其自身,那么这个函数就是递归函数。
简单理解:函数内部自己调用自己。这个函数就是递归函数
递归函数的作用和循环效果一样
由于递归很容易发生栈溢出错误,所以必须要加退出条件 return
利用递归求阶乘
<script>
// 1*2*3*4*5; f(n)=f(n-1)*n f(3)=(f2)*3 f(2)=f(1)*2
function f(n) {
if (n===1){
return 1;
}
return f(n-1)*n;
}
console.log(f(3));
</script>
利用递归求斐波那契数列
<script>
// 1 1 2 3 5 f(n)=f(n-1)+f(n-2)
function f(n) {
if (n===1||n===2){
return 1;
}
return f(n-1)+f(n-2);
}
console.log(f(24));
</script>
根据id号返回数据对象
数据遍历
<script>
var data = [{
id: 1,
name: '家电',
goods: [{
id: 11,
gname: '冰箱',
goods: [{
id: 111,
gname: '海尔'
}, {
id: 112,
gname: '美的'
},]
}, {
id: 12,
gname: '洗衣机'
}]
}, {
id: 2,
name: '服饰'
}];
function readData(data, id) {
var o = {};
data.forEach(value => {
if (value.id === id) {
o = value;
} else if (value.goods && value.goods.length > 0) {
o = readData(value.goods, id);
}
})
return o;
}
console.log(readData(data, 1));
console.log(readData(data, 2));
console.log(readData(data, 111));
console.log(readData(data, 12));
</script>
拷贝
浅拷贝
浅拷贝只是拷贝一层,更深层次对象级别的只拷贝引用
- ES5实现
<script>
var obj={
id:1,
name: 'andy',
msg:{
age:18
}
};
var o={};
for (let key in obj) {
o[key]=obj[key];
}
console.log(o);
</script>
- ES6实现
Object.assign(o,obj);
<script>
var obj={
id:1,
name: 'andy',
msg:{
age:18
}
};
var o={};
Object.assign(o,obj);
console.log(o);
</script>
深拷贝
深拷贝拷贝多层,每一级别的数据都会拷贝
- ES5实现
<script>
var obj={
id:1,
name: 'andy',
msg:{
age:18
}
};
var o={};
//深拷贝
function deepCopy(o,obj) {
for (let k in obj) {
let item = obj[k];
//如果是数组
if (item instanceof Array){
//开辟数组空间
o[k]=[];
deepCopy(o[k],item);
}else if (item instanceof Object){
//开辟新的对象空间
o[k]={};
deepCopy(o[k],item);
}else {
o[k]=item;
}
}
}
deepCopy(o,obj);
console.log(o);
</script>