你不知道的js学习日记随笔

这两天本小白在看一本书,书名《你不知道的js》听着很叼有木有。其实这已经是本人第二次看这本书,这本书全书不足200页,但是却真的是值得一读再读的好书,再次强烈推荐下,同推的还有《js忍者秘籍》是jQuery作者写的,也很好,需要一定的基础才能看!当然也不需要太深的基础否则本小白怎么看呵呵哒。闲话少述下面放一段书上的代码,就是这段代码让我今天有不小的收获(其实这个也是作者从mdn上copy的,所以说看文档真的重要!!!重要的话打三个感叹号!!!)

首先我相信大家如果一些书的话对js中的this绑定应该还算熟悉吧有四种绑定,默认,隐式(作为方法调用),显式(call,apply),new(new调用),那大家有想过这些绑定的优先问题吗?比如同时出现new绑定和显式绑定,到底函数中的this绑定到哪呢?(因为new和call或者apply是无法直接一起使用的,所以无法通过new foo.call(context)来直接测试,但是咱们可以使用bind来看看)相信大多数人和我一样根本没有想过这个问题,今天大家不妨跟着我来看看这个问题的答案。

if (!Function.prototype.bind) {
    Function.prototype.bind = function(context) {
        if (typeof  this !== ‘function‘) {
            throw new TypeError(‘只有函数才可以调用bind函数‘);
        }

        var args = Array.prototype.slice.call(arguments, 1),
            toBind = this,
            NOP = function(){},
            bound = function () {
                return toBind.apply(
                (this instanceof NOP && context ? this : context), args.concat(Array.prototype.slice.call(arguments)));
            };
            NOP.prototype = toBind.prototype;
            bound.prototype = new NOP;
            return bound;
    }
}

上面的代码是对ES5新增内置函数bind的实现,出现在讲解this绑定优先级的一章。如果大家和我水平相近应该对上面代码还算是hold住,比较迷茫的就应该是

this instanceof NOP && context ? this : context,这句代码的意义是什么呢?其实,这段代码就是检验你对这个bind函数返回的函数的调用方式,如果你是直接调用或者你把它作为一个对象方法调用,这两种情况都是返回 toBind.apply(context, arguments),这也是大家所期望的对吧?毕竟咱们调用啦bind给函数绑定了一个指定的上下文。可是大家思考下,如果你是把返回的这个bound(当然我这里这样说都是偷懒的说法,大家一般都要先把fn.bind(context)的返回值赋值到一个变量,我为了方便就直接说上面代码中的bound啦,但是注意如果直接在全局调用bound肯定是会出问题的啦!),用做构造函数调用呢?也就是var obj = new bound()?那各位看官你们说,这个函数中的this到底绑定的是什么呢?为了解决这个问题咱们先快速回顾下用new操作符调用一个函数时,会发生什么?

1.创建一个空对象

2.设置它的[[prototype]]属性,将其连接到函数的prototype对象上(也就是委托)

3将这个新创建的对象绑定到函数内部的this上(然后就是执行这个函数的代码)

4如果函数不返回一个对象(注意这个对象包括函数啊,数组啊这些),就返回this

所以说现在如果用new操作符调用bound的话,首先咱们要创建一个空对象,然后设置原型链,好现在咱们看bound函数的内部,那句this instanceof NOP && context ? this : context在这个情况下得到的值便是context啦因为此时this instanceof NOP为true(写到这里作者我要吐槽下线,其实写这个文章的时候我才发现那本书的作者已经有点跑题了,他本意用这段代码是要探讨到底new绑定和call或者apply绑定到底哪个优先级高,可是他其实在这里偷换了概念,这里先提一下,怎么个换概念咱们后面说,这段代码其实本来给我最大的帮助也不是什么this优先级的问题,而是js最根本的原型问题。我本人觉得其实this这个并没有太大意义)。我在看到this instanceof NOP的时候有点发懵,为什么这个instanceof返回true呢?我开始想了下,以为是因为我是建立了一个空对象,而NOP是个空函数,所以就为true?现在看当时的想法真是哔了整个动物园了,这种想法简直是一点都不理解js和核心原型这一概念的最佳体现啊。现在咱们来看看到底是怎么个情况(当然鉴于本人还是小白说不定也是错的,大家一起讨论,请高手指正!)。

先提个问题instanceof这个运算符到底是怎么工作呢?如果大家有类和实例的概念,可能会说就是检查这个对象是不是这个类的实例啊(正如它的名字暗示的意义),可是有一句会应该是学过js的人都知道,js是没有类的,它的继承原理是原型!所以这个instanceof肯定不是像它名字这个作用原理(真是坑爹啊名字都不起好)。其实instanceof是通过判断前面这个对象的原型链中有没有出现过后面这个函数.prototype对象(或者说这个对象有没有委托给函数.prototype对象,本人更爱这个说法,可以帮助我彻底把和类的说法区分开,防止混淆),如果有则为true,否则false,现在来看bind中的这两句代码,也是为何当用new调用函数的时候this instanceof NOP为true的原因。

NOP.prototype = toBind.prototype;

 bound.prototype = new NOP;

这段代码先是将NOP.prototype设置为调用bind方法的函数的prototype对象,之后又将bound.prototype委托到了一个新的空对象上(new NOP),而这个对象又委托到NOP.prototype上(其实很多书上都会写成将原型设置为一个NOP的实例,可是我觉得这样没有任何好处,反而会让大家无法看清楚js中原型的真面目而且越发混淆,事实上这段代码给我带来的帮助也是帮助我把之前的知识梳理了下,对原型的认识深刻了点,所以我会尽量避免使用任何可能与传统类语法混淆的词汇,希望大家可以接受委托这个词,其实这个词本身也很形象也很好理解啊,是另一种方式的继承,你想想看,你没钱的时候是不是找你老爹要呢?而你本来就是被委托到你老爹那了啊,同样的咱们还被委托到了妈妈那,所以饿了可以找妈妈给你做饭吃,如果你没有被委托到某位那边,人家就不会鸟你,也不会让你用他的东西,也就是不可以访问他的属性和方法!!!),所以在函数内部的this此时是一个被委托到NOP.prototype上的对象所以返回了true(但是要注意这个对象并不是直接被委托到NOP.prototype,中间还有个new NOP)。

原谅本小白初出茅庐本身文笔也不佳,加之并无多少干货,不知所云了半天好像也没有说出什么东西来,唉,台下的少侠你先把鸡蛋收起来好不好。。。。希望这篇文章对大家区分开原型和类这两个极易混淆的概念提供一点点帮助,最主要的是认识到instanceof到底是怎工作的,大家以后不妨多想想委托这个词,以后会介绍基于原型的继承方式,大家会看到这个比模仿类继承要简介明白的多!!!最后再说下为什么说书的作者偷换概念,书中是说比如var fn = foo.bind(obj1),(obj1是一个定义的对象,foo是一个函数),那么用new调用fn,则fn里面的this指向的不再是obj1而是那个新创造的对象,比如var b = new fn,就是这个b,大家可以测试下确实如此,然后作者就得出了new绑定优先于显式绑定,其实完全不在理我觉得,可以改变绑定的原因全在于

 (this instanceof NOP && context ? this : context), args.concat(Array.prototype.slice.call(arguments)));
            };
            NOP.prototype = toBind.prototype;
            bound.prototype = new NOP;

这三行代码,如果咱们用最简单的实现显示绑定的函数function test (fn, o){return function(){fn.apply(o, arguments)};},然后再去测试会发现并不像他说的什么new优先于显式绑定,关于这个绑定,我会在下一篇的瞎BB几句,如果你看到了这里,说明你的水平不太高和我差不多,那你还不赶紧关注我,看看我遇到什么问题,然后帮你排排雷!!!欢迎大家和我一起讨论学习!!!

时间: 2024-10-15 09:08:46

你不知道的js学习日记随笔的相关文章

js学习日记-隐式转换相关的坑及知识

隐式转换比较是js中绕不过去的坎,就算有几年经验的工程师也很有可能对这块知识不够熟悉.就算你知道使用===比较从而避免踩坑,但是团队其它成员不一定知道有这样或那样的坑,有后端语言经验的人常常会形成一个思维误区:"JS这门语言很简单,看看语法再找几个例子就能操作DOM,编写特效了".随着react.vue.html5等技术在项目中大规模使用,越来越多的项目中使用了大量的JS,甚至整个项目都用JS来写(例如基于webapi的SPA管理后台.微信小程序.微信H5应用,Hybrid app),

js学习日记 (1)createDocumentFragment() ES6 => 箭头

只能说是会用和记载,深入理解还需时间. 有关性能优化: 使用createdocumentfragment()方法可以创建某个具有节点该有的所有属性的节点. 使用情况:  提取文档中的某个小部分,修改文档中的小节点,添加部分内容在节点尾部或者某个标志处. 虽然可以用文档的文档对象来在这些情况中使用,但如果防止文件结构被破坏,createDocumentFragment() 方法可以更安全改变文档的结构及节点. 一般这样用: let newLists=document.createDocumentF

node.js学习日记(二)node.js的作用域

node.js的作用域 测试package1能否能通过require("./package2")来调用package2内的函数: 1 //paackage1.js 2 var a1 = 1; 3 4 require("./package2"); 5 6 /*即使require了package2,也无法调用函数double_a*/ 7 a1 = double_a(a1);//double_a is not defined 8 9 console.log("p

vue.js学习日记-组件篇

组件 自定义组件 全局注册: var question={name:'MR Liu'} Vue.component('my-header',{ template:'<p>hello world{{name}}</p> ', data:function(){//data必须是函数 且一般只能返回一个对象 return question//没有';'这个结束符 } }) 注意 question和template之间的关系一定要自己明确 局部注册: <html><hea

js学习日记-对象字面量

对象字面量语法 var person={ name:'小王', age:18, _pri:233 } 1.采用对象字面量方法创建的对象,不能采用var wang=new person()这样的方式来调用,要访问对象中的方法,直接使用person.xxx的形式 2.最后一个成员结尾不要用逗号,不然在某些浏览器中会抛出错误 对象成员配置 对象申明后,会默认为内部的每个成员(属性或方法)生成一些隐藏属性,这些隐藏属性是可以读取和可配置的: Object.getOwnPropertyDescriptor

Vue.js学习日记(3)——计算属性和侦听器

1.计算属性 模板不仅可以是简单的声明式逻辑,也可以是较为复杂的表达式. <div id="element"> <!--简单声明--> {{message}} <!--复杂表达式,表示变量message的翻转字符串--> {{message.split('').reverse().join('')}} </id> 如果表达式过于复杂,将不利于直接理解.当需要在模板中多次引用message的翻转字符串时,操作也会变得繁琐. 所以,对于任何复

[Pro Angular.JS]学习笔记1.1:设置开发环境

可以使用yeoman.io,很方便.我已经写了一篇随笔,介绍如何使用.这里也有一篇介绍的文章:http://www.cnblogs.com/JoannaQ/p/3756281.html 代码编辑器,在Mac下用了一下WebStorm,太恶心了.另外发现书的作者使用的开发环境是Windows + VS Express 2013,为了方便学习,我也使用VS Express 2013 Update2.VS2013用起来蛮舒服的,把WebStorm比得跟驼屎一样.也许是因为我没用习惯吧. 1.安装Nod

node.js 学习 00

前言 先写点废话,相中node.js倒是纯属偶然. 在这之前我想要要搭建一个人网站,我感到现有的博客/空间之类只能给予用户有限的控制力.于是在AWS上申请了免费一年的VPS,自己买了一个域名,百度了之后选择了在主机上挂了一个nginx.在这之后我发现直接手写html是一件十分麻烦的事情,于是暂时失去了构建的方向.只是改了改nginx的默认的主页,就先放着了. 在这之后的新学期里,我多一门 数据库原理 的课程,在这之前我通过王垠的博客了解过Nosql的一些概念.数据库原理老师对传统关系性数据库的吹

web学习日记1

web学习日记1 1.js在使用函数时加不加括号的区别 在慕课网的技术分享(原文链接;http://www.imooc.com/wenda/detail/237566)中遇到这个问题,之前有疑惑,趁着这个机会解开. 题目代码: 1 var fullname = 'John Doe'; 2 var obj = { 3 fullname: 'Colin Ihrig', 4 prop: { 5 fullname: 'Aurelio De Rosa', 6 getFullname: function()