caoruiy‘s blog

Wisdom outweighs any wealth

[笔记]前端笔试问题汇总-JavaScript

1. 原型和原型链( property__proto__)

参考:MDN-继承与原型链 | JS的prototype__proto__

2. new 操作的实质

function Type(){}
var a = {};
// 想要满足:a instanceof Type == true
// 可以:
a = new Type();
// 当然,new操作,等价于:
a.__proto__ = Type.property;
Type.call(a);

3. 遍历对象本身的属性:hasOwnProperty

hasOwnProperty 用来判断方法或属性是来自原对象本身还是原型链

function Type(){
    this.a = 'a';
}
Type.property.b='b';

var a = new Type();
a.hasOwnProperty('a');// true
a.hasOwnProperty('b');// false

4. delete 删除对象属性

参考:MDN-deletee操作符

  1. delete只是断开了属性和对象的联系,并不会去操作对象中的属性
  2. delete只能删除自有属性,而不能删除继承属性
  3. 如果你删除的属性在对象上不存在,那么delete将不会起作用,但仍会返回true
  4. var, let并 const 创建的属性, delete操作不能删除。其原因在于全局属性不可配置
  5. 对于所有情况都是true,除非属性是一个自己的不可配置属性,在这种情况下,非严格模式返回 false。
var a = {a:'a', b:'b', c:'c'};
console.log(a); // Object {a: "a", b: "b", c: "c"}
// delete
delete a.b;
console.log(a);// Object {a: "a", c: "c"}

// 不可配置属性,不能删除
var Employee = {};
Object.defineProperty(Employee, 'name', {configurable: false});
console.log(delete Employee.name);  // returns false

// 全局属性不可配置
var nameOther = 'XYZ';
Object.getOwnPropertyDescriptor(window, 'nameOther');
// 输出:Object {value: "XYZ", writable: true, enumerable: true, configurable: false}

5. this的使用场景和含义

参考:MDN-this

归根到底,this指向运行时的调用者;

具体来说:
1. 做函数使用,非严格模式下,函数中的this代表全局对象(Global)(如:浏览器:window,node.js:global); 在严格模式下,为undefined
2. 做对象使用,指向对象本身
3. 做构造函数使用,指向新生成的对象
4. 在call 和 apply 中使用,指向传递的this关键字
5. DOM事件处理函数中的 this,当函数被用作事件处理函数时,它的this指向触发事件的元素(一些浏览器在使用非addEventListener的函数动态添加监听函数时不遵守这个约定)。

function Foo(){console.log(this);}
Foo();// this 指向 window
new Foo();// this 指向新生成对象
a = {fun:Foo}; a.fun(); // this 指向 a 对象
Foo.call(this);// this 指向call中传递的this

当然,也可以为this指定具体的引用,使用 Function.property.bind方法 :

function Foo(){console.log(this);}
var g = Foo.bind({a:2});
g();// this 将永远指向 {a:2}

6. 移动端触摸事件和click事件

早先的移动端页面存在双击放大缩小的功能,为了和click事件做区分,click事件有300ms的延迟,如果300ms内第二次点击,则触发放大缩小,否则触发click事件。

写了一个DEMO测试下,发现:touch事件和click事件的触发顺序是:touchstart -> touchend -> click ; 如果触摸移动:touchstart -> touchmove -> touchend

7. 浏览器事件冒泡

  1. 不是所有事件都可以冒泡,其中 blur、focus、load、unload不能冒泡
  2. 冒泡由当前原始向根目录传递,捕获由根目录向目标元素传递
  3. 阻止冒泡的方法:e.stopPropagation() 和 e.cancelBubble = false;
  4. addEventListener(event, callback, true/false ),第三个参数:true表示捕获,false 表示冒泡,默认为false,表示冒泡。

冒泡/捕获DEMO示例

比如有 body -> div1 -> div2 -> div3 -> div4 四个div,在div2上阻止冒泡。

在冒泡阶段,div4 -> div3 -> div2
在捕获阶段:div1 -> div2

8. Array.property.splice(index, length, replace)

数组的替换:

var arr = [0,1,2,3,4,5];
arr.splice(1,2,'x'); // 返回: [1, 2]
console.log(arr); // [0, "x", 3, 4, 5] 

9.浅拷贝与深拷贝

概念:浅拷贝是指:对拷贝的对象只是拷贝了对象的引用,实际上在内存中,还指向统一内存地址。对拷贝的对象进行修改还会影响到原对象。深拷贝:则是完全的拷贝,包括元对象引用的对象,对拷贝后的对象的修改不会影响到原对象。

JS中,复制语句就是浅拷贝:

var a = {'a':'a'};
var b = a;

递归拷贝的原理就是把对象复制转换成值复制,JS中的对象的简单赋值都是引用赋值,但是值的赋值去不是,所以:这种递归的复制也是一种迂回的做法。

// 递归拷贝
var deepCopy= function(source) { 
    var result= (source.constructor.name == 'Object') ? {} : [];
    for (var key in source) {
        result[key] = (typeof source[key]==='object') ? deepCopy(source[key]) : source[key];
    } 
    return result; 
}

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注