0801 NOTE
部分知识自查面试题整理,原型部分后为收集资料,未思考总结,后续补上
JQUERY
-
Jquery的美元符号$有什么作用? 答:
是
J
q
u
e
r
y
的
别
名
,
可
以
通
过
是Jquery的别名,可以通过
是Jquery的别名,可以通过生成Jquery对象,调用Jquery的方法 -
Jquery中有哪几种类型的选择器? 答:从个人角度而言根据css样式选择器进行划分: ? 1.简单选择器,将css样式的基本选择器如id选择器,class选择器,标签选择器等作为对象参数传入
符
,
获
取
到
所
需
d
o
m
元
素
,
如
获
取
所
有
的
d
i
v
标
签
,
符,获取到所需dom元素,如获取所有的div标签,
符,获取到所需dom元素,如获取所有的div标签,(‘div’) ? 2.层次选择器,根据元素的层次递进关系如div标签下的ul标签下的li标签来确认作为参数传入
符
的
对
象
,
获
取
到
所
需
d
o
m
元
素
,
如
获
取
所
有
u
l
标
签
下
l
i
标
签
下
的
a
标
签
,
符的对象,获取到所需dom元素,如获取所有ul标签下li标签下的a标签,
符的对象,获取到所需dom元素,如获取所有ul标签下li标签下的a标签,(‘ul li a’) ? 3.过滤选择器,基于简单选择器和层次选择器,通过语法类似于css中伪类选择器的过滤规则筛选获取所需到dom元素,如获取li标签中的第一个元素,$(‘li:first’) -
JavaScript window.onload 事件和 jQuery ready 函数有何不同? ? 答:首先,两者功能都是等待页面加载完后执行指定函数,但是Jquery ready函数是在页面dom结构加载完后即执行,而onload事件则需等待所有文件包括图片、音频、视频等外部资源加载完成后执行,其次,onload事件只能执行一次,执行第二次会将第一次的执行结果覆盖,而jquery的ready函数则可以执行多次且不会覆盖上一次的执行结果。 -
如何找到所有 HTML select 标签的选中项? ? 答:$(’[name=NameOfSelectedTag] :selected’) -
$(this) 和 this 关键字在 jQuery 中有何不同? 答:$(this)获取的是一个Jquery对象,可以调用Jquery方法,this指向所需元素,不能调用Jquery方法
bootstrap
-
什么是Bootstrap?为什么要使用Bootstrap? ? 答:是一个用于快速开发的前端框架,使用的原因是移动设备优先,响应式开发,操作简单等。 -
使用Bootstrap时,要声明的文档类型是什么?为什么要这样声明? ? 答:html5,也就是Doctype文档,因为bootstrap使用了部分的h5的属性和css样式,如果文档声明类型不一致,可能出现浏览器显示与预期效果不同。 -
你能描述一下渐进增强和优雅降级之间的不同吗? ? 答: ? 渐进增强是先实现基础功能,随后根据各个浏览器不断增加功能,优化实现效果,简单来说,就是基于浏览器低版本,先达到最低要求,随后向上迭代 ? 优雅降级则是先完善所有功能,随后针对各个浏览器进行测试,修复漏洞,确保低版本浏览器也拥有最基本的功能,简单来说就是基于浏览器高版本,实现高要求,随后向下迭代
对象
-
js的内置类型有哪些? ? 答:number,string,boolean,symbol,undefined,null,object -
var obj1 = { x: 5 };
var obj2 = obj1;
obj1.a = obj1 = { x: 6 };
console.log(obj1.a);
console.log(obj2.a);
? 答:打印结果为:undefined和{x : 6} -
实现对象的深度克隆 ? 答: function cloneobj(source, target = {}) {
let classList = [Set, Map, Date, RegExp];
let keys = Object.getOwnPropertyNames(source).concat(Object.getOwnPropertySymbols(source));
for (let i = 0; i < keys.length; i++) {
if (keys[i] === "prototype") continue;
let desc = Object.getOwnPropertyDescriptor(source, keys[i]);
if (desc.value instanceof Object) {
let o;
if (desc.value instanceof HTMLElement) o = desc.value.cloneNode(true);
else if (classList.includes(desc.value.constructor)) o = new desc.value.constructor(desc.value);
else if (desc.value.constructor === Function) {
let arr = desc.value.toString().replace(/\n/g, "").match(/function\s*\((.*?)\)\s*\{(.*?)\}/).slice(1);
o = new Function(arr[0], arr[1])
}
else o = new desc.value.constructor();
Object.defineProperty(target, keys[i], {
value: o,
enumerable: desc.enumerable,
writable: desc.writable,
configurable: desc.configurable
})
cloneobj(desc.value, o);
}
else Object.defineProperty(target, keys[i], desc);
}
return target;
}
call,apply,bind
-
简述call、apply、bind,call 和 apply哪个性能更好? ? 答:首先,call方法传入的参数数量不定,第一个参数为this指定对象,如果为null或者undefined,则指向window,其余参数则传入函数,根据需求调用,其次,apply方法传入参数只有两个,第一个与call相同,为this指定对象,第二个为类数组对象,传入函数,bind则是改变this指向的同时,传入参数,返回一个新函数,该函数会在调用时才执行;就性能而言,call性能优于apply,传入参数3个以内时两者差距不大,传入参数超过三个,则call方法性能优于apply。 -
改变函数内部 this指针的指向函数(bind,apply,call的区别) ? 答:首先,call传入参数数量不定,apply传入参数只能有两个,其次,apply方法传入的第二个参数必须为数组或者类数组对象,而bind函数在改变this指向的同时会返回的是一个新函数,需要重新调用才会执行。 -
let a=0;
const obj={
a:1,
b:function () {
console.log(this.a);
},
};
const obj1={
a:2
}
const fun=obj.b;
fun();
fun.apply(obj);
fun.bind(obj1).call(obj);
const fun1=fun.bind(obj1)
new fun()
? 答:打印结果为:fun() 打印undefined,fun.apply(obj)打印1,fun.bind(obj1).call(obj) 打印2,new fun() 打印undefined
this
-
var myObject = {
foo: "bar",
func: function() {
var self = this;
console.log("outer func: this.foo = " + this.foo);
console.log("outer func: self.foo = " + self.foo);
(function() {
console.log("inner func: this.foo = " + this.foo);
console.log("inner func: self.foo = " + self.foo);
}());
}
};
myObject.func();
-
var length = 10;
function fn() {
console.log(this.length);
}
var obj = {
length: 5,
method: function(fn) {
fn();
arguments[0]();
}
};
obj.method(fn, 1);
-
window.number = 2;
var obj = {
'number': 3,
'db1': (function(){
console.log(this);
this.number *= 4;
return function(){
console.log(this);
this.number *= 5;
}
})()
}
var db1 = obj.db1;
db1();
obj.db1();
console.log(obj.number);
-
var name = '222'
var a = {
name: '111',
say: function () {
console.log(this.name)
}
}
var b = {
name: '333',
say: function (fn) {
fn()
}
}
a.say()
b.say(a.say)
-
var obj = {
a: 10,
c: 50,
b: {
a: 0,
c: this.a,
run: function () {
console.log(this.c);
}
}
}
笔记:判断this:
-
函数是否在 new 中调用(new 绑定)?如果是的话 this 绑定的是新创建的对象。 var bar = new foo() -
函数是否通过 call、apply(显式绑定)或者硬绑定调用?如果是的话,this 绑定的是指定的对象。 var bar = foo.call(obj2) -
函数是否在某个上下文对象中调用(隐式绑定)?如果是的话,this 绑定的是那个上下文对象。 var bar = obj1.foo() -
如果都不是的话,使用默认绑定。如果在严格模式下,就绑定到 undefined,否则绑定到全局对象。
setter和getter
-
请叙述一下js对象中的访问器属性 ? 答:js对象中的访问器属性是指的一组获取和设置值的函数,setter和getter,getter获取值后返回,setter设置值,没有返回值,访问器属性无法直接访问,可以通过Object.getOwnPropertyDescriptor()方法获取,但是与value值冲突,访问器属性不能与value属性共存
闭包
-
什么是闭包 ? 答:闭包就是一个函数和一个函数内部可以访问到的外部的局部变量的集合,闭包是js函数作用域的副产品,简单来说,js的函数内部可以调用函数外部的局部变量时,就产生了闭包。 -
闭包的作用 ? 答:可以实现外部访问函数内部的变量,可以保存函数内的局部变量,可以防止全局变量被污染,即公共属性和私有属性模块化。 -
闭包造成内存泄漏的原因 ? 答:实际闭包并没有造成内存泄漏,证明:闭包的变量可以访问使用,而非占据着内存空间却又无法调用的孤儿对象,觉得闭包造成内存泄漏的原因是因为ie浏览器本身存在bug,在使用完闭包后,依然回收不了闭包中引用的变量。闭包内变量是否回收决定于: 1.嵌套函数中是否使用该变量 2.嵌套函数中是否存在直接调用eval方法 3.是否使用了with表达式 详细证明
函数柯里化和反柯里化
-
什么是函数柯里化 ? 答:一种转换函数的技术,将接受多个参数的函数转换为接受单个参数的函数并且该函数的返回值是一个可以接受其余参数的新函数。 -
函数柯里化的作用是什么 ? 答:调用函数时,如果存在每次调用都相同的参数,可以避免重复传入该参数,比如比较两个变量a1,a2是否都是a,正常来说每次都要传入参数a,但是通过柯里化可以固定参数a,只传入单个参数即可比较。 -
什么是函数反柯里化 ? 答:实现一个对象调用本不属于他本身的方法,比如,可以通过函数反柯里化实现一个nodelist调用数组的forEach方法实现需求。 -
实现一个函数功能:sum(1,2,3,4…n)转化为 sum(1)(2)(3)(4)…(n) ? 答: function curry(fn){
let arr = [];
return function(){
if(arguments.length > 0){
[].push.apply(arr,arguments);
return arguments.callee;
}
else return fn(...arr);
}
}
Function.prototype.unCurry=function(){
var self=this;
return function(thisArg,...arg){
return self.apply(thisArg,arg);
}
}
原型
-
什么是原型? 答:解析1,解析2 -
什么时候会用到原型? ? 答:解析1,解析2 -
什么是原型链? ? 答:解析1,解析2 -
function Foo() {
Foo.a = function() {
console.log(1)
}
this.a = function() {
console.log(2)
}
}
Foo.prototype.a = function() {
console.log(3)
}
Foo.a = function() {
console.log(4)
}
Foo.a();
let obj = new Foo();
obj.a();
Foo.a();
-
function Person(name){
this.name = name;
};
var jack = new Person("jack");
ES5类和继承
-
通过ES5的语法实现类和继承 ? 答:
var elem = new Components("div")
elem.appendTo("body")
console.log(elem)
for(var prop in elem){
console.log(prop)
}
function Box(type){
this.super(type)
}
Function.prototype.extends = function(supClass){
function F(){}
F.prototype = supClass.prototype;
var o = this.prototype;
this.prototype = new F();
for(var porp in this.prototype){
o[prop] = this.prototype[prop]
}
this.prototype = new F();
for (var key in o){
this.prototype[key] = o[key];
}
this.prototype.constructor = this;
if(supClass.prototype.constructor!==supClass){
supClass.prototype.constructor=supClass;
}
this.prototype.super = function(){
supClass.prototype.constructor.apply(this,arguments);
}
this.prototype.superClass = supClass.prototype
this.prototype.superFn = function(fnName){
var arr = [].slice.call(arguments).slice(1);
if(supClass.prototype[fnName]) supClass.prototype[fnName].apply(this,arr)
}
}
Box.extends(Components);
Box.prototype.appendTo = function(parent){
this.superFn("appendTo",parent)
}
var a = new Box("div");
a.appendTo("body");
console.log(a)
class Component {
elem;
parent;
static cssBool = false;
constructor(type = "div") {
this.elem = document.createElement(type);
}
static setCss(str = "") {
if (this.cssBool) return true;
this.cssBool = true;
return false;
}
appendTo(parent) {
if (typeof parent === "string") parent = document.querySelector(parent);
parent.appendChild(this.elem);
this.parent = parent;
}
insertTo(parent, before = undefined) {
if (typeof parent === "string") parent = document.querySelector(parent);
if (typeof before === "string") before = document.querySelector(before);
if (!before) parent.appendChild(this.elem);
else parent.insertBefore(this.elem, before);
this.parent = parent;
}
remove() {
this.elem.remove();
this.elem = null;
}
}
class Ball extends Component {
constructor() {
super();
}
appendTo(parent) {
console.log(parent)
super.appendTo(parent)
}
}
let b = new Ball();
b.appendTo("body")
console.log(b);
function Box(type){
this.super(type);
}
Function.prototype.extends=function(supClass){
function F(){}
F.prototype=supClass.prototype;
var o=this.prototype;
this.prototype=new F();
for(var key in o){
this.prototype[key]=o[key];
}
this.prototype.constructor=this;
if(supClass.prototype.constructor!==supClass){
supClass.prototype.constructor=supClass;
}
this.prototype.super=function(){
supClass.prototype.constructor.apply(this,arguments);
}
this.prototype.superFn=function(fnName){
var arr=[].slice.call(arguments).slice(1);
if(supClass.prototype[fnName]) supClass.prototype[fnName].apply(this,arr)
}
}
Box.extends(Component);
Box.prototype.appendTo=function(parent){
this.superFn("appendTo",parent);
}
var a=new Box("div");
a.appendTo("body");
console.log(a);
var Components=(function(){
function Component(type){
if(type===undefined) type="div";
if(typeof type!=="string") throw new Error("Create Elements Error!");
Object.defineProperty(this,"elem",{writable:true,value:document.createElement(type)});
}
Object.defineProperties(Component.prototype,{
appendTo:{writable:true,value:function(parent){
if(typeof parent==="string") parent=document.querySelector(parent);
parent.appendChild(this.elem);
Object.defineProperty(this,"parent",{writable:true,value:parent});
}},
insertTo:{writable:true,value:function(parent,before){
if(typeof parent==="string") parent=document.querySelector(parent);
if(typeof before==="string") before=document.querySelector(before);
if(!before) parent.appendChild(this.elem);
else parent.insertBefore(this.elem,before);
Object.defineProperty(this,"parent",{writable:true,value:parent});
}},
remove:{writable:true,value:function(){
this.elem.remove();
this.elem=null;
}}
})
Object.defineProperties(Component,{
cssBool:{value:false,writable:true},
setCss:{value:function(str){
if(this.cssBool) return true;
if(str===undefined) str=""
this.cssBool=true;
Utils.setCss(str);
return false;
}}
})
return Component;
})()
-
CommonJS 和 RequireJS 的实现原理 ? 答: commonjs是通过module.exports导出模块,用require引入一个模块,原理:闭包 requirejs是通过define定义导出模块,用require引入模块。 define('name',[],function(){
return 'requirejs'
})
define('say',['name'].function(name){
return "my name is" + name
})
require(['say'],function(text){
console.log(text)
})
-
简述 commonJS、AMD 和 CMD ? 答: CommonJS导出模块的方法是exports,导入模块的是require,具体规范: 1)如果一个JS文件中存在exports或require,该JS文件是一个模块 2)模块内的所有代码均为隐藏代码,包括全局变量、全局函数,这些全局的内容均不应该对全局变量造成任何污染 3)如果一个模块需要暴露一些API提供给外部使用,需要通过exports导出,exports是一个空的对象,你可以为该对象添加任何需要导出的内容 4)如果一个模块需要导入其他模块,通过require实现,require是一个函数,传入模块的路径即可返回该模块导出的整个内容 AMD AMD 是 RequireJS 在推广过程中对模块定义的规范化产出。 AMD 推崇依赖前置。 CMD CMD 是 SeaJS 在推广过程中对模块定义的规范化产出。 CMD 推崇依赖就近
设计模式
-
什么是设计模式? ? 答:设计模式是一套反复使用的并且经过分类编目的代码设计经验总结。 -
设计模式有哪些? ? 答: ? GOF提出的23种设计模式,分为三大类。 ? 创建型模式,共5种,分别是工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。 ? 结构型模式,共7种,分别是适配器模式、装饰器模式、代理模式、外观模式桥接模式、组合模式、享元模式。 ? 行为型模式,共11种,分别是策略模式、模板方法模式、观察者模式、选代子模式、責任链模式、命令模式、备忘录模弌、状态模式、访问者模式、中介者模式、解释器模式。 -
工厂模式的概念是什么?它的优点和缺陷是什么? ? 答:工厂模式需要3个基本步骤,原料投入、加工过程以及成品出厂, ? 优点: ? (1)一个调用者想创建一个对象,只要知道它的名称即可。 ? (2)扩展性高,如果想增加一个产品,只要扩展一个工厂类即可。 ? (3)屏蔽产品的具体实现,调用者只需关心产品的接口。 ? 缺点: ? 每次增加一个产品时,都需要増加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定 程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。 -
什么是单例模式?为什么要使用单例模式?单例模式的优缺点是什么? ? 答: ? 单例模式用于公共数据存储,与中介者交互双方数据,在某些情况下,在处理多个模块的数据时,他们没有什么联系,但是我们想要用一个公共的部分来进行储存状态或者数据。 ? 为了保证这些模块之间能够稳定统一,那就要求这个公共部分是唯一的,各个模块之间所获取的数据与状态才能够保持一致 ? 这时候我们使用到了单例模式,顾名思义,就是单个实例。 ? 优点: ? (1)提供了对唯一实例的受控访问。 ? (2)由于在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象,单例模式无疑能够提高系统的性能。 ? (3)可以根据实际情况的需要,在单例模式的基础上扩展为双例模式和多例模式。 ? 缺点: ? (1)单例类的职责过重,里面的代码可能会过于复杂,在一定程度上违背了“单职责原则”。 ? (2)如果实例化的对象长时间不利用,系统会认为它是垃圾而进行回收,这将导致对象状态的丢失。 -
什么是代理模式? ? 答:代理( proxy)模式,即为目标对象指定代理对象,并由代理对象代替目标对象控制客户端对目标对象的访问。 -
原型模式和单例模式的区别是什么? ? 答:单例模式就是保证一个类只存在一个实例,只初始化一次,第一次完成初始化以后,在重复使用的时候,返回的都是这个实例,而不是新建一个实例。如果实例化的对象里面的属性值已经改变,就不能用单例了,只能通过原型模式重新实例化,原型模式允许多次创建实例对象。 -
组合模式的适用性指的是什么?什么时候要用到组合模式? ? 答: ? 组合模式是表示对象的“部分-整体”层次结构的一种设计模式;组合模式将对象组合成树状结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。 ? 使用组合模式的情况: ? (1)当想表示对象的“部分-整体”层次结构(树状结构)时可以使用组合模式 ? (2)在希望用户忽略组合对象与单个对象的不同并且统一地使用组合结构中的所有对象时使用组合模式。 -
用 JavaScript 实现观察者模式 ? 答: function BusinessOne(name){
this.name = name;
this.subscribers = new Array();
}
BusinessOne.prototype.delive = function(news){
var self = this;
this.subscribers.forEach(
function(fn){
fn(news,self);
}
)
}
Function.prototype.subscribe = function(publisher){
var that = this;
var alreadyExists = publisher.subscribers.some(
function(el){
if(el == that){
return;
}
}
);
if(!alreadyExists){
publisher.subscribers.push(that);
}
return this;
}
Function.prototype.unsubscribe = function(publisher){
var that = this;
publisher.subscribers = publisher.subscribers.filter(
function(el){
if(el !== that){
return el;
}
}
);
return this;
};
Gulp
-
什么是gulp? ? 答:Gulp 是基于node.js的一个前端自动化构建工具,开发这可以使用它构建自动化工作流程,即前端集成开发环境。 使用gulp你可以简化工作量,让你把重点放在功能的开发上,从而提高你的开发效率和工作质量。 例如:你可以用gulp可以网页自动刷新,和MVVM开发模式很相似,如果你对vue.js有所了解的话,那么你一定不会陌生。你也可以使用gulp对sass进行预处理、代码检测、图片优化压缩、只需要一个简单的指令就能全部完成。 -
webpack与grunt、gulp的不同? ? 答: ? 三者都是前端构建工具,grunt和gulp在早期比较流行,现在webpack相对来说比较主流,不过一些轻量化的任务还是会用gulp来处理,比如单独打包CSS文件等。 ? grunt和gulp是基于任务和流(Task、Stream)的。类似jQuery,找到一个(或一类)文件,对其做一系列链式操作,更新流上的数据, 整条链式操作构成了一个任务,多个任务就构成了整个web的构建流程。 ? webpack是基于入口的。webpack会自动地递归解析入口所需要加载的所有资源文件,然后用不同的Loader来处理不同的文件,用Plugin来扩展webpack功能。 总结:
-
从构建思路来说 gulp和grunt需要开发者将整个前端构建过程拆分成多个Task ,并合理控制所有Task 的调用关系 webpack需要开发者找到入口,并需要清楚对于不同的资源应该使用什么Loader做何种解析和加工 -
对于知识背景来说 gulp更像后端开发者的思路,需要对于整个流程了如指掌 webpack更倾向于前端开发者的思路 -
如何实现css,js的代码压缩? 答:应用gulp的gulp-uglify,gulp-minify-css模块完成
|