>

javascript中this指针探讨

- 编辑:正版管家婆马报彩图 -

javascript中this指针探讨

 javascript是一门类java语言有好些个跟java相临近的特征,但也仅是近似而已,真正使用中照旧有非常大的歧异。this指针常常让无数初学者抓狂,本身也曾为此疑忌不解,查找过很多材料,今日在此间总括一下,希望能支援后来者更加快驯服那只拦路虎。网络有看不尽上课this指针的小说在那之中不乏精品,以本身看来领悟this指针关键在于通晓javascript中等学校函授数的三种调用格局。那么怎样是调用?调用指的是跟在别的发生三个函数值的表明式之后选用"()",obj.f()这种方法成为调用,obj.f这种方法叫做访谈。

作业

 

this 相关主题素材

  • 难点1: apply、call 有啥样意义,什么差异

    • apply()和call()函数都可以钦赐this值和参数值的场地下调用有些函数。
    • call()和apply()的效果同样,分裂在于提须要原函数的参数的形式不同.
      • pply()函数只接受五个参数,提须求原函数的参数以数组或类数组对象的款式存在.
      • 而call()接收Infiniti个参数, 第一个参数及其背后的参数就是提需要原函数的参数。
  • 标题2: 以下代码输出什么?

var john = {
firstName: "John"
}
function func() {
alert(this.firstName + ": hi正版管家婆马报彩图,!")
管家婆马报图资料大全,}
john.sayHi = func
john.sayHi()//弹出john:hi!
//因为func赋给了john对象的sayHi属性,推行john.sayHi() 时 是在john对象上调用的,此时的内外文this是john了.

* 问题3: 下面代码输出什么,为什么?

    ```
func() //弹出window ,因为此时函数里的this归根结底是window调用的
function func() { 
  alert(this)
}
  • 主题素材4:上面代码输出什么

document.addEventListener('click', function(e){
console.log(this);//会打字与印刷document 因为这么些属于绑定事件类型,此时的this指的是事件源DOM对象
setTimeout(function(){
console.log(this);//setTimeout及setInterval里的this均指window
}, 200);
}, false);

* 问题5:下面代码输出什么,why

    ```
var john = { 
  firstName: "John" 
}
function func() { 
  alert( this.firstName )
}
func.call(john)//弹出John,因call(john)就是把函数执行的上下文及参数John传给func函数。此时firstName: "John",所以this.firstName肯定是“John”了。
  • 标题6: 以下代码有何样难题,如何修改

var module= {
bind: function(){
$btn.on('click', function(){
console.log(this) //this指的是$btn源DOM对象
this.showMsg();//此处应该改为module.showMsg(),不改的话它会在$btn源DOM对象找showMsg().会导致this.showMsg is not a function 报错
})
},

showMsg: function(){
console.log('饥人谷');
}
}

##原型链相关问题

* 问题7:有如下代码,解释Person、 prototype、__proto__、p、constructor之间的关联。

    ```
function Person(name){
    this.name = name;
}
Person.prototype.sayName = function(){
    console.log('My name is :' + this.name);
}
var p = new Person("若愚")
p.sayName();
//p是Person的实例,所以继承Person原型链上的属性和方法。
//关联:
    Person.prototype.constructor == Person,
    Person.prototype == p.__proto__,
    p.__proto__.constructor == Person,
    Person.prototype.__proto__ == Object.prototype,
    Object.prototype.constructor == Object,
    Object.prototype.__proto__ == null
  • 主题素材8: 上例中,对目的 p能够这么调用 p.toString()。toString是哪儿来的? 画出原型图?并解释如何是原型链。
    答:构造函数的原型自带一个指南针指向object的原型,由此toString是从object的原型里持续而来。

    管家婆赢钱一句话 1

    Paste_Image.png

原型链:JS在创建对象(不论是普通对象还是函数对象)的时候,都有一个叫做**proto**的内置属性,用于指向创建它的函数对象的原型对象prototype。在访问一个对象属性的时候,如果对象本身没有找到这个属性,就会沿着原型链一层一层的寻找。
  • 标题9:对String做扩张,达成如下格局赢得字符串中频率最高的字符

var str = 'ahbbccdeddddfg';
var ch = str.getMostOften();
console.log(ch); //d , 因为d 出现了5次

String.prototype.getMostOften = function(){
var obj = {};
for(var i=0,k;i<this.length;i++){
k = this[i];
if(obj[k]){
obj[k]++
}else{
obj[k] = 1
}
}

var max = 0,key;
for(var k in obj){
    if(obj[k]>max){
       max = obj[k];
       key = k;
    }
 }

return key;

}

* 问题10: instanceOf有什么作用?内部逻辑是如何实现的? 
答:
作用是确认instanceOf前面的对象是否是后面的对象的实例;![Paste_Image.png](http://upload-images.jianshu.io/upload_images/2858982-ad8795604b45cd13.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)



##继承相关问题
* 问题11:继承有什么作用?
答:
继承使不同的实例可以共享构造函数的原型对象的属性和方法,以提高代码的复用性;

* 问题12: 下面两种写法有什么区别?

    ```
//方法1
function People(name, sex){
    this.name = name;
    this.sex = sex;
    this.printName = function(){
        console.log(this.name);
    }
}
var p1 = new People('饥人谷', 2)
//方法2
function Person(name, sex){
    this.name = name;
    this.sex = sex;
}
Person.prototype.printName = function(){
    console.log(this.name);
}
var p1 = new Person('若愚', 27);
//printName:一个写在构造函数内部的实例对象上。另一个写在构建函数的prototype对象上。
//前者在每生成一个实例之后实例的printName就新占用内存。
//后者每生成一个实例后会共享构造函数prototype对象上的printName方法,以达到节省内存的效果;
  • 难题13: Object.create 有啥效果?兼容性怎么样?
    答:

    • Object.create()是ES5建议的一个新的艺术,它可以流传三个指标作为该方法重返的靶子的原型对象;

    • 包容性:各大浏览器的风行版本(包含IE9)都非常了那些措施。倘诺碰着老式浏览器,能够用上面包车型大巴代码包容:

if(!Object.create){
Object.create = function(obj){
function F(){};
F.prototype = obj;
return new F();
}
}

* 问题14: hasOwnProperty有什么作用? 如何使用?
答:
对象实例的hasOwnProperty方法返回一个布尔值,用于判断某个属性定义在对象自身,还是定义在原型链上。

管家婆赢钱一句话,var people = {
name:'teren'
}
people.hasOwnProperty('name')//true
people.hasOwnProperty('toString')//false
Object.getPrototypeOf(people).hasOwnProperty('toString')//true

* 问题15:如下代码中call的作用是什么?

    ```
function Person(name, sex){
    this.name = name;
    this.sex = sex;
}
function Male(name, sex, age){
    Person.call(this, name, sex);    //这里的 call 有什么作用
    ////构造函数Person在构造函数Male作用域下执行,以实现构造函数的继承;
    this.age = age;
}
  • 难题16: 补全代码,落成持续

function Person(name, sex){
this.name = name;
this.sex = sex;
}
Person.prototype.getName = function(){
return this.name
};
function Male(name, sex, age){
Person.call(this,name,sex);
this.age = age;
}
Male.prototype = Object.create(Person.prototype);
Male.prototype.constructor = Male;
Male.prototype.getAge = function(){
return this.age
};
Male.prototype.getAge = function(){
console.log(this.name)
};
var ruoyu = new Male('若愚', '男', 27);
ruoyu.printName();

  一、方法调用情势:

 

  在该调用格局中等高校函授数作为贰个指标的办法被调用:obj.fun()。当函数以此种格局被调用时this指针绑定到调用该办法的目的上即obj。

 

复制代码

 1 var myObj = {

 2   value: 0,

 3   increase: function(){

 4     this.value++;

 5     console.log(this.value);

 6   }

 7 };

 8 // this绑定到myObj对象上

 9 myObj.increase(); // 1

10 

11 myObj2 = {

12   value: 10

13 };

14 myObj2.increase = myObj.increase;// myObj2与myObj的increase指向同一函数引用地址

15 // this绑定到myObj2对象上

16 myObj2.increase(); // 11

复制代码

  所以在将三个html元素的某一平地风波绑定某一函数时,若函数中运用this指针,则this指针会被绑定到该因素上。

 

复制代码

1 var ele1 = document.getElementById('id');

2 ele1.addEventListener('click', myObj.increase, false);

3 // 该绑定也正是

4 ele1.onclick = myObj.increase;

5 // 事件触发时即一对一于调用click方法

6 ele1.click(); // 与上文中myObj2.increase三个道理,若ele第11中学从未value属性则会报错

复制代码

 

 

  二、函数调用方式:

 

  当函数没有当做方法调用即未有被叁个指标通过点语法,那时它被当做三个函数来调用。以此方式调用函数时,this被绑定到全局对象。

 

复制代码

 1 var value = -10;

 2 var myObj = {

 3   value: 0,

 4   increase: function(){

 5     this.value++;

 6     console.log(this.value);

 7   }

 8 };

 9 // this绑定到myObj对象上

10 myObj.increase(); // 1

11 

12 var gInc = myObj.increase;

13 gInc(); // -9 this绑定到window对象上

复制代码

  所以在措施中选取当中等学校函授数时要特别注意,下例中other函数中的this并未有绑定到myObj对象上

 

复制代码

var value = -10;

var myObj = {

  value: 0,

  increase: function(){

    this.value++;

    console.log(this.value);

    var other = function(){

      this.value++;

      console.log(this.value); 

    };

    other();// -9, 这时other中的this绑定到window对象上

  }

};

// this绑定到myObj对象上

myObj.increase(); // 1

 

var gInc = myObj.increase;

gInc(); // -8

///////////////

//1

//-9

//-8

//-7

复制代码

  幸运的是我们得以接纳以下格局来在other中访问myObj对象:

 

复制代码

 1 var myObj = {

 2   value: 0,

 3   increase: function(){

 4     this.value++;

 5     console.log(this.value);

 6     var that = this;

 7     var other = function(){

 8       that.value++;

 9       console.log(that.value); 

10     };

11     other();// -9, 这时other中的this绑定到window对象上

12   }

13 };

14 // this绑定到myObj对象上

15 myObj.increase(); // 1

16 //////////////

17 //1

18 //2

复制代码

  作为浏览器兼容性中非常重点的一条:element.attachEvent绑定事件措施,当该事件触发时this指针并未有绑定到element对象上,而是绑定到了window对象上,原因在于IE中事件触发时,响应函数是以一个独立函数即函数调用方式来调用的

 

 

 

  三、构造器形式调用:

 

  假设在二个函数前面加上new调用则改为构造器情势调用。使用new运算符,会发生四个总是到该函数prototype的新对象,this指针则被绑定到那个新目的上。

 

复制代码

1 var P = function(n){

2   this.name = n;

3 }

4 P.prototype.getName = function(){

5   console.log(this.name);

6 }

7 var p = new P('woodtree'); // 那时P中的this对象呗绑定p指向的指标援用上

8 p.getName();// woodtree

复制代码

  同期new运算符还有恐怕会退换函数的重临值。以函数调用格局调用P即P()重返undefined,而透过new运算符则重返贰个新目的。new运算符类似于以下Function.prototype.create函数:

 

复制代码

 1 var P = function(n){

 2   this.name = n;

 3 }

 4 P.prototype.getName = function(){

 5   console.log(this.name);

 6 }

 7 var p = new P('woodtree');

 8 p.getName();

 9 

10 Object.prototype.create = Object.create || function(proto){

11   var F = function(){};

12   F.prototype = proto;

13   return new F();

14 }

15 

16 Function.prototype.create = function(){

17   var that = object.create(this.prototype);

18   var obj = this.apply(that, arguments);

19 

20   return obj || that;

21 }

22 var p2 = P.create('hello new');

23 p2.getName(); // hello new

复制代码

 

 

  四、apply、call格局调用:

 

  javascript中等校园函授数对象继承自Object亦能够享有方法。call跟apply允许大家选择this的绑定对象。那多个方法的区分在于apply第3个参数必得是一个数组恐怕类数组对象即具备length属性(arguments、NodeList、HTMLElementCollection等),而call除了第二个参数为要绑定this的对象外,后可跟无数的参数,参数之间用逗号间隔。

 

复制代码

 1 var P = function(n){

 2   this.name = n;

 3 }

 4 P.prototype.getNameAndAge = function(age){

 5   console.log(this.name + age);

 6 }

 7 

 8 P.prototype.getNameAndAge.call({

 9   name: 'catboat'

10 }, 99);

11 P.prototype.getNameAndAge.apply({

12   name: 'lanuch'

13 }, [99]);

复制代码

 

 

  通过选取apply与call方法我们能够自动实现ES5中的bind函数

 

复制代码

 1 var P = function(n){

 2   this.name = n;

 3 }

 4 P.prototype.getNameAndAge = function(age, age2){

 5   console.log(this.name + age + age2);

 6 }

 7 

 8 P.prototype.getNameAndAge.call({

 9   name: 'catboat'

10 }, 99);

11 P.prototype.getNameAndAge.apply({

12   name: 'lanuch'

13 }, [99]);

14 

15 Function.prototype.bindContext = function(that){

16   var _method = this,

17   slice = Array.prototype.slice,

18   args = slice.call(arguments, 1);

19 

20   return function(){

21     _method.apply(that, Array.prototype.concat.apply(args, arguments));

22   }

23 };

24 

25 var f1 = P.prototype.getNameAndAge.bindContext({

26   name: 'barque'

27 }, 88);

28 f1(9);

复制代码

  相同大家也能够解决IE中事件触发时,this指针难点(以下代码来自《Javascript框架设计》):

 

1 var addEvent = document.addEventListener ? function(el, type, fn, capture){

2   return el.addEventListener(type, fn, capture);

3 } : function(el, type, fn){

4   el.attachEvent('on' + type, fn.bindContext(el, event));

5 }

 

...

本文由web前端发布,转载请注明来源:javascript中this指针探讨