前端JS初级面试题二

目录

  1. 传统事件绑定和符合W3C标准的事件绑定有什么区别?
  2. IE 和标准下有哪些兼容性的写法
  3. JavaScript 如何实现继承?
  4. JavaScript 创建对象的几种方式?
  5. this指针,闭包,作用域
  6. 如何阻止事件冒泡和默认事件
  7. JavaScript 的同源策略
  8. JavaScript是一门什么样的语言,它有哪些特点?
  9. 如何检测数组的数据类型?
  10. 添加 删除 替换 插入到某个节点的方法
  11. javascript的本地对象,内置对象和宿主对象
  12. 已知ID的Input输入框,希望获取这个输入框的输入值,怎么做?(不使用第三方框架)
  13. 希望获取到页面中所有的checkbox怎么做?(不使用第三方框架)
  14. 设置一个已知ID的DIV的html内容为xxxx,字体颜色设置为黑色(不使用第三方框架)
  15. 当一个DOM节点被点击时候,我们希望能够执行一个函数,应该怎么做?
  16. Javascript的事件流模型都有什么?
  17. 列举浏览器对象模型BOM里常用的至少4个对象,并列举window对象的常用方法至少5个
  18. 简述创建函数的几种方式
  19. iframe的优缺点?
  20. 请你谈谈Cookie的弊端?
  21. js延迟加载的方式有哪些?
  22. documen.write和 innerHTML 的区别?
  23. 哪些操作会造成内存泄漏?
  24. 解释jsonp的原理,以及为什么不是真正的ajax
  25. javascript 中的垃圾回收机制?
  26. BOM对象有哪些,列举window对象?
  27. 简述readyonly与disabled的区别?
  28. 为什么扩展javascript内置对象不是好的做法?

1. 传统事件绑定和符合W3C标准的事件绑定有什么区别?

传统事件绑定

<div onclick="">123</div>
div1.onclick = function(){};
<button onmouseover=""></button>

注意:
如果给同一个元素绑定了两次或多次相同类型的事件,那么后面的绑定会覆盖前面的绑定
(不支持DOM事件流 :事件捕获阶段=>目标元素阶段=>事件冒泡阶段)

符合W3C标准的事件绑定的方式 addEventListener/attachEvent
  • 非IE浏览器:addEventListener / removeEventListener

    所有的DOM节点都包含这两个方法,并且他们都接受三个参数:
    1.事件类型
    2.事件处理方法
    3.布尔参数,默认false
    (true捕获阶段调用事件处理方法;false冒泡阶段调用事件处理方法。)

    //addEventListener
    let box = document.querySelector('.box')
    box.addEventListener('click',function(){
      console.log('box clicked...')
    })
    
    
    function xxx(){console.log('box clicked...')}
    box.addEventListener('click',xxx)   //添加事件
    box.removeEventListener('click',xxx)   //删除事件
    

    注意:
    如果给同一个元素绑定了两次或多次相同类型的事件,绑定依次触发
    支持DOM事件流
    进行事件绑定不需要on前缀

  • IE浏览器:attachEvent / detachEvent

    这两个方法都接受两个相同的参数。
    1.事件处理程序名称
    2.事件处理程序方法

    IE只支持事件冒泡
    let box = document.querySelector('.box')
    function xxx(){console.log('box clicked...')}
    box.attachEvent('onclick',xxx) // 添加事件
    box.detachEvent('onclick',xxx) // 删除事件
    

    注意:
    进行事件类型传参需要带上on前缀
    这种方式只支持事件冒泡,不支持事件捕获

兼容性:
attachEvent——兼容:IE7、IE8;不兼容firefox、chrome、IE9、IE10、IE11、safari、opera
addEventListener——兼容:firefox、chrome、IE、safari、opera;不兼容IE7、IE8

推荐:JS事件绑定 事件冒泡与捕获 事件代理

2. IE 和标准下有哪些兼容性的写法

ev = event || window.event 获取触发事件的对象
var target = ev.srcElement || ev.target 获取事件的源对象
document.documentElement.clientWidth/Height || document.body.clientWidth/Height 获取浏览器视窗尺寸

3. JavaScript 如何实现继承?

😁(1) 原型链继承

function Animals() {
    this.age = 1;
}
Animals.prototype.getAge = function(){
    return this.age;
};

function Cat() {
    this.name = '咪咪'
}

// 继承,用 Animals 类型的一个实例来重写 Cat 类型的原型对象
// 这一步,让Cat的对象拥有了Animals对象的属性,方法
Cat.prototype = new Animals(); 
var cat = new Cat();
console.log(cat.name) // '咪咪'
console.log(cat.age)  // 1
console.log(cat.getAge()) // 1

特点:

  • 非常纯粹的继承关系,实例是子类的实例,也是父类的实例
  • 父类新增原型方法/原型属性,子类都能访问到
  • 简单,易于实现

缺点:

  • 要想为子类新增属性和方法,必须要在new Cat()这样的语句之后执行,不能放到构造器中
  • 无法实现多继承
  • 来自原型对象的引用属性被所有实例共享
  • 创建子类实例时,无法向父类构造函数传参

😁(2) 借用构造函数继承(也称伪造对象或经典继承)
在子类型构造函数的内部调用超类型构造函数;使用 apply()call() 方法将父对象的构造函数绑定在子对象上

function Animals() {
    // 定义引用类型值属性
    this.colors = ["red","green","blue"];
}
function Cat() {
    // 继承 Animals,在这里还可以给超类型构造函数传参
    Animals.call(this);
}

var cat1 = new Cat();
cat1.colors.push('yellow');
console.log(cat1.colors);  //  ["red", "green", "blue", "yellow"]

var cat2 = new Cat();
console.log(cat2.colors); // ["red", "green", "blue"]

通过使用 apply() 或 call() 方法,我们实际上是在将要创建的 Cat 实例的环境下调用了 Animals 构造函数。这样一来,就会在新 Cat 对象上执行 Animals() 函数中定义的所有对象初始化代码。结果 Cat 的每个实例就都会具有自己的 colors 属性的副本了

特点:

  • 解决了原型链继承中,子类实例共享父类引用属性的问题
  • 创建子类实例时,可以向父类传递参数
  • 可以实现多继承(call多个父类对象)

缺点:

  • 实例并不是父类的实例,只是子类的实例
  • 只能继承父类的实例属性和方法,不能继承原型属性/方法
  • 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能

😁(3)原型+构造函数组合继承 (也称伪经典继承)
将原型链和借用构造函数的技术组合到一块。使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。这样,既通过在原型上定义方法实现了函数复用,又能够保证每个实例都有自己的属性。

function Animals(age) {
    this.age = age;
    this.colors = ["red","green","blue"];
}
Animals.prototype.getAge = function(){
    return this.age;
};

function Cat(age, name) {
    // 借用构造函数方式继承属性
    Animals.call(this,age);
    this.name = name;
}

// 原型链方式继承方法
Cat.prototype = new Animals(); 
Cat.prototype.constructor = Cat;
Cat.prototype.getName = function(){
    return this.name;
};

var cat1 = new Cat(1,"咪咪");
cat1.colors.push("yellow");
console.log(cat1.colors);    //  ["red", "green", "blue", "yellow"]
console.log(cat1.getAge());  //  1
console.log(cat1.getName()); //  咪咪

var cat2 = new Cat(2, "小白")
console.log(cat2.colors);    // ["red", "green", "blue"]
console.log(cat2.getAge());  // 2
console.log(cat2.getName()); // 小白

特点:

  • 组合继承避免了原型链和借用构造函数的缺陷,融合了它们的优点(可以继承实例属性/方法,也可以继承原型属性/方法),成为 javascript 中最常用的继承模式。
  • 既是子类的实例,也是父类的实例
  • 不存在引用属性共享问题
  • 可传参
  • 函数可复用
  • 使用 instanceof 操作符和 isPrototype() 方法也能够用于识别基于组合继承创建的对象。

缺点:

  • 无论在什么情况下,都会调用两次超类型构造函数:一次是在创建子类型原型的时候,另一次是在子类型构造函数内部。

😁(4)原型式继承
使用 Object.create() 方法实现原型式继承

这个方法接收两个参数:一是用作新对象原型的对象和一个为新对象定义额外属性的对象。在传入一个参数的情况下,此方法与 object() 方法作用一致。 在传入第二个参数的情况下,指定的任何属性都会覆盖原型对象上的同名属性。

var person = {
            name: "luochen",
            colors: ["red","green","blue"]
}; 
var anotherPerson1 = Object.create(person,{
            name: {
                    value: "tom"
            }
});
var anotherPerson2 = Object.create(person,{
            name: {
                    value: "jerry"
            }
});
anotherPerson1.colors.push("purple");
alert(anotherPerson1.name);     // "tom"
alert(anotherPerson2.name);     // "jerry"
alert(anotherPerson1.colors);    // "red,green,blue,purple"
alert(anotherPerson2.colors);    // "red,green,bule,purple";

只是想让一个对象与另一个对象类似的情况下,原型式继承是完全可以胜任的。
缺点: 包含引用类型值的属性始终都会共享相应的值

😁(5)寄生式继承

// 创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后返回这个对象
function createPerson(original){
    // 通过 Object.create() 函数创建一个新对象
    var clone = Object.create(original);
    // 增强这个对象
    clone.sayGood = function(){           
        alert("hello world!!!");
    };
    // 返回这个对象 
    return clone;                          
}

在主要考虑对象而不是自定义类型和构造函数的情况下,寄生式继承也是一种有用的模式。
缺点:

  • 做不到函数复用,都是每次创建对象都会创建一遍方法,内存占用大

😁(6) 寄生组合式继承
通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型

function Animals(age) {
    this.age = age;
    this.colors = ["red","green","blue"];
}
Animals.prototype.getAge = function(){
    return this.age;
};

function Cat(age, name) {
    // 借用构造函数方式继承属性
    Animals.call(this,age);
    this.name = name;
}

// 创建超类型原型的一个副本
var animalsCopy = Object.create(Animals.prototype);
// 重设因重写原型而失去的默认的 constructor 属性
animalsCopy.constructor = Cat;
// 将新创建的对象赋值给子类型的原型
Cat.prototype = animalsCopy;

Cat.prototype.getName = function() {
    return this.name;
}

var cat1 = new Cat(1,"咪咪");
cat1.colors.push("yellow");
console.log(cat1.colors);    //  ["red", "green", "blue", "yellow"]
console.log(cat1.getAge());  //  1
console.log(cat1.getName()); //  咪咪

var cat2 = new Cat(2, "小白")
console.log(cat2.colors);    // ["red", "green", "blue"]
console.log(cat2.getAge());  // 2
console.log(cat2.getName()); // 小白

这个例子的高效率体现在它只调用一次 Animals 构造函数,并且因此避免了在 Cat.prototype上面创建不必要,多余的属性。与此同时,原型链还能保持不变;因此还能够正常使用 instance 操作符isPrototype() 方法
缺点:代码比较复杂

4. JavaScript 创建对象的几种方式?

😊(1) 使用对象字面量创建

var Person = {
  name:'小白',
  age:23,
  say: function() {
    console.log('我是:' + this.name); 
  }
}
Person.say();  // 我是:小白

😊(2) 使用Object 构造函数创建

var Person = new Object();
Person.name = '小白';
Person.age = 23;
Person.say = function() {
	console.log('我是:' + this.name); 
}
Person.say();  // 我是:小白

推荐使用对象字面量{}形式创建,效率比较高

😊(3) 使用工厂模式创建对象

function createPerson(name, age, job) {
  var o = new Object();
  o.name = name;
  o.age = age;
  o.say = function() {
    console.log('say' )
  }
  return o;
}

var person1 = createPerson('name',29)
person1.say();

创建createPerson的时候,返回的是一个对象,那么我们就无法判断返回的对象究竟是一个什么样的类型。于是出现了使用构造函数创建对象。

😊(4) 使用构造函数创建对象

function Person(name, age) {
  this.name = name;
  this.age = age;
}
Person.prototype.say = function() {
  console.log(this.name + ':' + this.age + '岁');
};

var person1 = new Person('小白', '12');
person1.say();     // 小白:12岁
var person2 =  new Person('小花', '11');
person2.say();     // 小花:11岁

这种方式与工厂模式相比:

  • 没有显示地构建对象
  • 直接将属性和方法赋给了this对象
  • 没有return语句
  • 可以通过instanceof识别对象的类型

使用内置对象创建对象
如:var str = new String("实例初始化String");
var str1 = "直接赋值的String";
var func = new Function("x","alert(x)");// 示例初始化func
var obj = new Object(); // 示例初始化一个Object

5. this指针,闭包,作用域

this: 指向调用上下文
闭包: 内层作用域可以访问外层作用域的变量
作用域: 定义一个函数就开辟了一个局部作用域,整个JS执行环境有一个全局作用域

6. 如何阻止事件冒泡和默认事件

防止冒泡和捕获
w3c的方法是e.stopPropagation(),IE则是使用e.cancelBubble = true

取消默认事件
w3c的方法是e.preventDefault(),IE则是使用e.returnValue = false

7. JavaScript 的同源策略

同源策略

  • ajax 请求时,浏览器要求当前网页和server必须同源(安全)
  • 同源:协议,域名,端口,三者必须一致

详情请点击查看另一篇博客 同源策略和跨域 (ノ°▽°)ノ 冲鸭!征服她!!!

8. JavaScript是一门什么样的语言,它有哪些特点?

js就是面向对象的弱类型语言
语言特性:面向对象(要掌握创建对象的多种方式,继承的多种方式、原型链),动态/弱类型语言

动态语言的特性
var num=10;//num是一个数字类型
num="jim";//此时num又变成一个字符串类型
//我们把一个变量用来保存不同数据类型的语言称之为一个动态语言,或者说是一个弱类型语言

9. 如何检测数组的数据类型?

检测数组的几种方式:

Array.isArray([1,2,3]); // true   (ES5)
toString.call([]);      // "[object Array]"
var arr = [];
arr.constructor;       // ƒ Array() { [native code] }   不推荐使用,因为constructor是可以修改的。
[] instanceof Array    // true

JS基础知识:变量的类型和计算

10. 添加 删除 替换 插入到某个节点的方法

原生:
appendChild() // 添加
removeChild() // 删除节点
replaceChild(新节点,旧节点) // 替换(前替换后)
insertBefore(插入节点,被插节点) // 插入(前插后)

jq:
// 添加
append()(旧节点添加新节点后面)
appendTo()(新节点添加到旧节点后面)
prepend()(旧节点添加新节点的前面)
prependTo() (新节点添加到旧节点的前面)

remove()// 删除
empty() // 清空

// 插入
after() // 旧节点后面插入 新节点
before() // 旧节点前面插入 新节点
insertAfter() // 新节点插到旧节点后
insertBefore() // 新节点插到旧节点前

replaceWith() // 替换

11. javascript的本地对象,内置对象和宿主对象

本地对象array obj regexp等可以new实例化
内置对象gload Math 等不可以实例化的
宿主对象为浏览器自带的document, window

12. 已知ID的Input输入框,希望获取这个输入框的输入值,怎么做?(不使用第三方框架)

	document.getElementById(ID).value

13. 希望获取到页面中所有的checkbox怎么做?(不使用第三方框架)

var domList = document.getElementsByTagName(‘input’)
var checkBoxList = [];
var len = domList.length;  //缓存到局部变量
while (len--) {  //使用while的效率会比for循环更高
  if (domList[len].type == ‘checkbox’) {
      checkBoxList.push(domList[len]);
  }
}

14. 设置一个已知ID的DIV的html内容为xxxx,字体颜色设置为黑色(不使用第三方框架)

var dom = document.getElementById(ID);
dom.innerHTML = “xxxx”
dom.style.color = “#000

15. 当一个DOM节点被点击时候,我们希望能够执行一个函数,应该怎么做?

直接在DOM里绑定事件: <div onclick=”test()”></div>
在JS里通过onclick绑定: xxx.onclick = test
通过事件添加进行绑定: addEventListener(xxx, ‘click’, test)

16. Javascript的事件流模型都有什么?

事件冒泡: 事件开始由最具体的元素接受,然后逐级向上传播
事件捕捉: 事件由最不具体的节点先接收,然后逐级向下,一直到最具体的
DOM事件流: 三个阶段:事件捕捉,目标阶段,事件冒泡

17. 列举浏览器对象模型BOM里常用的至少4个对象,并列举window对象的常用方法至少5个

对象:window, document, location, screen, history, navigator
方法: alert(), confirm(), prompt(), open(), close()

18. 简述创建函数的几种方式

第一种(函数声明):

function sum1(num1,num2){
   return num1+num2;
}

第二种(函数表达式)

var sum2 = function(num1,num2){
   return num1+num2;
}

第三种(函数对象方式):

var sum3 = new Function("num1","num2","return num1+num2");

19. iframe的优缺点?

优点:

  1. 解决加载缓慢的第三方内容如图标和广告等的加载问题
  2. Security sandbox
  3. 并行加载脚本

缺点:

  1. iframe会阻塞主页面的Onload事件
  2. 即时内容为空,加载也需要时间
  3. 没有语意

20. 请你谈谈Cookie的弊端?

缺点:

  1. Cookie数量和长度的限制。每个domain最多只能有20条cookie,每个cookie长度不能超过4KB,否则会被截掉。
  2. 安全性问题。如果cookie被人拦截了,那人就可以取得所有的session信息。即使加密也与事无补,因为拦截者并不需要知道cookie的意义,他只要原样转发cookie就可以达到目的了。
  3. 有些状态不可能保存在客户端。例如,为了防止重复提交表单,我们需要在服务器端保存一个计数器。如果我们把这个计数器保存在客户端,那么它起不到任何作用。

更多详情,请点击我的这篇博客查看:٩(๑❛ᴗ❛๑)۶
cookie localStorage sessionStorage (¦3」∠) 看完你居然就懂了!!!

21. js延迟加载的方式有哪些?

  1. defer和async
  2. 动态创建DOM方式(创建script,插入到DOM中,加载完毕后callBack)
  3. 按需异步载入js

22. documen.write和 innerHTML 的区别?

  • document.write只能重绘整个页面
  • innerHTML可以重绘页面的一部分

23. 哪些操作会造成内存泄漏?

内存泄漏指任何对象在您不再拥有或需要它之后仍然存在。

垃圾回收器定期扫描对象,并计算引用了每个对象的其他对象的数量。如果一个对象的引用数量为 0(没有其他对象引用过该对象),或对该对象的惟一引用是循环的,那么该对象的内存即可回收。

造成内存泄露的操作有:

  1. setTimeout的第一个参数使用字符串而非函数的话,会引发内存泄漏。
  2. 闭包
  3. 控制台日志
  4. 循环(在两个对象彼此引用且彼此保留时,就会产生一个循环)

24. 解释jsonp的原理,以及为什么不是真正的ajax

JSONP:
动态创建script标签,回调函数
jsonp可以用来解决跨域问题,详情请点击查看:同源策略和跨域 (ノ°▽°)ノ 冲鸭!征服她!!!

Ajax:
Ajax是页面无刷新请求数据操作
Ajax, jQuery ajax, fetch,axios ヾ(⌐■_■)ノ看完 你就明白了~~

25. javascript 中的垃圾回收机制?

  • 在Javascript中,如果一个对象不再被引用,那么这个对象就会被GC回收。
  • 如果两个对象互相引用,而不再 被第3者所引用,那么这两个互相引用的对象也会被回收。
  • 因为函数a被b引用,b又被a外的c引用,这就是为什么 函数a执行后不会被回收的原因。

26. BOM对象有哪些,列举window对象?

  • window对象,是JS的最顶层对象,其他的BOM对象都是window对象的属性;
  • document对象,文档对象;
  • location对象,浏览器当前URL信息;
  • navigator对象,浏览器本身信息;
  • screen对象,客户端屏幕信息;
  • history对象,浏览器访问历史信息;

27. 简述readyonly与disabled的区别

ReadOnlyDisabled的作用是使用户不能够更改表单域中的内容.

区别:

  • Readonly只针对input(text/password)textarea有效,而disabled对于所有的表单元素有效,包括select,radio,checkbox,button等。
  • 在表单元素使用了disabled后,我们将表单以POST或者GET的方式提交的话,这个元素的值不会被传递出去,而readonly会将该值传递出去

28. 为什么扩展javascript内置对象不是好的做法?

因为你不知道哪一天浏览器或javascript本身就会实现这个方法,而且和你扩展的实现有不一致的表现。到时候你的javascript代码可能已经在无数个页面中执行了数年,而浏览器的实现导致所有使用扩展原型的代码都崩溃了。。。

在这里插入图片描述

发布了91 篇原创文章 · 获赞 417 · 访问量 7万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 游动-白 设计师: 上身试试

分享到微信朋友圈

×

扫一扫,手机浏览