call的探索
01 call借用
//对象1
var myclass={
getAllStudentsNumbers:function(){
return 130}
};
//对象2
var student={
getDetail:function(){
return {name:'莉莉',aihao:'唱歌跳舞'}
}
};
//借用 -- 供爷法则
console.log(myclass.getAllStudentsNumbers.call(student))
02 call 传参1
//对象1
var myclass={
getAllStudentsNumbers:function(sum,sum1){
return sum+sum1}
};
//对象2
var student={
getDetail:function(){
return {name:'莉莉',aihao:'唱歌跳舞'}
}
};
//借用 -- 供爷法则
console.log(myclass.getAllStudentsNumbers.call(student,10,200))
console.log(myclass.getAllStudentsNumbers.apply(student,[10,200]))
02 call 传参2
//函数其实也是对象
function add(a, b) {
alert(a + b);
}
function sub(a, b) {
alert(a - b);
}
/*借用:
就是把人家的方法放到自己中来*/
add.call(sub, 3, 1);
03 call 作用 修改this
用户名:<input type="text" id="myText" value="探索" />
var value="全局变量";
/*函数中默认this指向window*/
function Fun1(){
console.log(this.value);
}
/*答案:全局变量*/
window.Fun1();
/*答案:window*/
Fun1.call(window);
/*答案:window*/
/*可以这么理解:先把fun1变成window对象的方法,同时改变Fun1中的this指向*/
/*这个时候this表示window*/
function Fun1(){
console.log(this.value);
}
Fun1.call(document.getElementById('myText'));
/*答案*/
/*这个时候this指向input元素对象*/
//探索
05 call作用 伪数组 - 将dom元素集合数组化
/*什么叫伪数组*/
/*伪数组:只有数组的部分功能:length,下标,无法访问数组对象中的方法*/
/*Array.prototype.slice.call(arguments)能将具有length属性的对象转成数组*/
/*这是一种固定用法*/
/*为什么需要学习伪数组*/
/*js中常见的伪数组:通过document获取的dom集合*/
/*最为常用的arguments*/
/*这些伪数组无法使用Array对象中的方法,因为他们不是数组对象,就是普通的含有length属性的json对象而已*/
/* 比如:var json = {1:'',2:'',length:2}*/
var divs = document.getElementsByTagName("div")
console.log(divs.length)
/*说明他不是一个数组,无法访问里面的方法*/
divs.pop().style.background='green'//报错
/*我们通过如下方式将其转换成数组*/
/* slice : 截取数组,返回的还是数组,这里我们截取全部 */
var domNodes = Array.prototype.slice.call(divs);
/*这样domNodes就可以应用Array下的所有方法了。*/
domNodes.pop().style.background='green'
06 将arguments数组化
function add(){
var sum=0;
/* arguments.push(10) //报错*/
var arr = Array.prototype.slice.call(arguments)
arr.push(10) //报错
for(var i=0;i<arr.length;i++){
sum+=arr[i]
}
return sum;
}
var sum = add(1,2,3,4,5)
console.log(sum)
07 将自定义伪数组数组化
var fackArray1 = {0:'first',1:'second',length:2};
Array.prototype.slice.call(fackArray1);// ["first", "second"]
var fackArray2 = {length:2};
Array.prototype.slice.call(fackArray2);// [undefined, undefined]
aplay的探索
02 妙用1 参数数组拆分法则 - 计算数组最大值
/* 我们先从Math.max()函数说起, Math.max后面可以接任意个参数,最后返回所有参数中的最大值。 比如*/
console.log(Math.max(5,8)) //8
console.log(Math.max(5,7,9,3,1,6)) //9
/*问题:如何获取一个数组的最大值*/
/*遍历*/
/* 但是在很多情况下,我们需要找出数组中最大的元素。*/
/* var arr=[5,7,9,1] alert(Math.max(arr)) // 这样却是不行的。一定要这样写*/
/*传统方式写法*/
function getMax(arr){
var arrLen=arr.length;
for(var i=0,ret=arr[0];i<arrLen;i++){
ret=Math.max(ret,arr[i]);
}
return ret;
}
console.log(getMax([1,2,3,4,5,6,7]))
/*这样写麻烦而且低效。如果用 apply呢,看代码:*/
/*参数数组拆分法则*/
/*传递一个数组,其实会将其拆成很多个参数*/
/*适用场景:函数可以接受不限个数的参数*/
/*这样我们只能使用arguments来管理可变参数*/
/*比如max min push join split replace*/
/*在js中有很多这样支持可变参数的函数 大家还记得我们前面写的extend,也是支持可变参数*/
/*这也是为什么apply这么流行,这么重要的原因*/
/*广泛运用在框架,算法中*/
/*巧用apply虽然传递的是数组,但是使用的时候是把数组拆开的。。 等价于 return Math.max.call(null,1,2,3,4,5);*/
/*所以等价于:Math.max(5,7,9,3,1,6)*/
function getMax2(arr){
return Math.max.apply(null,arr);
/* return Math.max.call(null,1,2,3,4,5);*/
}
console.log(getMax2([1,2,3,4,5,6,7]))
03 练习 计算最小值
//计算最小值
/*参数数组拆分法则*/
/*传递一个数组,其实会将其拆成很多个参数,正好符合min的语法*/
var min=Math.min.apply(null,[3335,333,34343,34343,5657767,34455,445466,45454,343434,46466,56556,464646,464646,466,4646464])
alert('最小值:'+min)
04 练习 将一个数组的值合并到另一个数组
/*练习*/
/*将一个数组合并到另一个数组中*/
var arr1=new Array("1","2","3");
var arr2=new Array("4","5","6");
/*最终arr1["1","2","3","4","5","6"]*/
//传统写法
function PushArray(arr1,arr2){
var arrLen=arr2.length
for(var i=0;i<arrLen;i++){
arr1.push(arr2[i])
}
return arr1;
}
var result = PushArray(arr1,arr2);
console.log(result)
/*使用apply写法*/
/*Array.prototype.push 可以实现两个数组合并 同样push方法没有提供push一个数组,但是它提供了push(param1,param,…paramN) push(arr,2,3,3,3,3) 所以同样也可以通过apply来装换一下这个数组,即:*/
Array.prototype.push.apply(arr1,arr2);
/* Array.prototype.push.call(arr1,"4","5","6");*/
/* push(arr1,"4","5","6")*/
console.log(arr1)
console.log(arr2)
05 自定义的函数
/*有的说 这样的函数也不多,apply应该也就使用部分函数而已,。。。。大打错了。 下面看下高手的编程 工作中70%用不好apply 50%都不理解apply 后台开发人员也做部分前端 80%都不知道这个用法*/
function add(a, b) {
return a + b;
}
function add(){
var sum=0;
for(var i=0;i<arguments.length;i++){
sum+=arguments[i]
}
return sum;
}
var sum = add(1,2,3,4,5)
console.log(sum)
/*如何计算数组的和*/
var sum2 = add.apply(null,[1,2,3,4,5])
console.log(sum2)
06 总结:调用函数的5种方式
/****************************************************************************** 普通模式 *******************************************************************************/
// 声明一个函数,并调用
function func() {
console.log("Hello World");
}
func();
/****************************************************************************** 函数表达式 *******************************************************************************/
// 使用函数的Lambda表达式定义函数,然后调用
var func = function() {
console.log("你好,传智播客");
};
func();
//可以发现函数调用很简单,就是平时学习的一样.
//这里的关键是,在函数调用模式中,函数里的 this 关键字指全局对象,
//如果在浏览器中就是 window 对象. 例如:
var func = function() {
console.log(this);
};
func();
// 此时,会弹出对话框,打印出 [object Window]
/****************************************************************************** 方法调用模式 *******************************************************************************/
// 函数调用模式很简单,是最基本的调用方式.
// 但是同样的是函数,将其赋值给一个对象的成员以后,就不一样了.
// 将函数赋值给对象的成员后,那么这个就不在称为函数,而应该叫做方法.
// 定义一个函数
var func = function() {
alert("我是一个函数么?");
};
// 将其赋值给一个对象
var o = {};
o.fn = func; // 注意这里不要加圆括号
// 调用
o.fn();
// 此时,o.fn 则是方法,不是函数了.
// 实际上 fn 的方法体与 func 是一模一样的,但是这里有个微妙的不同. 看下面的代码:
// 接上面的代码
alert(o.fn === func);
// 打印结果是 true ,这个表明两个函数是一样的东西. 但是修改一下函数的代码:
// 修改函数体
var func = function() {
alert(this);
};
var o = {};
o.fn = func;
// 比较
alert(o.fn === func);
// 调用
func();
o.fn();
// 这里的运行结果是,两个函数是相同的,因此打印结果是 true.
// 但是由于两个函数的调用是不一样的,
// func的调用,打印的是 [object Window],而o.fn 的打印结果是[object Object].
// 这里便是函数调用与方法调用的区别.
// 函数调用中,this专指全局对象window,
// 而在方法中this专指当前对象. 即o.fn 中的this 指的就是对象o.
/****************************************************************************** 构造函数调用模式 *******************************************************************************/
// 同样是函数,在单纯的函数模式下,this表示window;
// 在对象方法模式下,this指的是当前对象.
// 除了这两种情况,JavaScript中函数还可以是构造器.
// 将函数作为构造器来使用的语法就是在函数调用前面加上一个new关键字. 如代码:
// 定义一个构造函数
var Person = function() {
this.name = "传智播客";
this.sayHello = function() {
alert("你好,这里是" + this.name);
};
};
// 调用构造器,创建对象
var p = new Person();
// 使用对象
p.sayHello();
// 上面的案例首先创建一个构造函数Person,然后使用构造函数创建对象p.
// 这里使用 new语法.然后使用对象调用sayHello()方法.
// 这个使用构造函数创建对象的案例比较简单. 从案例可以看到,此时 this指的是对象本身.
/****************************************************************************** apply call调用模式 *******************************************************************************/
//前面已经详细讲解了
/*Function对象定义函数*/
07 apply实现继承 - 继承的简单介绍
// apply实现继承
// 学生类本来不具备任何方法,
// 但是在 Person.apply(this,arguments) 后,
// 他就具备了 Person类的sayhello方法和 所有属性。
// 在 Print.apply(this,arguments) 后就自动得到了 show() 方法。
//人对象
function Person(name,age){
this.name=name //名字
this.age=age //年龄
this.sayhello=function(){
console.log("人对象方法")
}
}
Person.prototype={
buy:function(){
console.log('测试是否能够继承原型中的方法')
}
}
//输出打印对象
function Print(){ //显示类的属性
this.funcName="我是打印对象"
this.show=function(){
console.log ('打印对象方法')
}
}
//学生对象
function Student(name,age,grade,school){ //学生类
Person.apply(this,arguments)
Print.apply(this,arguments)
this.grade=grade //年级
this.school=school //学校
}
/*子类继承两个父类*/
/* 也就是通俗一点讲就是: 用student去执行Person这个类里面的内容, 在Person这个类里面存在this.name等之类的语句, 这样就将属性创建到了student对象里面*/
var lisi=new Student("tom",13,6,"清华小学")
//学生继承了人和打印对象,则拥有了人的属性和方法
/*打印父类*/
lisi.show()
/*人父类*/
lisi.sayhello()
/*无法继承原型对象中的方法*/
alert(lisi.buy())