JavaScript
-
js的基本类型有哪些?引用类型有哪些?null和undefined的区别。
-
如何判断一个变量是Array类型?如何判断一个变量是Number类型?(都不止一种)
-
Object是引用类型嘛?引用类型和基本类型有什么区别?哪个是存在堆哪一个是存在栈上面的?
-
JS常见的dom操作api
-
解释一下事件冒泡和事件捕获
-
事件委托(手写例子),事件冒泡和捕获,如何阻止冒泡?如何组织默认事件?
-
对闭包的理解?什么时候构成闭包?闭包的实现方法?闭包的优缺点?
-
this有哪些使用场景?跟C,Java中的this有什么区别?如何改变this的值?
-
call,apply,bind
-
显示原型和隐式原型,手绘原型链,原型链是什么?为什么要有原型链
-
创建对象的多种方式
-
实现继承的多种方式和优缺点
-
new 一个对象具体做了什么
-
手写Ajax,XMLHttpRequest
-
变量提升
-
举例说明一个匿名函数的典型用例
-
指出JS的宿主对象和原生对象的区别,为什么扩展JS内置对象不是好的做法?有哪些内置对象和内置函数?
-
attribute和property的区别
-
document load和document DOMContentLoaded两个事件的区别
-
JS代码调试
所谓显式return,就是在构造函数中主动return一个对象,这里说的对象不仅包括Object
,也包含Array
,Date
等对象哦。
我们可以试一试:
function Test() {
this.name = ‘jack’;
this.age = 18;
return {
content: ‘我有freestyle’
}
}
new Test();
// Chrome控制台会输出以下内容
// {content: “我有freestyle”}
那么return一个普通类型数据有没有用呢?比如字符串,数字?试试便知。
function Test() {
this.name = ‘jack’;
this.age = 18;
return ‘我有freestyle’
}
new Test();
// Chrome控制台会输出以下内容
// Test {name: “jack”, age: 18}
可以看到,当我们return一个普通类型数据时,不会影响结果,依然会返回new出来的这个新对象。
我们也应该知道,new构造函数就是为了创建对象,你return一个字符串之类的普通类型数据是没有任何意义的,所以我们的关注点应该是return一个特殊的对象。请接着往下看。
无new实例化
=======
所谓“无new实例化”,就是指不通过new关键字实例化对象(当然,这里说的不通过new,只是调用层面的,底层还是用了new)。这一点我们使用jQuery的时候已经体验过了。
// 实例化了一个jQuery对象,但是没有用到new
var ele = jQuery(‘
那么这种黑科技是怎么实现的呢?
前面已经提到了,我们可以在构造函数中通过显式return来返回一个自定义的对象,那么这里就有发挥的空间了。我们通过一个简单的例子来感受下:
function Shadow() {
this.name = ‘jack’;
this.age = 18;
}
function jQuery() {
return new Shadow();
}
var obj1 = jQuery();
console.log(obj1)
// Chrome控制台会输出以下内容
// Shadow {name: “jack”, age: 18}
jQuery()
用了移花接木的障眼法完成了对象实例化,一手隐藏的new Shadow()
让我们误以为不用new
直接调用函数也能创建实例。
我们再来试下new jQuery()
,会发现,“卧槽,怎么跟jQuery()
执行结果一模一样!”
var obj2 = new jQuery();
console.log(obj2)
// Chrome控制台会输出以下内容
// Shadow {name: “jack”, age: 18}
这是因为new构造函数显式return了new Shadow()
,这样返回的结果也就是new Shadow()
实例化出来的对象,而不使用new
直接调用jQuery()
,只是把jQuery()
当成一个普通的函数执行,其结果不言而喻是new Shadow()
实例化出来的对象。
所以,这里new jQuery()
和jQuery()
是等价的。
虽然jQuery已经用得越来越少,但是其设计思路非常值得我们学习。那么jQuery到底妙在哪里?可以说是很多,链式操作,插件体系这些特色都是我们耳熟能详的。不扯太多了,就让我们来简单分析下jQuery实例化的过程。
我这里拿到了jQuery v1.12.4版本的代码,大概1W行,很舒服。
翻啊翻啊,翻到了第71行,看到了这么一串代码:
jQuery = function( selector, context ) {
return new jQuery.fn.init( selector, context );
}
这不就是我们熟悉的移花接木技术吗?jQuery.fn.init
似乎就是上面例子中的Shadow
。看着有点像了,但是还是要好好研究下。
为啥要搞个jQuery.fn?
jQuery.fn是jQuery.prototype的别名,是为了代码简洁的考虑。这一点参考源码第91行就可以知道。
jQuery.fn = jQuery.prototype = {
// …
移花接木如何保证原型指向?
我们知道,如果仅仅通过new jQuery.fn.init(selector, context)
是存在一个问题的,问题就是得到的实例不是jQuery
的实例,而是jQuery.fn.init
的实例。那么如何处理这个问题呢?
我们翻到源码2866行,可以看到:
init = jQuery.fn.init = function( selector, context, root ) {
// 创建实例的具体逻辑
}
具体init
方法怎么创建一个jQuery对象,做了哪些判断逻辑,这些都不是本文关注的重点。我们需要关注的是,jQuery是如何保证实例化的对象的原型指向是正确的?不然实例化的对象如何使用jQuery.prototype
上面挂载的诸多方法呢,比如this.show()
、this.hide()
?
紧接着翻到2982行,我有了答案:
init.prototype = jQuery.fn;
妙啊,这一手修改原型指向的操作,完美解决了这个问题。这样一来,new init()
得到的实例自然也是jQuery
的实例。
jQuery.prototype.init.prototype === jQuery.prototype; // true
var a = $(‘
a instanceof jQuery // true
a instanceof jQuery.fn.init // true
这样一来,我们可以得到一个基本的设计思路:
function myModule(params) {
return new myModule.fn.init(params);
}
myModule.fn = myModule.prototype = {
constructor: myModule
}
myModule.fn.init = function(params) {
// 可以对实例对象进行各种操作
}
myModule.fn.init.prototype = myModule.prototype;
在这个基础上,我们可以扩展静态方法和原型方法,这个myModule模块就变得越来越丰富。
刷面试题
刷题的重要性,不用多说。对于应届生或工作年限不长的人来说,刷面试题一方面能够尽可能地快速自己对某个技术点的理解,另一方面在面试时,有一定几率被问到相同或相似题,另外或多或少也能够为自己面试增加一些自信心,可见适当的刷题是很有必要的。
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
-
前端字节跳动真题解析
-
【269页】前端大厂面试题宝典
最后平时要进行自我分析与评价,做好职业规划,不断摸索,提高自己的编程能力和抽象思维能力。大厂面试远没有我们想的那么困难,摆好心态,做好准备,你也可以的。