我在乐字节学习前端的第十天-前端面试总结/JS面试

92 阅读3分钟

**
1.JS继承机制** 构造函数中的属性和方法是不共享的,而为了共享一些属性和方法,也为了不浪费资源,出现了prototype,挂在prototype上的属性和方法是共享的。

function Ani(name) {    this.name = name;    // this.act = '叫';}​var dog = new Ani('狗');var cat = new Ani('猫');​// dog.act = '旺旺'; //只修改了dog的act属性  不会影响cat的act属性Ani.prototype.act = '旺旺';​console.log(dog.name, dog.act, cat.name, cat.act);

由此想到原型链继承:

题目:

用原型链的方式实现继承。创建一个基类PeoClass,其中有两个公开方法:eat、sleep, 再创建一个子类EngiClass, eat继承基类,重写sleep方法:

function PeoClass() {​}PeoClass.prototype = {    eat: function() {​    },    sleep: function() {​    }}​function EngiClass() {​}EngiClass.prototype = new PeoClass();EngiClass.prototype.constructor = EngiClass;EngiClass.prototype.sleep= function() {    // 重写}

2.关于深拷贝

function deepClone(obj){    var newObj = obj instanceof Array ? [] : {};    for(var i in obj){       newObj[i] = typeof obj[i] == 'object'? deepClone(obj[i]) : obj[i];        }    return newObj;}​

3.关于数组 (1)数组去重

function norepeat(arr) {    var new_arr = [];    var obj = {};​    for(var i = 0, len = arr.length; i < len; i ++) {        if(!obj[arr[i]]) {            obj[arr[i]] = arr[i];            new_arr.push(i);        }    }    return new_arr; }123456789101112

(2)数组排序/乱序

function arrRand(arr) {    arr.sort(function() {        return 0.5 - Math.random();    });}

(3)出现次数

function showCount(param) {    param = typeof param == 'string' ? param.split('') : param;​    var obj = {};​    for(var i = 0, len = param.length; i < len; i ++) {        if(!obj[param[i]]) {            obj[param[i]] = 1;        }else {            obj[param[i]] += 1;        }    }​    return obj;}

4.关于作用域、闭包以及this

作用域

:javascript是基于词法作用域的语言,也就是静态作用域,即在函数定义时就确定了作用域,而不是执行时

闭包:

两个函数中间包裹一块无法直接访问的作用域,只能通过间接地方式访问;闭包可以使内部变量始终保存在内存中;有闭包就可能造成内存泄漏。

function f1() {    var n = 99;​    add = function() {        n += 1;    }    function f2() {        console.log(n);    }    return f2;}var res = f1();res(); // 99add();res(); // 100  n一直保持在内存中/************************************************/var x = 20;var a = {    x: 15,    fn: function() {        var x = 30;        return function() {            return x;        };    }}console.log(a.fn());// function() {return x}console.log(a.fn()());// 30console.log((a.fn())());// 30console.log((a.fn())() == a.fn()());// trueconsole.log(a.fn().call(this));// console.log(a.fn().call(a)); //

关于this:

动态绑定,也就是在函数执行时从上下文中获取指向,上下文不同,this指向不同;一般指向调用者对象,也就是函数的拥有者;特殊的情况是自执行函数,this指向window;(闭包遇上this时,要注意运行时的上下文,看栗子)(当构造函数中return一个对象(除了null)时,this指向return的对象)

var x = 'windows';var obj_a = {    x: 1,    y: {        x: 2,        y: function() {            return function() {                return this.x;            }        },        z: function() {            return this.x;        }    }}​var fun = obj_a.y.y();console.log(obj_a.y.z()); // 2console.log(obj_a.y.y()()); // windowsconsole.log(fun()); // 'windows'

4.关于call/apply/bind

var obj = {    a: 'obj.a',    b: function() {        console.log(this.a);    }}var fun = obj.b;fun(); // undefined 因为执行时上下文中的this指向windowobj.b(); // 'obj.a' 执行时上下文中的this指向obj​

call

:改变对象的环境,即改变this指向并调用函数;参数:n个,第一个参数是目标对象或者对象本身,其他参数可以是原函数的参数; 上述fun()语句若改为apply

 fun.call(obj);//'obj.a'上下文中原本指向window的this强制指向了obj对象

apply

:与call方法类似,效果也类似,只是参数格式不同,第一个参数都是目标对象或对象本身,但第二个参数必须是个数组,放置函数的参数

注意:非严格模式下,若call/apply的第一个参数传入null、undefined, 则this指向window对象

bind

:与以上两个方法有些不同,但是都能改变this指向,不同之处在于bind方法并不能调用原函数,而是返回一个修改后的函数,称为绑定函数,若要执行需要手动调用该函数;

fun.bind(obj)(); // 'obj.a'​

同样bind也可以有多个参数,格式可以与call一样,也可以执行时再次添加

var a = {    x: 'mx',    y: function(a, b) {        console.log(this.x);        console.log(a+b);    }}var b = a.y;b.call(a, 1, 2); // mx 3b.apply(a, [1, 2]); // mx 3b.bind(a, 1, 2)() // mx 3b.bind(a, 1)(2) // mx 3