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

**
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;
}
我在乐字节学习前端的第十天-前端面试总结/JS面试_第1张图片
4.关于作用域、闭包以及this _作用域_:javascript是基于词法作用域的语言,也就是静态作用域,即在函数定义时就确定了作用域,而不是执行时 _闭包:_两个函数中间包裹一块无法直接访问的作用域,只能通过间接地方式访问;闭包可以使内部变量始终保存在内存中;有闭包就可能造成内存泄漏。

function f1() {
var n = 99;

add = function() {
n += 1;
}
function f2() {
console.log(n);
}
return f2;
}
var res = f1();
res(); // 99
add();
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()());// 30
console.log((a.fn())());// 30
console.log((a.fn())() == a.fn()());// true
console.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()); // 2
console.log(obj_a.y.y()()); // windows
console.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指向window
obj.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 3
b.apply(a, [1, 2]); // mx 3
b.bind(a, 1, 2)() // mx 3
b.bind(a, 1)(2) // mx 3

你可能感兴趣的:(前端,javascript)