更多课程 选择中心


Web培训

400-996-5531

Web培训

web前端面试题:JavaScript这几个点一定要知道


1.函数的3种定义方法

1.1 函数声明 //ES5function getSum(){}function (){}//匿名函数//ES6()=>{}//如果{}内容只有一行{}和return关键字可省, 1.2 函数表达式(函数字面量) //ES5var sum=function getSum(){}//ES6let sum=()=>{}//如果{}内容只有一行{}和return关键字可省, 1.3 构造函数 var sum=new GetSum(num1,num2) 1.4 三种方法的对比

1.函数声明有预解析,而且函数声明的优先级高于变量;

2.使用Function构造函数定义函数的方式是一个函数表达式,这种方式会导致解析两次代码,影响性能。第一次解析常规的Java代码,第二次解析传入构造函数的字符串

2.ES5中函数的4种调用

在ES5中函数内容的this指向和调用方法有关

2.1 函数调用模式

包括函数名()和匿名函数调用,this指向window

function getSum() { console.log(this) //window } getSum() (function() { console.log(this) //window })() var getSum=function() { console.log(this) //window } getSum()2.2 方法调用

对象.方法名(),this指向对象

var objList = { name: 'methods', getSum: function() { console.log(this) //objList对象 }}objList.getSum()2.3 构造器调用

new 构造函数名(),this指向构造函数

function Person() { console.log(this); //指向构造函数Person}var personOne = new Person();2.4 间接调用

利用call和apply来实现,this就是call和apply对应的第一个参数,如果不传值或者第一个值为null,undefined时this指向window

function foo() { console.log(this);}foo.apply('我是apply改变的this值');//我是apply改变的this值foo.call('我是call改变的this值');//我是call改变的this值3.ES6中函数的调用

箭头函数不可以当作构造函数使用,也就是不能用new命令实例化一个对象,否则会抛出一个错误

箭头函数的this是和定义时有关和调用无关

调用就是函数调用模式

(() => { console.log(this)//window})()let arrowFun = () => { console.log(this)//window}arrowFun()let arrowObj = { arrFun: function() { (() => { console.log(this)//arrowObj })() } } arrowObj.arrFun(); 4.call,apply和bind

1.IE5之前不支持call和apply,bind是ES5出来的;

2.call和apply可以调用函数,改变this,实现继承和借用别的对象的方法;

4.1 call和apply定义

调用方法,用一个对象替换掉另一个对象(this)

对象.call(新this对象,实参1,实参2,实参3.....)

对象.apply(新this对象,[实参1,实参2,实参3.....])

4.2 call和apply用法

1.间接调用函数,改变作用域的this值

2.劫持其他对象的方法

var foo = { name:"张三", logName:function(){ console.log(this.name); }}var bar={ name:"李四"};foo.logName.call(bar);//李四实质是call改变了foo的this指向为bar,并调用该函数

3.两个函数实现继承

function Animal(name){ this.name = name; this.showName = function(){ console.log(this.name); } } function Cat(name){ Animal.call(this, name); } var cat = new Cat("Black Cat"); cat.showName(); //Black Cat

4.为类数组(arguments和nodeList)添加数组方法push,pop

(function(){ Array.prototype.push.call(arguments,'王五'); console.log(arguments);//['张三','李四','王五']})('张三','李四')

5.合并数组

let arr1=[1,2,3]; let arr2=[4,5,6]; Array.prototype.push.apply(arr1,arr2); //将arr2合并到了arr1中

6.求数组最大值

Math.max.apply(null,arr)

7.判断字符类型

Object.prototype.toString.call({})4.3 bind

bind是function的一个函数扩展方法,bind以后代码重新绑定了func内部的this指向,不会调用方法,不兼容IE8

var name = '李四' var foo = { name: "张三", logName: function(age) { console.log(this.name, age); } } var fooNew = foo.logName; var fooNewBind = foo.logName.bind(foo); fooNew(10)//李四,10 fooNewBind(11)//张三,11 因为bind改变了fooNewBind里面的this指向5.JS常见的四种设计模式5.1 工厂模式

简单的工厂模式可以理解为解决多个相似的问题;

function CreatePerson(name,age,sex) { var obj = new Object(); obj.name = ame; obj.age = age; obj.sex = sex; obj.sayName = function(){ return this.name; } return obj;}var p1 = new CreatePerson("longen",'28','男');var p2 = new CreatePerson("tugenhua",'27','女');console.log(p1.name); // longenconsole.log(p1.age); // 28console.log(p1.sex); // 男console.log(p1.sayName()); // longenconsole.log(p2.name); // tugenhuaconsole.log(p2.age); // 27console.log(p2.sex); // 女console.log(p2.sayName()); // tugenhua 5.2单例模式

只能被实例化(构造函数给实例添加属性与方法)一次

// 单体模式var Singleton = function(name){ this.name = ame;};Singleton.prototype.getName = function(){ return this.name;}// 获取实例对象var getInstance = (function() { var instance = null; return function(name) { if(!instance) {//相当于一个一次性阀门,只能实例化一次 instance = new Singleton(name); } return instance; }})();// 测试单体模式的实例,所以a===bvar a = getInstance("aa");var b = getInstance("bb"); 5.3 沙箱模式

将一些函数放到自执行函数里面,但要用闭包暴露接口,用变量接收暴露的接口,再调用里面的值,否则无法使用里面的值

let sandboxModel=(function(){ function sayName(){}; function sayAge(){}; return{ sayName:sayName, sayAge:sayAge }})()5.4 发布者订阅模式

就例如如我们关注了某一个公众号,然后他对应的有新的消息就会给你推送,

//发布者与订阅模式 var shoeObj = {}; // 定义发布者 shoeObj.list = []; // 缓存列表 存放订阅者回调函数 // 增加订阅者 shoeObj.listen = function(fn) { shoeObj.list.push(fn); // 订阅消息添加到缓存列表 } // 发布消息 shoeObj.trigger = function() { for (var i = 0, fn; fn = this.list[i++];) { fn.apply(this, arguments);//第一个参数只是改变fn的this, } } // 小红订阅如下消息 shoeObj.listen(function(color, size) { console.log("颜色是:" + color); console.log("尺码是:" + size); }); // 小花订阅如下消息 shoeObj.listen(function(color, size) { console.log("再次打印颜色是:" + color); console.log("再次打印尺码是:" + size); }); shoeObj.trigger("红色", 40); shoeObj.trigger("黑色", 42);

代码实现逻辑是用数组存贮订阅者, 发布者回调函数里面通知的方式是遍历订阅者数组,并将发布者内容传入订阅者数组

6.原型链

6.1 定义

对象继承属性的一个链条

6.2构造函数,实例与原型对象的关系


var Person = function (name) { this.name = name; }//person是构造函数var o3personTwo = new Person('personTwo')//personTwo是实例


原型对象都有一个默认的constructor属性指向构造函数

6.3 创建实例的方法

1.字面量

let obj={'name':'张三'}

2.Object构造函数创建

let Obj=new Object()Obj.name='张三'

3.使用工厂模式创建对象

function createPerson(name){ var o = new Object(); o.name = name; }; return o; }var person1 = createPerson('张三');

4.使用构造函数创建对象

function Person(name){ this.name = name;}var person1 = new Person('张三');6.4 ew运算符

1.创了一个新对象;

2.this指向构造函数;

3.构造函数有返回,会替换new出来的对象,如果没有就是new出来的对象

4.手动封装一个new运算符

var new2 = function (func) { var o = Object.create(func.prototype); //创建对象 var k = func.call(o); //改变this指向,把结果付给k if (typeof k === 'object') { //判断k的类型是不是对象 return k; //是,返回k } else { return o; //不是返回返回构造函数的执行结果 }} 6.5 对象的原型链


7.继承的方式

JS是一门弱类型动态语言,封装和继承是他的两大特性

7.1原型链继承

将父类的实例作为子类的原型

1.代码实现

定义父类:

// 定义一个动物类function Animal (name) { // 属性 this.name = name || 'Animal'; // 实例方法 this.sleep = function(){ console.log(this.name + '正在睡觉!'); }}// 原型方法Animal.prototype.eat = function(food) { console.log(this.name + '正在吃:' + food);};

子类:

function Cat(){ }Cat.prototype = new Animal();Cat.prototype.name = 'cat';// Test Codevar cat = new Cat();console.log(cat.name);//catconsole.log(cat.eat('fish'));//cat正在吃:fish undefinedconsole.log(cat.sleep());//cat正在睡觉! undefinedconsole.log(cat instanceof Animal); //true console.log(cat instanceof Cat); //true

2.优缺点

简单易于实现,但是要想为子类新增属性和方法,必须要在new Animal()这样的语句之后执行,无法实现多继承

7.2 构造继承

实质是利用call来改变Cat中的this指向

1.代码实现

子类:

function Cat(name){ Animal.call(this); this.name = name || 'Tom';}

2.优缺点

可以实现多继承,不能继承原型属性/方法

7.3 实例继承

为父类实例添加新特性,作为子类实例返回

1.代码实现

子类

function Cat(name){ var instance = new Animal(); instance.name = name || 'Tom'; return instance;}

2.优缺点

不限制调用方式,但不能实现多继承

7.4 拷贝继承

将父类的属性和方法拷贝一份到子类中

1.子类:

function Cat(name){ var animal = new Animal(); for(var p in animal){ Cat.prototype[p] = animal[p]; } Cat.prototype.name = name || 'Tom';}

2.优缺点

支持多继承,但是效率低占用内存

7.5 组合继承

通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用

1.子类:

function Cat(name){ Animal.call(this); this.name = name || 'Tom';}Cat.prototype = new Animal();Cat.prototype.constructor = Cat;7.6 寄生组合继承function Cat(name){ Animal.call(this); this.name = name || 'Tom';}(function(){ // 创建一个没有实例方法的类 var Super = function(){}; Super.prototype = Animal.prototype; //将实例作为子类的原型 Cat.prototype = new Super();})();7.7 ES6的extends继承

ES6 的继承机制是先创造父类的实例对象this(所以必须先调用super方法),然后再用子类的构造函数修改this,链接描述

class ColorPoint extends Point { constructor(x, y, color) { super(x, y); // 调用父类的constructor(x, y) this.color = color; } toString() { return this.color + ' ' + super.toString(); // 调用父类的toString() }}

免责声明:内容和图片源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容

预约申请免费试听课

填写下面表单即可预约申请免费试听! 怕学不会?助教全程陪读,随时解惑!担心就业?一地学习,可全国推荐就业!

上一篇:盘点web前端必知的20道面试题
下一篇:参加web前端面试时容易犯的错误有哪些?

web前端面试题:JavaScript这几个点一定要知道

Copyright © 2023 Tedu.cn All Rights Reserved 京ICP备08000853号-56 京公网安备 11010802029508号 达内时代科技集团有限公司 版权所有

选择城市和中心
黑龙江省

吉林省

河北省

贵州省

云南省

广西省

海南省