1.回忆
1、在普通函数中this指向window
2、在自执行函数this指向window
3、在定时器this指向window
4、在构建函数this执行实例化对象
5、在对象方法中this指向该方法所属的对象
6、在绑定事件中this指向绑定该事件的对象
7、在构建函数原型对象上this指向实例化对象
2.改变this指向
2.1 call()方法
语法:call(要指向的对象,参数,参数。。。。。。。。。)、
var obj={
name:'张三',
age:34
}
function max(x,y){
console.log(this);
console.log(x+y);
console.log(this.age-x-y);
}
此时max()方法中的this指向为window对象
max.call(obj,10,20)
就改变this的指向,此时this的指向就是obj
1、call会立即调用函数
2、参数传递的方式是以逗号隔开的
3、可以改变this的指向
2.1.1应用场景
检测数据类型
通过 Object.prototype.toString.call(要检测的数据)(最精准的检测方式)
Object.prototype.toString()判断数据类型
console.log(Object.prototype.toString()); //[object Object]
console.log(Object.prototype.toString.call(123)); //[object Number]
console.log(Object.prototype.toString.call(new Date)); //[object Date]
console.log(Object.prototype.toString.call(new RegExp));//[object RegExp]
function fun() {
}
console.log(Object.prototype.toString.call(fun)); //[object Function]
2.2 apply()方法
语法:语法:call(要指向的对象,数组)、
var obj={
name:'张三',
age:12
}
function sum(x,y){
console.log(this);
console.log(this.age+a+b);
}
sum.apply(obj,[20,20]);
1、apply 会立即调用函数
2、传入的参数是以数组形式
3、改变this指向
2.2.1应用场景
求最大值.....
// 求最大值
// Math.max
var rel=Math.max(1,2,3,4,5,6,7);
console.log(rel); //7
var arr=[342,464,46,424,646,535];
// 先看apply(Math,arr);让this指向Math,然后Math.max求出最大值;
var rel1 =Math.max.apply(Math,arr);
console.log(rel1);
2.3 bind()方法
语法:var rel=obj.bind(要指向的对象,参数,参数。。。。。。。。。)
rel() 或call(要指向的对象,参数,参数。。。。。。。。。)() 需要调用
var obj={
name:'李四',
age:42
}
function sum(a,b){
console.log(this);
console.log(this.age+a+b)
}
// 在这一行bind只是把sum函数内部的this指向改变并没有调用函数,应该先改变this指向在调用该函数
//并没有调用该函数
var rel =sum.bind(obj,200,200);
console.log(rel); // ƒ sum(a,b){
// console.log(this);
// console.log(this.age+a+b)
// }
// 只是指向了并没有调用该sum对象
// 先让this指向该对象在调用该函数
var rel1 = sum.bind(obj,200,200)();
console.log(rel1); //{name: '李四', age: 42} 442
1、bind 不会立即调用 需要手动调用
2、传入的参数是以逗号隔开的
3、改变this指向
2.3.1 应用场景
延迟应用定时器
<body>
<button>5秒之后再次点击</button>
<button>5秒之后再次点击</button>
<button>5秒之后再次点击</button>
<button>5秒之后再次点击</button>
<button>5秒之后再次点击</button>
<script>
var btn = document.querySelectorAll("button");
// var timerId = null;
for (var i = 0; i < btn.length; i++) {
btn[i].onclick = function () {
this.disabled = true;
var num = 5;
var timerId = setInterval(function () {
num--;
if (num <= 0) {
this.disabled = false;
this.innerText = "5秒之后再次点击";
clearInterval(timerId);
} else {
this.innerText = num + "秒之后再次点击";
}
}.bind(this), 1000);
}
}
</script>
2.4 call / apply / bind 有啥区别
- 共同点 : 都可以改变this指向
- 不同点:
- call 和 apply会立即调用函数.bind不会立即调用函数, 需要手动调用.
- call及bind 和 apply传递的参数不一样,call及bind传递参数使用逗号隔开,apply使用数组传递.
- 应用场景
- call 经常做继承.
- apply 经常跟数组有关系. 比如借助于数学对象实现数组最大值最小值
- bind 不调用函数,但是还想改变this指向. 比如改变定时器内部的this指向.
3.检测数据类型
1、typeof (检测基本数据类型)
console.log(typeof num); //number
2、instanceof 用于检测复杂数据类型
console.log(new Date instanceof Object); //true
console.log(num instanceof Object); //false
console.log(fun instanceof Function); //true
3.constructor: 检测当前实例的构造函数
console.log(obj.constructor == Object);//true
console.log(date.constructor == Date);//true
4、Object.prototype.toString.call()最精准的检测方式
console.log(Object.prototype.toString.call(123)); //[object Number]
console.log(Object.prototype.toString.call(new Date)); //[object Date]
4.定时器传参
var j =10;
setTimeout('fun(j)',3000); //3s输出 30
function fun(i){
console.log(i+20);
}
加引号会让定时器会在2s后运行,先运行定时器在运行函数
不加会直接调用函数,函数在定时器前面,会直接打印函数内容
作用:
解决定时器不能传参的问题
在外部封装函数 写在定时器方法里面进行调用
注意:要用引号将函数包括
5.继承
5.1 构造函数继承
子构建函数继承父构建函数的属性
使用call方式实现子继承父的属性
// 父结构函数
function Fun(name,age,gender){
this.name=name;
this.age=age;
this.gender=gender;
console.log(1);
}
var fun = new Fun("熊大",20,'动物');
console.log(fun);
// 子构建函数
function Son(name,age,gender){
// this指向Fun参数
console.log(2);
console.log(this);
//3.使用call方式实现子继承父的属性
// 并没有改变this的指向,只是继承了父元素的属性
console.log( Fun.call(this,name,age,gender));
console.log(this);
}
var son = new Son('熊二',18,'动物');
5.2 原型对象继承方法
也是通过call来继承
// 父结构函数
function Fun (name,age,gender){
this.name=name;
this.age=age;
this.gender=gender;
}
Fun.prototype.x=function(){
console.log('翠花');
}
var rel = new Fun('熊大',20,'动物');
console.log(rel);
// 子构建函数
function Son (name,age,gender){
// 让子构建函数继承父构建函数的属性
// 不会改变this的指向
Fun.call(this,name,age,gender);
}
// 原型继承 如果直接使用原型对象赋值的方式 继承 那么两个对象会指向同一个数据
// 修改其中一个 另外一个也会被修改 ;
//
// Son.prototype=Fun.prototype;
// 应该
Son.prototype=new Fun(); //constructor:ƒ Fun(name,age,gender)
// 此时constructor 指向父元素
// 所以这里必须要多一步 让son 的constructor指回本身
Son.prototype.constructor=Son; //constructor:ƒ Son(name,age,gender)
// 在子元素的原型上添加修改方法不会改变父元素的方法
Son.prototype.gtq=function(){
console.log('光头强');
}
var son = new Son('熊二',18,'动物');
console.log(son);
5.3 Object.create实现类式继承
内一个方法Object.create(proto, [propertiesObject])
function Fun (a){
this.a=a;
}
var rel = new Fun('170cm');
console.log(rel);
// 渴热奥特
// Object.create()
// 第一个参数是以谁为原型创建对象
// 第二个参数 传入一个对象用来设置 新对象的值和属性特征;
var rel1 =Object.create(rel,{
name:{
// 也可以不加下列该属性,下列属性起到权限的作用1
configurable:true,
enumerable:true,
writable:true,
value:"玛玛哈哈"
},age:{
configurable:true,
enumerable:true,
writable:true,
value:20
}
})
console.log(rel1);
// 继承到原型对象的上
console.log(rel1.a); //170cm
6.数组操作方法
不会对伪数组进行操作
都不会改变原数组
6.1 数组方法forEach遍历数组
语法:
forEach遍历数组 arr.forEach(function(value, index, array) { //参数一是:数组元素 //参数二是:数组元素的索引 //参数三是:当前的数组 }) //相当于数组遍历的 for循环 没有返回值
var arr = [1, 2, 3, 5, 6, 7, 89];
// 遍历数组
var rel = arr.forEach(function (value, index, arr) {
// value当前元素
// index元素的索引
// arr当前数组
console.log(value);
})
每次运行都会对数组的每一个值进行遍历
6.2 数组方法map遍历数组
map() 方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。
map() 方法按照原始数组元素顺序依次处理元素。
注意: map() 不会对空数组进行检测, map() 不会改变原始数组
var arr = [1,2,3,4,5,6,7];
var newArr = arr.map(function(value, index, array){
//参数一是:数组元素
//参数二是:数组元素的索引
//参数三是:当前的数组
return value*4;
});
console.log(arr);//[1,2,3,4,5,6,7]
console.log(newArr);//[4,8,12,16,20,24,28]
6.3 数组方法filter过滤数组
filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。
var arr = [12, 66, 4, 88, 3, 7];
var newArr = arr.filter(function(value, index,array) {
//参数一是:数组元素
//参数二是:数组元素的索引
//参数三是:当前的数组
return value >= 20;
});
console.log(newArr);//[66,88] //返回值是一个新数组
6.4 数组方法some
some 查找数组中是否有满足条件的元素 ,如果数组中有元素满足条件返回 true,否则返回 false。
只要查找到满足条件的一个元素就立马终止循环
var arr = [10, 30, 4];
var flag = arr.some(function(value,index,array) {
//参数一是:数组元素
//参数二是:数组元素的索引
//参数三是:当前的数组
return value < 3;
});
console.log(flag);
6.5数组方法every
every() 方法用于检测数组所有元素是否都符合指定条件(通过函数提供
如果数组中检测到有一个元素不满足,则整个表达式返回 false ,且剩余的元素不会再进行
如果所有元素都满足条件,则返回 true。
注意: every() 不会对空数组进行检测。
注意: every() 不会改变原始数组。
var arr = [56, 32, 78, 11, 23, 103, 45, 103];
// every() 方法用于检测数组所有元素是否都符合指定条件(通过函数提供)。
var rel = arr.every(function (v) {
console.log("zhixing");
return v < 100
// 如果数组中检测到有一个元素不满足,则整个表达式返回false,且剩余的元素不会再进行检测。
// 所有元素都满足条件 才会返回true
})
console.log(rel); //6次zhixing false
6.6 数组方法find
find() 方法返回通过测试(函数内判断)的数组的第一个元素的值。
find() 方法为数组中的每个元素都调用一次函数执行:
当数组中的元素在测试条件时返回 true 时, find() 返回符合条件的元素,之后的值不会再调用执行函数。
如果没有符合条件的元素返回 undefined
var arr = [56, 32, 78, 11, 23, 103, 45, 103];
var rel = arr.find(function (v) {
console.log("执行");
return v > 100
})
console.log(rel); //6次执行 103
6.7 数组方法reduce
reduce方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。
array.reduce(function (total, value, index, array) {
- total 必需。初始值, 或者计算结束后的返回值。
value 必需。当前元素
index 可选。当前元素的索引
array可选。当前元素所属的数组对象。
- initialValue 作为第一次调用 `callback`函数时的第一个参数的值。 如果没有提供初始值,则将使用数组中的第一个元素。
}, initialValue)
// 求和
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var rel1 = arr.reduce(function (total, value) {
return total + value
})
console.log(rel1); //45
// 求最大值
var arr2 = [45, 67, 12, 2, 103, 44, 33];
var rel2 = arr2.reduce(function (total, value) {
// if (total < value) {
// total = value;
// }
return Math.max(total, value);
})
console.log(rel2); //103
// 数组去重
// splice push()
var arr3 = [44, 65, 44, 12, 3, 2, 5, 2, 16];
var rel3 = arr3.reduce(function (total, value, index) {
// []
if (!total.includes(value)) {
total.push(value);
}
return total;
}, [])
console.log(rel3); //[44, 65, 12, 3, 2, 5, 16]