探索JavaScript中的函数(下)

简介: 探索JavaScript中的函数(下)

探索js函数(下)

this

调用函数时 this 会隐式传递给函数指函数调用时的关联对象,也称之为函数的上下文。

全局环境下this就是 window 对象的引用

<body>
  <script>
    console.log(this===window);//true
  </script>
</body>

使用严格模式时在全局函数内thisundefined

<body>
  <script>
    var hd = '人人做后盾';
    let get = function(){
      "use strict"
      return this.hd;
    }
    console.log(get());//严格模式将产生错误 Cannot read property 'name' of undefined
  </script>
</body>

函数中的this

在对象中的方法(对象中声明的函数称为方法),要读取对象中的其他属性的时候可以用this来引用对象,来代替使用对象名。

当然 func: function(){}也可以简写为func(){}

let obj = {
  click: 199,
  func: function(){
    return this.click;
  }
}
console.log(obj.func());//119

而在对象方法的普通函数中,使用this,这时的对象的引用不是他的上层方法的对象,而是全局对象window

<body>
  <script>
    let obj = {
      click: 199,
      func: function(){
        function send(){
          return this;
        }
        return send();
      }
    }
    console.log(obj.func());//window
  </script>
</body>

要想改变this的指向,有多种途径。

改变this指针

es5的方式(不建议),声明一个变量引用this。

let obj = {
  string: 'str',
  arr: [199,188,177],
  func(){
    let that = this;
    return this.arr.map( function add(item){
      return `${that.string}-${item}`;
    });
  }
}
console.log(obj.func());//[ 'str-199', 'str-188', 'str-177' ]

在某些方法中,如map,有第二个参数,可以设置this的值。

let obj = {
  string: 'str',
  arr: [199,188,177],
  func(){
    return this.arr.map( function add(item){
      return `${this.string}-${item}`;
    },this);
  }
}
console.log(obj.func());//[ 'str-199', 'str-188', 'str-177' ]

也可以使用箭头函数=>

let obj = {
  string: 'str',
  arr: [199,188,177],
  func(){
    return this.arr.map( (item)=>`${this.string}-${item}`);
  }
}
console.log(obj.func());//[ 'str-199', 'str-188', 'str-177' ]

箭头函数与this

箭头函数没有this, 也可以理解为箭头函数中的this 会继承定义函数时的上下文,可以理解为和外层函数指向同一个 this。

  • 如果想使用函数定义时的上下文中的 this,那就使用箭头函数

下例中的匿名函数的执行环境为全局所以 this 指向 window

let obj = {
  click: 199,
  func: function(){
    function send(){
      return this.click;
    }
    return send();
  }
}
console.log(obj.func());//undefined

我们可以用箭头函数=>,箭头函数会让this指向上一层的对象的引用。

let obj = {
  click: 199,
  func(){
    let send = () => this.click;
    return send();
  }
}
console.log(obj.func());//199

事件中使用箭头函数结果不是我们想要的

  • 事件函数可理解为对象onclick设置值,所以函数声明时this为当前对象
  • 但使用箭头函数时this为声明函数上下文

下面体验使用普通事件函数时this指向元素对象

使用普通函数时this为当前 DOM 对象

<body>
  <button>周杰伦</button>
  <script>
    let dom = {
      star: 'zjl',
      func: function(){
        const btn = document.querySelector('button');
        btn.addEventListener('click', function(){
          console.log(this);
        })
      }
    }
    dom.func();//<button>周杰伦</button>
  </script>
</body>

使用箭头函数时,取到的是父级作用域的this。

<body>
  <button>周杰伦</button>
  <script>
    let dom = {
      star: 'zjl',
      func: function(){
        const btn = document.querySelector('button');
        btn.addEventListener('click', ()=>{
          console.log(this);
        })
      }
    }
    dom.func();//{star: 'zjl', func: ƒ}
  </script>
</body>

而在有时候,我们既需要取到当前DOM对象又需要取到父级作用域的this,可以这样做。

我们可以使用target属性。

<body>
  <button>周杰伦</button>
  <script>
    let dom = {
      star: 'zjl',
      func: function(){
        const btn = document.querySelector('button');
        btn.addEventListener('click', (event)=>{
          console.log(`${this.star}是${event.target.innerHTML}`);
        })
      }
    }
    dom.func();//zjl是周杰伦
  </script>
</body>

apply/call/bind

改变 this 指针,也可以理解为对象借用方法,就现像生活中向邻居借东西一样的事情。

原理分析

构造函数函数可以看做是一个工厂,使用new关键字来进行调用。

创建的是一个对象。具体可以看对象章节。

构造函数中的this默认是一个空对象,然后构造函数处理后把这个空对象变得有值。

function User(name){
  this.name = name;
}
let user = new User('张三');
console.log(user.name);//张三

可以改变构造函数中的空对象,即让构造函数 this 指向到另一个对象。

可以看到call能够改变this的指向。

function User(name){
  this.name = name;
  console.log(this);//{ age: 18, name: '张三' }
}
let student = {age: 18};
User.call(student, '张三');
console.log(student);//{ age: 18, name: '张三' }

apply/call

call 与 apply 用于显示的设置函数的上下文,两个方法作用一样都是将对象绑定到 this,只是在传递参数上有所不同。

  • apply 用数组传参
  • call 需要分别传参
  • 与 bind 不同 call/apply 会立即执行函数

语法使用介绍

  • call和apply方法的第一个的参数为要绑定到this的对象。
  • call传值的时候需要传递的参数用逗号隔开
  • apply传值的时候第二个参数为数组,需要传递的参数都放在数组里面,并且通过,隔开
function func(title, time){
  console.log(`${title}-${this.name}-${time}`); 
}
let zs = {
  name: '张三'
};
let ls = {
  name: '李四'
};

func.call(zs, 'zs', '3.1');//zs-张三-3.1
func.apply(ls, ['ls', '3.1']);//ls-李四-3.1

在这个例子中,使用了call或者apply来改变alt方法中this的指向。如果不使用这两个方法,那么this指向的将是window。

将event.target(dom对象)作为绑定到this的对象,这样就能让alt()函数的this指向 btn数组中的两个button节点对象。

<body>
  <button>zjl</button>
  <button>ljj</button>
  <script>
    let alt = function(){
      alert(this.innerHTML);
    }
    let btn = document.querySelectorAll('button');
    btn.forEach(item=>{
      item.addEventListener('click',event => {
        alt.call(event.target);
        // alt.apply(event.target); call和apply都可以
      });
    })
  </script>
</body>

apply也可以用来找出数组的最大值

let arr = [1,2,3,4,5];
console.log(Math.max(arr));//NaN
console.log(Math.max(...arr));//5
console.log(Math.max.apply(Math,arr));//5

其中,max不依赖于当前的上下文,所以任何东西都可以代替Math

let arr = [1,2,3,4,5];
console.log(Math.max.apply(null,arr));//5
console.log(Math.max.apply(undefined,arr));//5
console.log(Math.max.apply(123,arr));//5

实现构造函数属性继承

function Requre(){
  this.get = function(params={}){
    let option = Object.keys(params)//params是传入的对象,Object.keys方法将返回一个对象键的数组。
    .map(key => `${key}=${params[key]}`)
    .join('&');
    return `获取数据 API:www.bilibili.com/${this.url}?${option}`;
    //这里的this.url,分别指Article的和User的,在其余两个构造函数中利用apply方法,让Requre的this指向了Article和User
  }
}

function Article(){
  this.url = `artile/list`;
  Requre.apply(this);//在这里,Requre的this指向Article
  console.log(this);//Article { url: 'artile/list', get: [Function (anonymous)] }
}

function User(){
  this.url = `user/list`;
  Requre.apply(this);//在这里,Requre的this指向User
  console.log(this);//User { url: 'user/list', get: [Function (anonymous)] }

}

let artile = new Article()
let user = new User()

console.log(artile.get({
  title: 'ts',
  autor: 'xiaoming'
}));//获取数据 API:www.bilibili.com/artile/list?title=ts&autor=xiaoming

console.log(user.get({
  name: 'xiaoming',
  age: 18
}));//获取数据 API:www.bilibili.com/user/list?name=xiaoming&age=18

制作显示隐藏面板

<body>
  <dl>
      <dt>1</dt>
      <dd>隐藏1</dd>
      <dt>2</dt>
      <dd hidden="hidden">隐藏2</dd>
  </dl>
  <script>
    function hidden(i){
      let dd = document.querySelectorAll('dd');
      dd.forEach(elem => elem.setAttribute('hidden','hidden'));//全部设置hidden
      dd[i].removeAttribute('hidden');//移除当前索引的hidden
    }
    document.querySelectorAll('dt').forEach( (dt, i) => {
      dt.addEventListener('click',() => hidden.call(null, i))//传入index[0,1]
    });
  </script>
</body>

bind

bind()是将函数绑定到某个对象,比如 a.bind(hd) 可以理解为将 a 函数绑定到 hd 对象上即 hd.a()。

  • 与 call/apply 不同 bind 不会立即执行
  • bind 是复制函数形为会返回新函数

bind 是复制函数行为,与原函数的引用的内存空间不同。

let func = function(){};
let func1 = func;
console.log(func===func1);//true
console.log(func.bind()===func1);//false

bind的两种传参方式

let func = function(a,b){
  console.log(this.click+a+b);
};
let newFunc = func.bind({click: 100});
newFunc(11,12);//123
let newFunc1 = func.bind({click: 200}, 22,33);
newFunc1();//255

使用bind进行背景颜色的重复修改,当然,也可以使用箭头函数

<body>
  <script>
    function Color(elem){
      this.elem = elem
      this.color = ['black','yellow','red','green','brown'];
      this.run = function(){
        setInterval(function(){
          let pos = Math.floor(Math.random()*this.color.length);
          this.elem.style.background = this.color[pos];
        }.bind(this),1000)
      };
    }
    let change = new Color(document.body);
    change.run();
  </script>
</body>
相关文章
|
16天前
|
JavaScript 前端开发 Java
[JS]同事:这次就算了,下班回去赶紧补补内置函数,再犯肯定被主管骂
本文介绍了JavaScript中常用的函数和方法,包括通用函数、Global对象函数以及数组相关函数。详细列出了每个函数的参数、返回值及使用说明,并提供了示例代码。文章强调了函数的学习应结合源码和实践,适合JavaScript初学者和进阶开发者参考。
30 2
[JS]同事:这次就算了,下班回去赶紧补补内置函数,再犯肯定被主管骂
|
15天前
|
前端开发 JavaScript 开发者
除了 Generator 函数,还有哪些 JavaScript 异步编程解决方案?
【10月更文挑战第30天】开发者可以根据具体的项目情况选择合适的方式来处理异步操作,以实现高效、可读和易于维护的代码。
|
29天前
|
JavaScript 前端开发
JavaScript 函数语法
JavaScript 函数是使用 `function` 关键词定义的代码块,可在调用时执行特定任务。函数可以无参或带参,参数用于传递值并在函数内部使用。函数调用可在事件触发时进行,如用户点击按钮。JavaScript 对大小写敏感,函数名和关键词必须严格匹配。示例中展示了如何通过不同参数调用函数以生成不同的输出。
|
1月前
|
存储 JavaScript 前端开发
JS函数提升 变量提升
【10月更文挑战第6天】函数提升和变量提升是 JavaScript 语言的重要特性,但它们也可能带来一些困惑和潜在的问题。通过深入理解和掌握它们的原理和表现,开发者可以更好地编写和维护 JavaScript 代码,避免因不了解这些机制而导致的错误和不一致。同时,不断提高对执行上下文等相关概念的认识,将有助于提升对 JavaScript 语言的整体理解和运用能力。
|
2月前
|
JavaScript 前端开发 安全
JavaScript函数详解
JavaScript函数的详细解析,包括函数的定义和调用方式(如一般格式、匿名函数、构造函数、自调用函数、箭头函数和严格模式)、函数参数(arguments对象、可变参数、默认参数值)、闭包的概念和应用实例。
JavaScript函数详解
|
1月前
|
JavaScript 前端开发
js教程——函数
js教程——函数
36 4
|
1月前
|
存储 JavaScript 前端开发
js中函数、方法、对象的区别
js中函数、方法、对象的区别
16 2
|
1月前
|
JavaScript 前端开发 Java
【javaScript数组,函数】的基础知识点
【javaScript数组,函数】的基础知识点
23 5
|
1月前
|
JavaScript 前端开发
Node.js 函数
10月更文挑战第5天
23 3
|
1月前
|
前端开发 JavaScript
探索JavaScript函数基础
探索JavaScript函数基础
18 3