首页
Search
1
解决visual studio code (vscode)安装时没有选择安装路径问题
138 阅读
2
Linux 下 Bash 脚本 bad interpreter 报错的解决方法
131 阅读
3
Arch Linux 下解决 KDE Plasma Discover 的 Unable to load applications 错误
107 阅读
4
如何在 Clash for Windows 上配置服务
77 阅读
5
Uniapp如何引入自定义样式文件
75 阅读
clash
服务器
javascript
全部
游戏资讯
登录
Search
加速器之家
累计撰写
1,061
篇文章
累计收到
0
条评论
首页
栏目
clash
服务器
javascript
全部
游戏资讯
页面
搜索到
624
篇与
的结果
2024-10-21
jQuery 中 extend 的实现
通常我们使用 jquery 的 extend 时,大都是为了实现默认字段的覆盖,即若传入某个字段的值,则使用传入值,否则使用默认值。如下面的代码:function getOpt(option) { var _default = { name: "wenzi", age: "25", sex: "male", }; $.extend(_default, option); return _default; } getOpt(); // {name: "wenzi", age: "25", sex: "male"} getOpt({ name: "bing" }); // {name: "bing", age: "25", sex: "male"} getOpt({ name: "bing", age: 36, sex: "female" }); // {name: "bing", age: 36, sex: "female"} 那现在我们就得需要知道这个 extend 具体是怎么实现的了,除了实现上面的功能,还有其他作用么?那肯定是有的啦,否则我也不会问那句话了((⊙﹏⊙)b)。我们先来看看 extend 主要有哪些功能,然后再看实现这些功能的原理。 1. extend 能实现的功能 # 其实从 extend 的含义里,我们就能知道 extend 是做什么的了。extend 翻译成汉语后就是:延伸、扩展、推广。 1.1 将两个或更多对象的内容合并到第一个对象 # 我们来看看$.extend()提供的参数:jQuery.extend( target [, object1 ] [, objectN ] ),extend 方法需要至少传入一个参数,第一个必需,后面的都是可选参数。若传给 extend 是两个或两个以上的参数都是对象类型,那么就会把后面所有对象的内容合并给 target(第一个对象)上。我们再来看看上面的例子:function getOpt(option) { var _default = { name: "wenzi", age: "25", sex: "male", }; $.extend(_default, option); return _default; } $.extend()中接收了两个参数 _default 和 option,那么 extend 方法执行时,就会把 option 对象上字段的值全给了 _default。于是 _default 上设置的默认值就会被 option 上的值覆盖。当然,若 option 上没有这个字段,就不会覆盖 _default 上字段的值。上面函数中的 extend,只是传入了两个参数,那传的参数再更多一些呢:function getOpt(target, obj1, obj2, obj3) { $.extend(target, obj1, obj2, obj3); return target; } var _default = { name: "wenzi", age: "25", sex: "male", }; var obj1 = { name: "obj1", }; var obj2 = { name: "obj2", age: "36", }; var obj3 = { age: "67", sex: { error: "sorry, I dont't kown" }, }; // {name: "obj2", age: "67", sex: {error: "sorry, I dont't kown"}} getOpt(_default, obj1, obj2, obj3); 这里我们传入了 4 个参数,然后 getOpt()返回第一个参数的值。从运行的得到结果我们可以看到,属性值永远是最后一个属性的值。还有很重要的一点,$.extend()其实是有返回值的,返回的就是修改后的第一个参数的值。如我们可以把上面的函数修改成这样:function getOpt(target, obj1, obj2, obj3) { var result = $.extend(target, obj1, obj2, obj3); return result; // // result即修改后的target值 } 若我们传入的参数不想被修改,我们可以用一个空对象来作为第一个参数,然后获取$.extend()的返回值:function getOpt(target, obj1, obj2, obj3) { var result = $.extend({}, target, obj1, obj2, obj3); return result; // // result即为{}修改后的值 } 1.2 为 jQuery 扩展方法或属性 # 刚才我们在 1.1 中讲的$.extend()的例子都是传了两个或两个以上的参数,但其实只有一个参数是必须的。若只传一个参数会怎样呢。 如果只有一个参数提供给$.extend(),这意味着目标参数被省略。在这种情况下,jQuery 对象本身被默认为目标对象。这样,我们可以在 jQuery 的命名空间下添加新的功能。这对于插件开发者希望向 jQuery 中添加新函数时是很有用的。 举个例子:$.extend({ _name: "wenzi", _getName: function () { return this._name; }, }); $._name; // wenzi $._getName(); // wenzi 这样我们就为 jQuery 扩展了_name属性和_getName方法。 1.3 深度拷贝和浅度拷贝 # 针对什么是深度拷贝,什么是浅度拷贝,我们先来看一个简单的例子。var obj = { name: "wenzi", sex: "male" }; var obj1 = obj; // 赋值 obj1.name = "bing"; console.log(obj.name); // bing 我们修改了 obj1 中的 name 值,结果 obj 中的值也跟着发生了变化,这是为什么呢。其实这就是 浅度拷贝 :这仅仅是将 obj 对象的引用地址简单的复制了一份给予变量 obj1,而并不是将真正的对象克隆了一份,因此 obj 和 obj1 指向的都是同一个地址。当修改 obj1 的属性或给 obj1 添加新属性时,obj 都会受到影响。可是如果变量的值不是对象和数组,修改后面的变量是不会影响到前面的变量:var s = "hello"; var t = s; t = "world"; console.log(s); // hello 那么深度拷贝就不是拷贝引用地址,而是实实在在的复制一份新对象给新的变量。 在上面使用$.extend()中,都是使用的浅度拷贝,因此若后面的参数值是 object 类型或 array 类型,修改_default(target)的值,就会影响后面参数的值。如我们使用getOpt(_default, obj1, obj2, obj3);得到的_default 值是{name: "obj2", age: "67", sex: {error: "sorry, I dont't kown"}},可是若:_default.sex.error = "hello world"; 那么 obj3.sex.error 也会跟着修改,因为 obj3.sex 是一个 object 类型。不过$.extend()也提供了深度拷贝的方法:jQuery.extend( [deep ], target, object1 [, objectN ] )。若第一个参数是 boolean 类型,且值是 true,那么就会把第二个参数作为目标参数进行合并。var obj = { name: "wenzi", score: 80 }; var obj1 = { score: { english: 80, math: 90 } }; $.extend(true, obj, obj1); obj.score.english = 10; console.log(obj.score.english); // 10 console.log(obj1.score.english); // 80 执行后我们发现,无论怎么修改 obj.score 里的值,都不会影响到 obj1.score 了。 2. jQuery 中 extend 实现原理 # 其实不看源码,对 extend 大致的过程应该也是了解的:对后一个参数进行循环,然后把后面参数上所有的字段都给了第一个字段,若第一个参数里有相同的字段,则进行覆盖操作,否则就添加一个新的字段。下面是 jQuery 中关于 extend 的源码,我就在源码上进行注释讲解了,随后再在后面进行总结:// 为与源码的下标对应上,我们把第一个参数称为`第0个参数`,依次类推 jQuery.extend = jQuery.fn.extend = function () { var options, name, src, copy, copyIsArray, clone, target = arguments[0] || {}, // 默认第0个参数为目标参数 i = 1, // i表示从第几个参数凯斯想目标参数进行合并,默认从第1个参数开始向第0个参数进行合并 length = arguments.length, deep = false; // 默认为浅度拷贝 // 判断第0个参数的类型,若第0个参数是boolean类型,则获取其为true还是false // 同时将第1个参数作为目标参数,i从当前目标参数的下一个 // Handle a deep copy situation if (typeof target === "boolean") { deep = target; // Skip the boolean and the target target = arguments[i] || {}; i++; } // 判断目标参数的类型,若目标参数既不是object类型,也不是function类型,则为目标参数重新赋值 // Handle case when target is a string or something (possible in deep copy) if (typeof target !== "object" && !jQuery.isFunction(target)) { target = {}; } // 若目标参数后面没有参数了,如$.extend({_name:'wenzi'}), $.extend(true, {_name:'wenzi'}) // 则目标参数即为jQuery本身,而target表示的参数不再为目标参数 // Extend jQuery itself if only one argument is passed if (i === length) { target = this; i--; } // 从第i个参数开始 for (; i < length; i++) { // 获取第i个参数,且该参数不为null和undefind,在js中null和undefined,如果不区分类型,是相等的,null==undefined为true, // 因此可以用null来同时过滤掉null和undefind // 比如$.extend(target, {}, null);中的第2个参数null是不参与合并的 // Only deal with non-null/undefined values if ((options = arguments[i]) != null) { // 使用for~in获取该参数中所有的字段 // Extend the base object for (name in options) { src = target[name]; // 目标参数中name字段的值 copy = options[name]; // 当前参数中name字段的值 // 若参数中字段的值就是目标参数,停止赋值,进行下一个字段的赋值 // 这是为了防止无限的循环嵌套,我们把这个称为,在下面进行比较详细的讲解 // Prevent never-ending loop if (target === copy) { continue; } // 若deep为true,且当前参数中name字段的值存在且为object类型或Array类型,则进行深度赋值 // Recurse if we're merging plain objects or arrays if (deep && copy && (jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)))) { // 若当前参数中name字段的值为Array类型 // 判断目标参数中name字段的值是否存在,若存在则使用原来的,否则进行初始化 if (copyIsArray) { copyIsArray = false; clone = src && jQuery.isArray(src) ? src : []; } else { // 若原对象存在,则直接进行使用,而不是创建 clone = src && jQuery.isPlainObject(src) ? src : {}; } // 递归处理,此处为2.2 // Never move original objects, clone them target[name] = jQuery.extend(deep, clone, copy); // deep为false,则表示浅度拷贝,直接进行赋值 // 若copy是简单的类型且存在值,则直接进行赋值 // Don't bring in undefined values } else if (copy !== undefined) { // 若原对象存在name属性,则直接覆盖掉;若不存在,则创建新的属性 target[name] = copy; } } } } // 返回修改后的目标参数 // Return the modified object return target; }; 源码分析完了,下面我们来讲解下源码中存在的几个难点和重点。 2.1 若参数中字段的值就是目标参数,停止赋值 # 在源码中进行了一下这样的判断:// Prevent never-ending loop if ( target === copy ) { continue; } 为什么要有这样的判断,我们来看一个简单的例子,如果没有这个判断会怎么样:var _default = { name: "wenzi" }; var obj = { name: _default }; $.extend(_default, obj); console.log(_default); 输出的_default 是什么呢:_default = { name: _default }; _default 是 object 类型,里面有个字段 name,值是_default,而_default 是 object 类型,里面有个字段 name,值是_default......,无限的循环下去。于是 jQuery 中直接不进行操作,跳过这个字段,进行下一个字段的操作。 2.2 深度拷贝时进行递归处理 # 我们在前面稍微的讲解了一下,变量值为简单类型(如 number, string, boolean)进行赋值时是不会影响上一个变量的值的,因此,如果当前字段的值为Object或Array类型,需要对其进行拆分,直到字段的值为简单类型(如 number, string, boolean)时才进行赋值操作。 3. $.extend()与$.fn.extend() # 上面讲解的全都是$.extend(),根本就没讲$.fn.extend()。可是,你有没有发现一个细节,在这段代码的第一行是怎么写的:jQuery.extend = jQuery.fn.extend = function () {}; 也就是说$.extend()与$.fn.extend()共用的是同一个函数体,所有的操作都是一样的,只不过两个 extend 使用的对象不同罢了:$.extend()是在 jQuery($)上进行操作的;而$.fn.extend()是在 jQuery 对象上进行操作的,如$('div').extend(). 4. 总结 # 这就是 jQuery 中 extend 的实现,以后若我们需要用到上面的功能时,除了使用$.extend(),我们也可以在不引入 jQuery 框架的情况下,自己写一个简单的 extend()来实现上面的功能。
2024年10月21日
3 阅读
0 评论
0 点赞
2024-10-21
我的博客之路
最近对【我的博客】的页面样式改动了几次,让我想起了我一路走来的博客之路。想想从开始网络博客到现在也有 5 年的时间了,那时候还不知道什么是博客呢,顶多算是一篇日志吧。从刚开始的 qq 空间,到后来的博客园,再到现在自己的博客,可谓走了很长的一段时间。 1. QQ 空间 # 刚开始是从 QQ 空间开始的。每个刚开始使用 qq 的时候,总是要矫情一番,而且大多还都是转载的文章。看看我那时转载的文章题目《心等久会死心,原来 521+365=886 》,《每天看一遍保持清醒 》,《"赢在中国”中对 90 后有用的 30 个忠告 》,《很美的句子,句句掉泪,不知道原创是谁,感谢他 》,《让你少奋斗 30 年的 9 句至理名言》,等等等等。各种文章充满了矫揉造作,东拼西凑的语句。而且在 QQ 空间里很少有自己真正感情的日志(当然 QQ 说说还是能反映真实感情的)。在 QQ 空间里转一些当时觉得很是至理名言的文章或金句,从 2010 年 5 月到第二年的 7 月份,总算是没那么疯狂的转载别人的日志了;不过在 2013 年和 2014 年还转了 3 篇文章。QQ 空间的日志历程总算是结束了。在这个刚开始的阶段,基本没有自己的干货,差不多都是转载着别人的文章,什么大学生要励志呀,什么大学生爱情观啦,什么不转死全家了等等。等过了一年之后,可能是心态也成熟了一些,不再在 qq 空间转载哪些日志了。 2. 百度空间 # 从 2010 年的夏天开始,在我们学院的 ACM 实验室里,各种大量的做题,接触了各种的编程题目和算法,差不多宿舍快关门的时候,才从实验室出来往回赶;后来在 2011 的时候开始使用 js+php,写各种管理系统,学习 jQuery。从这个时候开始,算是正式的步入了程序员的行列了吧。从真正的开始接触程序,才有了自己的想法和思路,想着能把自己的思路或遇到过的问题记录下来,而当时觉得 qq 空间不是很适合写技术方面的东西,也不知怎么地就找到了百度空间。于是就一直在百度空间上写文章、写感想。直到 2012 年 8 月份左右,百度空间开始改版了,改的比较难以适应。当时已经听说了新浪博客的大名了,于是就打算寻找一个新的地方开始写我的博客。当然,从 2015 年 5 月 7 日,百度空间正式关闭了,所有的文章都迁移到百度云上面去了。本来想着留一个百度云的地址,让你们去逛逛我的文章,结果发现,自己是没有百度云的个人域名的,只有文章是有链接的。算了,不去也罢,从 2012 年 8 月份也不再更新了。 3. 博客园 # 本来是想把新浪博客放在第三位的,结果发现新浪博客还真没起到什么作用。当时就从百度空间转了几篇文章到新浪博客,还没写新的东西呢,就已经注册了博客园了。正式搬到博客园。终于是进入到了真正开始写博客的时代了。从 2012-09-19 的第一篇文章一直更新到现在,还有 3 个月就三年的时间了,带着转载的和自己写的,一共有 83 篇博文了。从刚开始的 php 总结,到现在更加专注于前端方面的文章,从技术到个人心得上,差不多能写出来的都写在博客园了。博客园是我关注的最多的技术网站,现在每天早晨的第一件事儿就是看看园子首页上,有没有好的文章。如果有什么赞同或者想法,必定也是要评论一番的,总不能了凉了博主的一番心意。若是博主的文章欠缺一些含量,但是还没被管理员移出首页的时候,有时候也会给他指出来文章中一些欠缺的地方。真的,在博客园上成长了很多,可能也有一种先入为主或者习惯的问题吧,虽然现在也收藏不了不少的技术网站,但是逛的最多的还是博客园。相信我也会一直关注下去,并一直更新我的文章。那时我给自己的博客起域名的时候,还是用了当时比较喜欢的网名的拼音:xumengxuan(许梦轩)。因此博客的地址也就是 http://www.cnblogs.com/xumengxuan 了。不过现在在网上各种论坛的名字都已经统一了,统一叫做“蚊子”。 4. 自己的博客 # 有些人在写了段时间的博客后,就不满足于一直在技术园区写博客了,想着有自己的域名和博客。而我,就是其中一个。从 2014 年的年底,博客正式上线,一直维护到现在【我的博客】。有自己的博客后,很多的东西都能随着自己的性子来。比如今天我要改这儿,明天我要改那儿。今天我学习了 gulp,然后我就开始拿我的博客进行实验,把之前要加载的 4 个 css 文件压缩合并成一个文件,把之前要加载的 3 个 js 文件压缩合并成一个文件进行加载。可能也有人要问了,是自己的博客好,还是在技术区写博客好。各有各的好处,自己的博客呢,就像上面说的,自己可以随便霍霍(当然,为了收录也不能太随便了),学到 SEO,网站运营和维护的知识,学到为了加快自己博客的加载速度的各种改进;而技术区的博客呢,能有有很多的访问量,其他的用户能够很直接的发现你的文章,并能够浏览和评论,但自己博客的文章,除非别人收藏了,或者通过搜索引擎才能找到你的文章,或者通过其他的一些外链。 5. 总结 # 一路走来,换了好几个地方写博客,总是希望能够找到适合自己的一种方式。有的时候写文章的时候,忽然冒出一个想法来,网上关于这个知识点已经有很多的例子了,我就不用写了吧,这不是在重复造轮子么。其实不然,别人写出的东西,永远是别人的,只有重复造过轮子之后,才能明白轮子的原理。不管是搭建自己的博客,还是再博客园,csdn 或者什么地方写博客,最主要的是能给自己一个总结,然后才是帮助别人。想想从开始写日志到现在,差不多也要 5 年的时间了,零零散散在网上也发表了很多的文章。其实一路走来,也是能够发现我们的心态也在一步步的发生着变化。愿我的博客之路能一直走下去。
2024年10月21日
3 阅读
0 评论
0 点赞
2024-10-21
浅谈javascript中的prototype
在本文中,我们讲解prototype的内容主要由:什么是prototype,prototype与函数之间的关系,prototype与实例对象之间的关系,使用proto实现一个简单的继承。 1. prototype的简要介绍 # 在javascript中,创建的每个函数天生都自带着一个prototype属性。这里我们要强调的是:这个prototype属性是一个指针,指向一个对象,在这里,我们称指向的这个看不到但确实存在的对象为原型对象。其实可以用下面一个简单的例子来说明:var proto = { name : 'wenzi', age : 25 } function Person(){ } Person.prototype = proto; 这样Person.protptype就指向到了proto,如果还有其他的引用(A)也指向到了proto,那么这个引用和Person.prototype就是相等的:A==Person.prototype;prototype指向的这个对象是真实存在的,可能很多的同学对prototype属性和原型对象有些混淆,我们在这里把原型对象叫做大SB。大SB与普通对象的一个不同之处就是,他也有一个天生的属性:constructor,这个constructor重新指回到了函数。不过,既然大SB也是一个对象,那么它也是继承于Object的,拥有Object所有的方法和属性,比如toString()等。大SB = { constructor : Person, say : function(){ return "hello world"; } } 那么现在我们就能得到两个引用关系: 大SB = Person.prototype; // 原型对象 = 函数.prototype;Person = 大SB.constructor(Person.prototype.constructor); // 函数 = 原型对象.constructor 从运行的代码中,可以验证我们的观点,Person.prototype的类型是object,Person.prototype.constructor重新指回到了Person。其实在实例对象中,也存在着一个属性指向到大SB中:var John = new Person(); 大SB = John.__proto__; 即 John.proto 和 Person.prototype 指向的是同一个引用:John.__proto__==Person.prototype。 2. 对象实例和prototype中的属性 # 在构造函数能设置属性和方法,在prototype中也能设置属性和方法,那new出的对象使用的是哪个呢?我们来看一个例子:function Person(){ this.name = "wenzi"; } Person.prototype.name = "bing"; Person.prototype.say = function(){ return "hello world"; } var John = new Person(); alert(John.name); // "wenzi" alert(John.say()); // "hello world" 从运行的结果我们可以看到,John.name输出的是构造函数中的属性值"wenzi",John.say()输出的是"hello world"。这是因为,当读取某个对象的属性值时,会首先在实例对象中进行搜索,若搜索到则直接进行返回;若搜索不到则去原型对象中进行寻找。因此在使用John调用say()方法时是正确的,不会报错。而且是进行了两次的搜索。虽然say()是挂载在prototype上,John也同样能直接进行访问。但是,我们不能直接对John.say进行修改从而影响prototype的say()方法,如下:John.say = function(){ return "this has changed"; } John.say(); // "this has changed" var Tom = new Person(); Tom.say(); // "hello world" 从运行John.say()的结果来看,say()方法确实发生了变化。但是,当我们再new出一个新对象Tom时,Tom.say()返回的还是"hello world",这是为什么呢?因为,对John.say()进行修改时,不是修改了prototype上的say(),而是给John这个实例对象添加了一个say()方法,从而屏蔽了prototype上的say()方法,由上面的寻找顺序我们可以知道,若实例对象存在这个方法就直接返回了,不再去原型对象上寻找。而new出的新对象Tom在调用say()方法时,Tom自己是没有say()方法的,只能去原型对象上寻找,因此返回的还是"hello world"。所以,对John.say进行修改时,不是修改了prototype上的say()方法,而是给John添加了实例方法,屏蔽掉了prototype上的方法而已。那如何才能修改prototype上的方法呢,好办,直接在prototype上修改:Person.prototype.say = function(){ return "wenzi's blog"; } 这样就能修改prototype的say()方法了。让我们从图里看看这些的关系,懒得画图了,从网上盗了一张:最左边是两个实例对象,都有__proto__属性,指向中间的原型对象;中间的原型对象,有constructor属性,指回到函数Foo,同时因为他也是对象,也有__proto__属性,指向超类Object.prototype;上面的Foo()函数的prototype指向中间的原型对象,Foo()的__proto__指向到Function.prototype;下面的是超类Object的原型对象。 3. 重写prototype # 在上面的例子中,我们都是大部分给prototype添加属性或方法,本来prototype指向的是大SB,若我们给prototype添加属性或方法时,就是给大SB添加属性或方法:Person.prototype.name = "wenzi"; 而大SB里其他的属性和方法是不受影响的,constructor依然指回到Person。但是,若我们这样写:Person.prototype = { name : "wenzi", say : function(){ return "my name is name" } } 就是对Person的prototype重写了,让prototype进行了重新的指向,本来Person.prototype指向的是大SB,可是现在却指向了CTM,而CTM里也没有constructor属性指回到Person,若是想重新指回到Person,还得手动添加一个constructor属性:Person.prototype = { constructor : Person, // 重新指回到Person name : "wenzi", say : function(){ return "my name is name" } } 这样就能手动构造出新的原型对象了,new出的实例对象也能使用这个prototype上的属性和方法。但是这里还存在一个问题,若之前已经有new出的实例对象,然后再修改Person.prototype,之前的实例对象是无法使用新的原型对象(CTM)上的属性和方法的,因为之前的实例对象的__proto__指向的依然是大SB。因此,请慎重重写prototype 4. 原型继承 # 说到prototype就不得说prototype继承,我们通过给prototype上添加属性和方法,就能使该构造函数所有的实例对象拥有属性和方法。我们先来看下面的代码:function Father(){ this.name = "father"; this.age = 43; } Father.prototype.job = "Doctor"; Father.prototype.getName = function(){ return this.name; } function Son(){ this.name = "son"; } Son.prototype = new Father(); // Son的prototype指向Father的实例对象 var John = new Son(); for(var k in John){ console.log(k+' : '+john[k]); } /* 输出结果: name : son age : 43 job : Doctor getName : function (){ return this.name; } */ 从上面的例子中可以看到,Son的实例对象继承了Father中所有的属性和方法。当然,若Son的对象实例中存在的,还依然保留。不过Son原型中的属性和方法是会被彻底覆盖的。我们来分析一下这是为什么?Son的prototype指向的是Father的一个实例,我们把这拆成两步:var father = new Father(); Son.prototype = father; 在实例father中既有name,age属性,也有Father.prototype中的属性和方法,我们对father循环看一下:for(var k in father){ console.log(k, father[k]); } /* name father age 43 job Doctor getName Father.getName() */ 由于constructor是不可枚举的类型,在for~in循环里是输出不了constructor的,其实father是这样的:father = { constructor : Father, name : father age : 43 job : Doctor getName : Father.getName() } 因此Son的prototype指向的就是上面father的内容。到此,Son的prototype中的constructor的指向也发生了改变,本来Son.prototype是指向到Son的,现在指向到了Father。即完全重写了Son的prototype,重新指向了另一个引用。所以,我们就能知道为什么对象实例中的属性能够保存,而prototype中的会彻底被删除了。如果想给Son添加原型方法或属性,那只能是在Son.prototype = new Father();之后进行添加:Son.prototype = new Father(); Son.prototype.getJob = function(){ return this.job; } 这样就能添加上getJob方法了。到这里,会有人问,如果Son.prototype = Father.prototype会怎么样呢?我们刚才也说了Father.prototype指向的是大SB,而大SB也是一个实例对象,是Object的一个实例,这就相当于:Son.prototype == 大SB; // 指向了大SB 因此,如果是Son.prototype = Father.prototype的话,那么Son只能继承到Father.prototype上的job和getName(),其他的属性是获取不到的。最后的最后,给大家留一个小问题,看看输出的都是什么:function AAA(name){ if(name){ this.name = name; } } function BBB(name){ this.name = name; } function CCC(name){ this.name = name || 'John'; } AAA.prototype.name = 'Tom'; BBB.prototype.name = 'Tom'; CCC.prototype.name = 'Tom'; console.log((new AAA()).name, (new BBB()).name, (new CCC()).name); 5. 总结 # 本文简单的介绍了一下prototype,让我们能对prototype有个浅显的认识。当然,博主才疏学浅,文章里会有很多疏漏和不完善的地方,欢迎大家批评指正。
2024年10月21日
3 阅读
0 评论
0 点赞
2024-10-21
leetcode-invert-binary-tree
最近的一个新闻倒是挺火的,homebrew的作者Max Howell面试谷歌时因为没在白板上写出反转二叉树的算法,结果面试面试挂掉了。于是这位哥们儿在Twitter上发帖: Google: 90% of our engineers use the software you wrote (Homebrew), but you can’t invert a binary tree on a whiteboard so fuck off.(谷歌:虽然我们 90% 工程师都在用你写的软件(Homebrew),但你不能在白板上反转二叉树,所以滚蛋。) 现在让我们来亲自解一下这个面试题:如何反转二叉树。我们先来看看leetcode上对这个题目的具体描述(Invert Binary Tree):其实思路还是比较简单的:将当前的root节点的左右分支进行对调反转,若左分支存在,则将左分支的节点作为root节点进行对调反转;若右分支存在,则将右分支的节点作为root节点进行对调反转;一直**递归**到所有节点的左右分支都不存在。这里使用js来解决这个反转二叉树的问题:/** * Definition for a binary tree node. * function TreeNode(val) { * this.val = val; * this.left = this.right = null; * } */ /** * @param {TreeNode} root * @return {TreeNode} */ var invertTree = function(root) { // 传入的根节点可能就是null或者异常节点,则对root进行判断 if(root){ var temp = null; // 将当前节点的左右分支进行对调反转 temp = root.left; root.left = root.right; root.right = temp; // 若左分支存在,则递归左分支的节点 if(root.left){ invertTree(root.left); } // 若右分支存在,则递归右分支的节点 if(root.right){ invertTree(root.right); } } // 所有的节点遍历完成后,返回根节点 return root; }; 从以上的代码我们能够看出,算法其实还是比较简单的,递归其左右分支就能把整个二叉树进行反转。
2024年10月21日
3 阅读
0 评论
0 点赞
2024-10-21
how-many-fibs
前几天在我们学校的OJ平台上做了一道大数运算的题目,其实也不算很难,一次就通过了,不过还是想用日志记录一下解题思路。先附上题目的链接How many Fibs?。这个题目的意思是,输入两个数a和b(a
2024年10月21日
3 阅读
0 评论
0 点赞
1
...
13
14
15
...
125