一.方法劫持
- 通过call apply bind实现方法劫持(我的理解就是通过这三个代码将一个函数的调用者强行指向一个对象)
代码说话:
call:
var obj1={name:"jack",age:18,say:function (arg1,arg2) {
console.log(arg1,arg2)
console.log(this.name,this.age)
}}
var obj2={name:"xxxxx",age:"xxxx"}
obj1.say()
obj2.xxx=obj1.say
obj2.xxx()
obj1.say.call(obj2,100,200)//这里如果是obj1.say(),方法的调用者则是obj1,而使用了call的方法劫持后,将say的方法调用对象指向obj2,obj2(指向的对象);100,200(传入的实参)
//所以打印结果为100,200
xxxxx,xxxx
function fn (arg1) {
console.log(this)
console.log(arg1)
}
fn.call(obj1,"hello")
apply:
fn.apply(obj2,[100])
obj1.say.apply(obj2,[100,200])//apply用法()里的obj2也代表指向的调用对象,[]里的100,200是传入的实参,使用apply方法劫持的时候传入的实参要放入一个数组里
bind
var obj1={name:"jack"};
var obj2={name:'karen',say:function() {
console.log(this)
}.bind(obj1)}//在设计方法的时候就给this指定对象,后续修改无效bind(obj1)就为这个方法的调用者指向obj1
obj2.say()
obj2.say.call(window)//修改无效
obj2.say.apply(window);//修改无效
((function fn () {
console.log(this)
}).bind(obj1))()//这种写法是错误的,bind不能和一个直接声明的函数绑定,只能给方法绑定,哪怕这里给fn外加了一个()看起来像是通过()调用fn这个方法,也是不对的
fn()//无效,还是window
obj1.say1=function() {
console.log(this)
}
obj1.say1.bind(obj2)//无效绑定
obj1.say1()
var str="hello"
var re=str.charAt(1)
console.log(re)
总结一下:
call apply 函数调用的时候为函数内部指定this对象
bind 方法在设计的时候就为其指定this对象,以后都不能被修改 ,声明的函数不能直接绑定 只能方法直接绑定(声明式的不能直接绑定,定义式的可以直接绑定 )
二.练习题部分
1
var a, b;
(function() {
//var a
alert(a);//局部变量a声明提前声明了a,所以undefined
alert(b);//外部声明了b,所以undefined
var a = b = 3;//a在局部里有声明所以存在局部变量里,外部读取不到,b局部未声明所以赋值给了全局变量b
alert(a);//3
alert(b);//3
})();//后面的()用来调用这个function,
alert(a);//undefinded
alert(b);//3
2
var obj = {};
obj.log = console.log; //obj.log=window.console.log
obj.log.call(console, this);//用call让obj.log指向了console,而console为window.console,所以this代指window
===>window.console.log(this)
===>console.log(this)
obj.log.call(window.console,1000)//相当于这一行,把this换成1000,所以打印1000
3
var msg = 'hello';
for (var i = 0; i < 10; i++) {
var msg = 'hello' + i * 2 + i; //hello189
}
alert(msg);//因为msg没有被存起来,所以每执行一次循环都被重新赋值一次,所以打印最后一次的数据
4
var x = 10;
function cals(myNum) {
return x + myNum;//x在全局变量里有值,考察点:函数内部可以访问函数外部
}
var re=cals(7)
console.log(re)//17
5
function Parent() {
this.a = 1;
this.b = [1, 2, this.a];
this.c = {
demo: 5
};
this.show = function() {
console.log(this.a, this.b, this.c.demo);
}
}
function Child() {
this.a = 2;
this.change = function() {
this.b.push(this.a);
this.a = this.b.length;
this.c.demo = this.a++;
}
}
Child.prototype = new Parent();
//① Child.prototype = {a:1,b:[1,2,1,11,12],c:{demo:5},show:function(){console.log(this.a, this.b, this.c.demo);}}
var parent = new Parent();
//② var parent={a:1,b:[1,2,1],c:{demo:5},show:function(){console.log(this.a, this.b, this.c.demo);}}
var child1 = new Child();
//var child1 = {__proto__:上1,a:5,change:function(){this.b.push(this.a); this.a = this.b.length;this.c.demo = this.a++;}}
var child2 = new Child();
//var child2 = {__proto__:上1,a:6,change:function(){this.b.push(this.a); this.a = this.b.length;this.c.demo = this.a++;}}
child1.a = 11;
child2.a = 12;
parent.show(); //1 [1,2,1] 5
child1.show(); //11 [1,2,1]5
child2.show();//12 [1,2,1] 5
child1.change();
child2.change();
parent.show(); //1 [1,2,1] 5
child1.show(); //5 [1,2,1,11,12] 5
child2.show(); //6 [1,2,1,11,12] 5
做题思路:这道题很长看起来比较吓人,其实并不难,考察的都是基础知识点,其中有个新知识
this.a = 1;
this.b = [1, 2, this.a]; 这里this.a是直接把调用者a的值写在b里,后续的调用者改变时[]里的this.a一直为1不变.
这个地方没学过,但是可以通过写一个小的代码段去实验一下,得到结论再继续做题;
因为题整体很长所以我再读完每一步后就会把给每个对象赋的值都用注释写出来,后续改变的时候再去注释里改,可以很好的理清思路避免混乱.
6
function employee(name, job, born) {
this.name = name;
this.job = job;
this.born = born;
}
var bill = new employee("Bill Gates", "Engineer", 1985);
//bill={__proto__:{salary:null},name:"Bill Gates",job:"Engineer",born:1985,salary:20000}
employee.prototype.salary = null;//考察点当使用xx.prototype.xx的时候,可以给原型对象的prototype属性上添加一个xx属性,后面可以访问的到
bill.salary = 20000;
document.write(bill.salary); //20000
console.log(bill.__proto__ == employee.prototype)
console.log(bill.__proto__ === employee.prototype)
7
//所有的函数都是由Function创建出来的 所有函数都能使用a属性==>所有函数的原型对象上有a属性
Function.prototype.a = 'a';
//所有的对象的原型对象有b属性
Object.prototype.b = 'b';
//创建了一个函数对象
function Person() {};
// Person.prototype 系统为每一个函数提供了一个prototype属性,内置的空对象{}
var p = new Person();
console.log('p.a: ' + p.a);//undefined,p是一个对象访问不到Function.prototype
console.log('p.b: ' + p.b);//b,p是一个对象所以访问的到Object.prototype
console.log('p.b: ' + Person.b);b,函数也是一种对象,所以同上
这里考察的知识点时原型链,原型链上的原型对象不能够跨链访问,而对象和函数的原型对象在一层层往上的时候总会在Object.prototype交汇,因为函数也是一种对象,所以Object.prototype上的对象,两者都可以访问.