call、 apply和 bind的使用
一、用途
call()、apply()、bind() 都是用来重定义 this 这个对象的,
二、区别
call:改变了this指向 并 让函数执行,传递参数一个个传递
apply:改变了this指向 并 让函数执行,传送参数必须是数组
bind:改变了this指向 函数不执行。
三、使用
1.数据类型的检测
typof的不足:检测基本数据类型OK,对于引用数据类型来说,检测function也可以检测到,但是其它的检测的比较笼统,不够准确。
<script>
console.log(typeof 1) // number ok
console.log(typeof "hello") // string ok
console.log(typeof true) // boolean ok
var a;
console.log(typeof a) // undefined ok
console.log(typeof [1,2,3]) // object ok
console.log(typeof {a:1}) // object ok
let d = new Date();
console.log(typeof d) // object ok
let r = new RegExp() //正则
console.log(typeof r) // object ok
function f(){}
console.log(typeof f) // function ok
</script>
利用Object.prototype.toString.call可以非常精确地检测一个数据的数据类型。思路:一个对象在调用toSring时,如果它的原型上有toString方法,就调用它的原型上的toString。没有的话,和会找Object的原型对象上的方法。这里直接去调用Object上面的toString方法,返回数据类型。
<script>
// call 1)改变toString中的this的指向 指向了{}
// 2)让toString执行
console.log(Object.prototype.toString.call(1)); // 此时会把1瞬间包装成对象
console.log(Object.prototype.toString.call("hello")); // 此时"hello"也瞬间包装成对象了
console.log(Object.prototype.toString.call(true))
var a;
console.log(Object.prototype.toString.call(a))
console.log(Object.prototype.toString.call({}))
console.log(Object.prototype.toString.call([]))
function f(){}
console.log(Object.prototype.toString.call(f))
let d = new Date()
console.log(Object.prototype.toString.call(d))
let r = new RegExp();
console.log(Object.prototype.toString.call(r))
</script>
一般对象通过打点调用
2.简单封装类进行数据类型检测
<script>
function getType(abc) {
var rs = Object.prototype.toString.call(abc);
rs = rs.substr(8) //截取字符串,具体使用在下面
var len = rs.length
return rs.substr(0,len-1).toLowerCase() //转化为小写
}
console.log(getType(123));
console.log(getType([]));
console.log(getType({}));
console.log(getType(new Date));
console.log(getType(new RegExp));
var f = function(){}
console.log(getType(f));
</script>
1)substr()
转自:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/substr
substr() 方法返回一个字符串中从指定位置开始到指定字符数的字符。
语法
str.substr(start[, length])
参数
start:开始提取字符的位置。如果为负值,则被看作 strLength + start,其中 strLength 为字符串的长度(例如,如果 start 为 -3,则被看作 strLength + (-3))。
length:可选。提取的字符数。
示例
var str = "abcdefghij";
console.log("(1,2): " + str.substr(1,2)); // (1,2): bc
console.log("(-3,2): " + str.substr(-3,2)); // (-3,2): hi
console.log("(-3): " + str.substr(-3)); // (-3): hij
console.log("(1): " + str.substr(1)); // (1): bcdefghij
console.log("(-20, 2): " + str.substr(-20,2)); // (-20, 2): ab
console.log("(20, 2): " + str.substr(20,2)); // (20, 2):
3.字符串进行翻转
方法一
<script>
var str = "123456789";
// 把上面的字符串进行翻转
var newStr = "";
// ...
for (var i=str.length-1; i>=0; i--){
newStr += str[i];
}
console.log(newStr); // 987654321
</script>
方法二:
<script>
// 数组中有一个翻转的方法
var arr = [1,2,3];
console.log(arr.reverse()); // [3, 2, 1]
// 目标:让字符串翻转
// 把字符串变成数组
var str = "123456789";
console.log(str.split("")); // split()分割字符串 ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
console.log(str.split("").reverse()); // ["9", "8", "7", "6", "5", "4", "3", "2", "1"]
console.log(str.split("").reverse().join()); // 9,8,7,6,5,4,3,2,1
console.log(str.split("").reverse().join("")); // 987654321
</script>
1)join()
转自:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/join
join() 方法返回一个字符串中从指定位置开始到指定字符数的字符。
语法
arr.join([separator])
参数
separator(可选):指定一个字符串来分隔数组的每个元素。如果需要,将分隔符转换为字符串。如果缺省该值,数组元素用逗号(,)分隔。如果separator是空字符串(""),则所有元素之间都没有任何字符。
返回值
一个所有数组元素连接的字符串。如果 arr.length 为0,则返回空字符串。
示例
var a = ['Wind', 'Rain', 'Fire'];
var myVar1 = a.join(); // myVar1的值变为"Wind,Rain,Fire"
var myVar2 = a.join(', '); // myVar2的值变为"Wind, Rain, Fire"
var myVar3 = a.join(' + '); // myVar3的值变为"Wind + Rain + Fire"
var myVar4 = a.join(''); // myVar4的值变为"WindRainFire"
4.伪数组变成一个真实的数组
伪数组:长的像数组,但不是真正的数组,本质是对象,没有数组原型对象上的方法。
常见的伪数组
1)通过document.getElementsByTagName获取的元素集合就是伪数组
2)函数内部的arguments
arguemnts是函数内部的一个对象,用来收集实参,函数外部是不能访问arguments的
方法一:
<span>1</span><span>2</span><span>3</span>
<script>
// 如何把一个伪数组(对象)转成真实的数组
var spans = document.getElementsByTagName("span");
var arr = [];
// 把一个伪数组变成一个真实的数组
for (let i = 0; i < spans.length; i++) {
arr.push(spans[i]);
}
console.log(arr);
</script>
方法二:
<span>1</span><span>2</span><span>3</span>
<script>
var spans = document.getElementsByTagName("span");
console.log(Array.isArray(spans)); // false
// spans本质还是对象 让span借用slice方向
console.log(Array.prototype.slice.call(spans));
console.log(Array.isArray(Array.prototype.slice.call(spans))); // true
</script>
1)slice()
转自:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/slice
substr() 方法返回一个字符串中从指定位置开始到指定字符数的字符。
语法
str.slice(beginIndex[, endIndex])
参数
beginIndex:从该索引(以 0 为基数)处开始提取原字符串中的字符。如果值为负数,会被当做 strLength + beginIndex 看待,这里的strLength 是字符串的长度(例如, 如果 beginIndex 是 -3 则看作是:strLength - 3)
endIndex:可选。在该索引(以 0 为基数)处结束提取字符串。如果省略该参数,slice() 会一直提取到字符串末尾。如果该参数为负数,则被看作是 strLength + endIndex,这里的 strLength 就是字符串的长度(例如,如果 endIndex 是 -3,则是, strLength - 3)。
返回值
返回一个从原字符串中提取出来的新字符串
示例
var str1 = 'The morning is upon us.', // str1 的长度 length 是 23。
str2 = str1.slice(1, 8),
str3 = str1.slice(4, -2),
str4 = str1.slice(12),
str5 = str1.slice(30);
console.log(str2); // 输出:he morn
console.log(str3); // 输出:morning is upon u
console.log(str4); // 输出:is upon us.
console.log(str5); // 输出:""
5.区别
call()方法
<script>
function F(a,b) {
return a+b;
}
var obj = {};
F.call(obj); // 让F执行,关键是我们如何给F传递参数
F(1,2); // 我们自己调用F函数 并 传递参数
console.log(F.call(obj,4,5)); // call方法里面可以有多个参数
// 第个参数表示谁去借用这个方法 后面的参数都是给这个方法传递的参数
</script>
apply()方法
<script>
// apply 和 call一模一样 唯一区别是传递参数的区别
function F(a,b) {
console.log("F...")
return a+b;
}
var obj = {};
console.log(F.apply(obj,[1,2])); // 让obj借用F函数
</script>
bind()方法
<script>
// bind 绑定的意思
// call 改变了this指向 并 让函数执行 传递参数一个个传递
// apply 改变了this指向 并 让函数执行 传送参数必须是数组
// bind 改变了this指向 函数不执行
function F(a,b) {
console.log("F...")
return a+b;
}
var obj = {};
let k = F.bind(obj)
console.log(k(1, 2));;
</script>
小练习
问:什么情况下,让a可以等于1,也可以等于2,也可以等于3
方法一:
<script>
let a = {
n:0, // a对象的私有属性 1
toString:function () { // a对象有私有属性(方法)
// console.log("这是自己的toSring...")
// this ==> a this.n a.n
return ++this.n;
}
}
// 显示地调用 a.toString()
console.log(a == 1)
console.log(a == 2)
console.log(a == 3)
</script>
方法二:
<script>
let a = {
n:0,
toString:function () {
return ++this.n;
}
}
if(a==1 && a==2 && a==3){
console.log("ok");
}
</script>
方法三:
<script>
let a = [1,2,3];
// .... shift
a.toString = a.shift; // 你调用toString就相当于调用了shift
// a==1 先调用a.toString 内部调用了
if(a==1 && a==2 && a==3){
console.log("ok");
}
</script>