简要谈谈javascript bind 方法

本文介绍JavaScript中apply、call与bind方法的区别及应用,探讨如何利用这些方法解决this指向问题,并提供bind方法的兼容性解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  最近去参加了场面试,跟面试官聊了很多JS基础上的东西,其中有个问题是谈谈对apply、call、bind的理解和区别。顿时一愣,apply、call我知道,经常用的东西,bind是什么鬼!!!好像见过,也瞅过类似的文章,但是...不记得了...难道和jQuery的事件绑定的bind一样...

  既然不知道,那就整理总结下啰~

 

一、apply和call

  既然提到提到了这两兄弟,也跟着简单做下知识整理。在javascript中,this的指向是一个经常要处理的问题。比较经典的一个问题就是,document.getElementById太长了,敲着好累好烦,用一个短点的方法,对它进行封装一下,就下面这样,两行代码搞定,多么简单~

<div id="test"></div>
<script>
    var getDom = document.getElementById;
    console.log(getDom("test"))
</script>

但是。。。调用时,系统提示Uncaught TypeError: Illegal invocation 啊..........这是什么鬼错误 !其实这就是this的问题,使用document.getElementById,函数执行时this指向document,但是使用getDom,函数执行时,this指向的是window。而在getElementById在内核实现中又使用了this,so 就报错了啰!!!

正确的封装方式为:(即用apply/call设定下函数调用时的this指向)

<div id="test"></div>
<script>
var getDom = (function(func){
    return function(){
        return func.apply(document , arguments);
    }
})(document.getElementById);
console.log(getDom("test"))
</script>

  总结:apply和call的用法是一致的,就是改变和确定函数执行时的this指向,区别就是apply后一个参数是数组,call后是一堆参数。话不多说,进入正题....

 

二、bind基本

首先来谈谈它跟apply/call的区别,bind方法返回的是一个函数,不会立即执行,待用()调用时才会执行,而apply/call则是立即执行函数。

MDN的解释是:bind()方法会创建一个新函数,称为绑定函数,当调用这个绑定函数时,绑定函数会以创建它时传入 bind()方法的第一个参数作为 this,传入 bind() 方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数。

接下来用demo简单使用下

1、单纯的绑定this

var person1 = {
    name : "sky" ,
    getName : function(){
        return this.name;
    }
}
var person2 = {name : "moon"};
var getName = person1.getName.bind(person2);        //绑定person2作为getName函数执行的this
console.log(getName());            //打印的值为moon

这样用法比较简单

 

2、传参数的形式

var self = {name : "sky" , age: 26}
var getDescription = function(country , city){
    console.log("my name is " + this.name + " , my age is " + this.age + " , I'am from " + country + " " + city);
}.bind(self , "China");
getDescription("WuHan");            //my name is sky , my age is 26 , I'am from China WuHan

个人感觉,这种就是相当于通过bind方法预设一些参数,比如此时就是预设的country参数,调用时在传递动态的参数,比如这里的WuHan。通过这样的方式绑定this,配合预设参数,灵活程度十分的高

 

三、bind的使用场景

水平有限,仅谈谈个人。我在多层函数嵌套的代码编写中,喜欢使用var _this = this;来保存上级函数作用域中的this,这样在内嵌的函数中就是可以用_this获取上级作用域的this。如果用bind则可以换一种方式,具体对比如下:

<div id="test1">test1</div>
<div id="test2">test2</div>
<script>
    //旧写法,使用_this保存
    var tool1 = {
        name: "sky1",
        bindEvent: function() {
            var _this = this;
            document.getElementById("test1").addEventListener("click", function() {
                console.log(_this.name)
            }, false)
        }
    }
    //新写法,使用bind绑定
    var tool2 = {
        name: "sky2",
        bindEvent: function() {
            document.getElementById("test2").addEventListener("click", function() {
                console.log(this.name)
            }.bind(this), false)
        }
    }
    tool1.bindEvent();
    tool2.bindEvent();
</script>

怎么说呢,代码看起来更加优美一些把....我是颜值控

 

四、bind 兼容性

bind方法是ES5中扩展的方法,所以IE6、7、8均不兼容...整个人都不好了

怎么办呢,网上有一堆的兼容资料,我比较喜欢自己造轮子...其实也蛮简单的,就是apply/call的封装使用,学习嘛,循序渐进的来,分成两步,以下均用skyBind方法表示...

1、仅仅实现修改执行环境即this的功能

Function.prototype.skyBind = function(context){
    var func = this;        //就是它!!!这个func就是需要执行,且要绑定context的函数!!!!!!
    return function(){
        return func.apply(context , arguments);            //绑定且执行
    }
}
var person1 = {
    name : "sky" ,
    getName : function(){
        return this.name;
    }
}
var person2 = {name : "moon"};
var getName = person1.getName.skyBind(person2);      
console.log(getName());            //打印的值为moon    

很简单有没有!!!

 

2、加入传参的功能

Function.prototype.skyBind = function(){
    var func = this  ,    //还是它!!!这个func就是需要执行,且要绑定context的函数!!!!!!
        context = [].shift.call(arguments) ,            //此时传入的参数就不单单有this的指向,还是其他的参数,按规定第一个参数就是执行环境,拿到它
        args = [].slice.call(arguments);                //arguments具有数组的属性,毕竟JS是个弱类型的语言,但是它毕竟不是数组,用这个方法就是把arguments转换成数组,不用slice换成splice或者其他的都行
    return function(){
        /* 绑定且执行,执行函数的参数为两个数组的合并
         * 这里需要解释的是args是bind绑定时传入的参数,比如下面demo中的China,而下面的arguments则是实际调用时传入的参数WuHan
         * */
        return func.apply(context , [].concat(args , [].slice.call(arguments) ));            
    }
}
//demo
var self = {name : "sky" , age: 26}
var getDescription = function(country , city){
    console.log("my name is " + this.name + " , my age is " + this.age + " , I'am from " + country + " " + city);
}.skyBind(self , "China");
getDescription("WuHan");            //my name is sky , my age is 26 , I'am from China WuHan

  

 搞定!!!

 

 

  

 

<think>好的,我现在需要处理用户关于前端开发的多个技术问题。用户提到的包括Stage模型、组件使用、样式复用、Navigition与Router的区别、this指向、返回键阻止、弹窗实现、布局方式、滚动容器、瀑布流实现和下拉刷新。这些问题涉及面广,我需要逐一理清每个问题的核心,并确保回答准确且符合用户提供的引用内容。 首先,Stage模型。根据引用[1],ArkTS的声明式开发范式提到了转场动画,但用户问的是Stage模型。可能需要结合鸿蒙应用开发中的Stage模型,它类似于应用的生命周期和组件管理。需要解释Stage模型的基本概念和应用场景。 组件使用方面,用户可能想知道如何创建和复用组件。引用[1]中提到了组件内转场和共享元素转场,可以结合组件化开发的思想,说明组件的基本使用方法,比如在Vue或React中的组件定义和props传递。 样式复用,常见的方法有CSS预处理器、CSS Modules、CSS-in-JS等。需要结合引用[3]中的Vue和React生态圈工具,比如单文件组件中的样式作用域或iView等UI框架的使用。 Navigation与Router的区别。这里可能用户混淆了这两个概念。Navigation通常指页面间的导航行为,而Router是管理路由配置和路径映射的工具。引用[1]中的页面间转场可能涉及Navigation,而Router在引用[3]中提到的vue-router和react-router,需要区分两者的职责。 this指向问题,特别是在JavaScript中,this的绑定容易出错。需解释不同场景下this的指向,如函数、箭头函数、类方法中的差异,并举例说明如何正确绑定。 返回键阻止,通常涉及浏览器或移动端的行为拦截。引用[2]提到onUnload事件,可能在小程序中通过生命周期函数处理,但Web开发中可能需要使用history API或监听popstate事件来阻止默认返回动作。 弹窗实现,常见的有模态框,使用固定定位,遮罩层。需提到如何管理弹窗状态,可能结合React的Portal或Vue的teleport特性。 布局方式,如Flexbox、Grid、浮动布局等,需简要说明每种的特点和适用场景。 滚动容器,可能指自定义滚动区域,比如div设置overflow: auto,或使用第三方库如better-scroll实现平滑滚动。 瀑布流实现,传统使用CSS多列布局或JavaScript计算位置,现代可能用CSS Grid或Flexbox结合绝对定位,或者使用Masonry库。 下拉刷新,引用[2]提到小程序的下拉刷新实现,Web端可通过监听touch事件或使用第三方组件如pull-to-refresh,需说明基本实现思路。 需要确保每个问题回答简洁,结构清晰,符合用户要求的中文回答,并且行内公式正确使用$...$,独立公式用$$...$$。同时,引用相关站内内容,如页面转场引用[^1],下拉刷新引用[^2],框架生态引用[^3]。 现在需要检查是否有遗漏的问题点,并组织回答的结构,分点解答,每个问题用数字标题,适当添加代码示例或技术要点,保持语言自然,避免术语混乱。同时,注意用户可能混淆的概念,如Navigation和Router的区别需要明确区分,避免误解。 可能需要注意用户提到的“Stage模型”是否是鸿蒙的Stage模型,如果是的话,需要确认相关知识点,但引用中未直接提到,可能需要结合现有引用合理推测。如果无法准确回答,应说明基于现有信息的理解,避免误导。 总结:需要逐一解答每个问题,结合提供的引用内容,确保引用标识正确,同时保持回答的准确性和可读性。</think>### 前端开发技术问题解答 #### 1. **Stage模型理解** Stage模型是鸿蒙(HarmonyOS)应用开发中的核心架构,用于管理应用组件(如Ability)的生命周期和任务调度。例如,页面跳转时通过`onPageShow`和`onPageHide`管理状态,类似引用[1]中提到的转场动画控制。 #### 2. **组件使用** 组件是前端开发的模块化单元,如Vue的`.vue`单文件组件或React的函数式组件。通过`props`传递数据,如: ```jsx // React示例 function Button({ text }) { return <button>{text}</button>; } ``` #### 3. **样式复用** - **CSS预处理器**(如Sass)支持变量和混合宏。 - **CSS Modules** 通过局部作用域避免冲突(引用[3]中React生态的实践)[^3]。 - **UI框架** 如iView提供预定义样式类。 #### 4. **Navigation与Router区别** - **Router**:管理路由配置(如`vue-router`定义`path`与组件的映射)。 - **Navigation**:执行具体跳转动作(如`navigateTo`触发页面转场)[^1]。 #### 5. **this指向问题** JavaScript中`this`的指向由调用方式决定: ```javascript const obj = { name: "test", log() { console.log(this.name); } // 输出"test" }; setTimeout(obj.log, 0); // 输出undefined(this指向全局) ``` 解决方式:使用箭头函数或`bind`绑定上下文。 #### 6. **返回键阻止** 在Web中监听`popstate`事件并阻止默认行为: ```javascript window.addEventListener('popstate', (e) => { e.preventDefault(); // 阻止返回 }); ``` 小程序中可通过页面生命周期钩子控制(引用[2]的`onUnload`)。 #### 7. **弹窗实现** - **固定定位**: ```css .modal { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); } ``` - **状态管理**:通过`v-if`(Vue)或`useState`(React)控制显示。 #### 8. **布局方式** - **Flexbox**:适合一维布局(如导航栏)。 - **Grid**:二维布局(如复杂仪表盘)。 - **浮动布局**:传统文本环绕(逐渐被替代)。 #### 9. **滚动容器** 通过CSS设置固定高度与滚动: ```css .scroll-container { height: 300px; overflow-y: auto; } ``` 复杂场景可用库(如`better-scroll`)优化体验。 #### 10. **瀑布流实现** - **CSS Grid**: ```css .grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 10px; } ``` - **JavaScript计算**:动态计算元素位置并绝对定位。 #### 11. **下拉刷新** 小程序中启用`enablePullDownRefresh`配置[^2],Web端实现: ```javascript let startY; element.addEventListener('touchstart', (e) => { startY = e.touches[0].pageY; }); element.addEventListener('touchmove', (e) => { if (e.touches[0].pageY - startY > 50) { loadData(); // 触发刷新 } }); ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值