2020年出现的大厂面试题
var x = 1;
function func(x, y = function anonymous1() {
x = 2}) {
x = 3;
y();
console.log(x); // 1
}
func(5);
console.log(x); // 1
1.函数func作用域内的变量是私有的,形参赋值x=5,私有赋值x=3,anonymous1函数的作用域链是func,所以函数y()执行会改变x=2,第一个console.log(x)打印2
2.全局作用域,第二个打印数值 x=1
var x = 1;
function func(x, y = function anonymous1() {
x = 2}) {
var x = 3;
y();
console.log(x); //3
}
func(5);
console.log(x);//1
/*
es6中存在块级作用域(只要{}[除对象之外的大括号] 出现let/const/function)
有一种情况也会产生
1.函数有形参赋值了默认值
2.函数体中有单独声明过某个变量
这样在函数运行的时候会产生两个上下文
第一个:函数执行形成的私有上下文EC(FUNC) => 作用域链/形参赋值/...
第二个:函数大括号包起来的就是块级上下文EC(BLOCK)
*/
/*
*EC(G)
*x=1
*func = AAAFFF000
*/
var x = 1;
function func(x, y = function anonymous1() {
x = 2}) {
/*
*EC(FUNC)私有上下文
* 作用域链:
* x=5
* y=anonymous1 [[scope]]:EC(FUNC)
*EC(BLOCK)块级上下文(上级上下文 EC(FUNC))
* 变量提升 var x
* 在代码没有执行之前,我们会把EC(FUNC)中的值也给它一份 x=5
*/
var x = 3; // 块级上下文中的x x=3
y(); // 不是块级的y,向上级找 EC(FUNC)
//anonymous1执行
// 私有上下文EC(AN) 作用域链:
// x = 2 修改的是EC(FUNC)中的2
console.log(x); //3 块级上下文中的x,还是3
}
func(5);
console.log(x);//1
// 相应三道练习题
{
function foo() {
}
foo = 1;
// =>1
}
console.log(foo); // 函数
//-----------------------------------------
{
function foo() {
}
foo = 1;
function foo() {
}
// 1
}
console.log(foo); // 1
// -----------------------------------------
{
function foo() {
}
foo = 1;
function foo() {
}
foo = 2;
// 2
}
console.log(foo); //1
函数柯里化:必报实现存储值,后期用的机制
已知结果,求函数
let res = fn(1,2)(3)
console.log(res) // 6
// 答案
function fn (...outerArgs){
return function anonymous(...innerArgs){
return outerArgs.concat(innerArgs).reduce((a,b)=> a+b)
}
}
// 简化
let fn = (...outerArgs) => {
(...innerArgs)=> outerArgs.concat(innerArgs).reduce((a,b)=> a+b)}
函数式编程
/*
在函数式编程当中有一个很重要的概念就是函数组合, 实际上就是把处理数据的函数像管道一样连接起来, 然后让数据穿过管道得到最终的结果。 例如:
const add1 = (x) => x + 1;
const mul3 = (x) => x * 3;
const div2 = (x) => x / 2;
div2(mul3(add1(add1(0)))); //=>3
而这样的写法可读性明显太差了,我们可以构建一个compose函数,它接受任意多个函数作为参数(这些函数都只接受一个参数),然后compose返回的也是一个函数,达到以下的效果:
const operate = compose(div2, mul3, add1, add1)
operate(0) //=>相当于div2(mul3(add1(add1(0))))
operate(2) //=>相当于div2(mul3(add1(add1(2))))
简而言之:compose可以把类似于f(g(h(x)))这种写法简化成compose(f, g, h)(x),请你完成 compose函数的编写
*/
const add1 = (x) => x + 1;
const mul3 = (x) => x * 3;
const div2 = (x) => x / 2;
function compose(...funcs){
return function anonymous(...args){
if (funcs.length === 0) return args
if (funcs.length === 1) return funcs[0](...args)
let n = 0
return funcs.reduce((a,b)=>{
n++
if (n === 1) {
// 第一次a是一个函数
return b(a(...args))
}
return b(a) // 第二次开始,a是一个累加值
})
}
}
// 不传函数
let result = compose()(0,1)
console.log(result) // 返回传进去的参数
// 传一个函数
let result = compose(add1)(0,1)
console.log(result) // 返回第一个函数执行
// 传多个函数
let result = compose(add1,mul3,div2,add1)(0,1)
console.log(result) // 依次执行,返回最后一个函数结束后的结果
function Dog(name) {
this.name = name;
}
Dog.prototype.bark = function () {
console.log('wangwang');
}
Dog.prototype.sayName = function () {
console.log('my name is ' + this.name);
}
function _new() {
//=>完成你的代码
}
let sanmao = _new(Dog, '三毛');
sanmao.bark(); //=>"wangwang"
sanmao.sayName(); //=>"my name is 三毛"
console.log(sanmao instanceof Dog); //=>true
// 答案
function _new(Func, ...args) {
// 创建实例对象
let obj = {
}
obj.__proto__ = Func.prototype // IE let obj = Object.create(Func.prototype)
// 方法执行,让里面的this指向实例对象
let result = Func.call(obj, ...args)
// 分析返回结果
if (result !== null && (/^(object|function)$/.test(typeof result))) {
return result
}
return obj
}
~function(){
function change(){
//=>实现你的代码
};
Function.prototype.change=change;
}();
let obj = {
name:'Alibaba'};
function func(x,y){
this.total=x+y;
return this;
}
let res = func.change(obj,100,200); // let res = func.call(obj,100,200); 一样的效果
//res => {name:'Alibaba',total:300}
// 答案
/*
obj.xxx = func
obj.xxx(10,20) // func执行,方法中的this指向obj
*/
~function(){
function change(context, ...args){
// this -> func
context = context == undefined ? window : context // 处理传值为空情况
let type = typeof context
if(!/^(object|function)$/.test(type)){
// 处理传值为字符串情况
if (/^(symbol|bigint)$/.test(type)){
context = Object(context)
}else{
context = new context.contructor(context) // 转换成对应的函数
}
}
let key = Symbol('key')
console.log(key, this)
context[key] = this // 指向
let result = context[key](...args) // 执行
delete context[key]
return result
};
Function.prototype.change=change;
}();
~function(){
//=>bind方法在IE6~8中不兼容,接下来我们自己基于原生JS实现这个方法
function bind(){
};
Function.prototype.bind=bind;
}();
var obj = {
name:'zhufeng'};
function func(){
console.log(this,arguments);
//=>当点击BODY的时候,执行func方法,输出:obj [100,200,MouseEvent事件对象]
}
document.body.onclick = func.bind(obj,100,200);
// 答案
/*
bind执行完成后,返回的函数
document.body.onclick = function(ev){
func.call(obj, 100,200)
}
*/
~function(){
//=>bind方法在IE6~8中不兼容,接下来我们自己基于原生JS实现这个方法
function bind(context, ...args){
// this -> func
let _this = this
context = context == undefined ? window : context // 处理传值为空情况
let type = typeof context
if(!/^(object|function)$/.test(type)){
// 处理传值为字符串情况
if (/^(symbol|bigint)$/.test(type)){
context = Object(context)
}else{
context = new context.contructor(context) // 转换成对应的函数
}
}
return function anonymous(...innerArgs){
// _this指向func
_this.call(context, ...args.concat(innerArgs))
}
};
Function.prototype.bind=bind;
}();
PS:需配套视频讲解请发邮件到 [email protected] 并备注文章标题