JavaScript进阶之OOP(二),前端开发实习面试题

本文详细介绍了如何在JavaScript中使用`Object.defineProperty`实现对象属性的定义和修改,涉及Vue的双向绑定原理以及ES5中常量`const`的实现。同时讨论了函数的this指向、闭包、递归和正则表达式等概念,并分享了Web前端学习资源,特别是大厂面试题解析和学习路径建议。
摘要由CSDN通过智能技术生成

定义对象中新属性或修改原有的属性(应用于vue响应式双向绑定,还有es5实现const的原理)

Object.defineProperty(obj, prop,desciptor)

obj:必须,目标对象

prop: 必需,需定义或修改的属性名

descriptor: 必须,目标属性所拥有的特性,一对象的形式{ }进行书写,

  • value设置属性的值,默认undefined;

  • writable值能否重写(修改),默认为false;

  • enumerable:目标属性是否可以被枚举(是否可以被遍历,显示出来),默认false;

  • configurable目标属性是否可以被删除,或者再次修改特性(是否可以再次更改这个descriptor),默认false;

  • 除此外还具有以下可选键值:

  • get:当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入 this 对象(由于继承关系,这里的this并不一定是定义该属性的对象)。该函数的返回值会被用作属性的值。

  • set:当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象(修改后的值)。

var obj = {

id: 1,

pname: ‘小米’,

price: 1999

}

//以前的对象添加修改方式

//obj.num = 1000;

//obj.price = 99;

Object.defineProperty(obj, ‘num’, {

value : 999,

enumerable : true

})

Object.keys(obj)

方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和使用 for…in 循环遍历该对象时返回的顺序一致 。如果对象的键-值都不可枚举,那么将返回由键组成的数组。

6.函数进阶


函数定义和调用

函数定义:

1.自定义函数:function fn() {};

2.匿名函数: var fun = function() {};

3.new Function('参数1', '参数2', '函数体')形式调用 像构造函数, Function里面的参数都必须是字符串格式(了解)

var f = new Function(‘a’, ‘b’, ‘console.log(a + b)’);

实际上所有的函数都是Function的实例,函数也属于对象

函数调用:
1.普通函数调用

function fn() {

//something

}

fn();

2.对象方法

var o = {

say: function() {

//something

}

}

o.say();

3.构造函数

function Star() {};

new Star();

4.绑定事件函数

btn.onclick = function() {}

5.定时器函数

setInterval(function() {}, 1000);

6.立即执行函数(自动调用)

(function() {} )();

7.this的指向


函数内this的指向

是当我们调用函数时确定的,调用方式不同导致this指向不同

1.普通函数调用:window

2.构造函数调用:实例对象,原型对象也是指向实例对象

3.对象方法:该方法所属对象

4.事件绑定:绑定事件对象

5 .定时器函数:window

6.立即执行函数:window

但是立即执行函数还得看这时this是否在对象方法或者构造函数中,第二个虽然是立即执行函数,但是它先找的是全局变量foo,再找到foo.bar,所以this返回的是foo作用域的a

var a = 1;

var foo = {

a: 2,

bar: function () {

return this.a;

}

};

console.log(foo.bar()); //2

console.log((foo.bar)()); //2

console.log((foo.bar=foo.bar)()); //1

“匿名函数的执行环境具有全局性”,所以最里层那个函数中this指向全局环境,全局环境没有定义foo变量所以输出undefined。在匿名函数外部将this保存到一个内部函数可以访问的变量self中,可以通过self访问这个对象,所以self.foo为bar

var myobject = {

foo: “bar”,

func: function () {

var self = this;

console.log(this.foo);

console.log(self.foo);

(function () {

console.log(this.foo);//undefined

console.log(self.foo);//bar

})();

}

};

myobject.func();

改变this指向

JavaScript为我们专门提供了一些函数方法来帮助我们处理函数内部this指向问题,常用的有bind()、call()、apply()三种方法

1.call()

前面讲过,call的主要作用可以实现继承

var obj = {

a:1

}

function f(){

console.log(this);

}

f.call(obj)

//call 第一个可以调用函数,还可以改变函数类this指向

//call 主要作用可以实现继承

2.apply()

方法调用一个函数,简单理解为调用函数的方式,但是它可以改变this的指向

fun.apply(thisArg, [argsArray])

thisArg:在函数执行时指定的this对象

argsArray: 传递的值,必须包含在数组(伪数组)里面

返回值为函数的返回值,因为它就是调用函数

应用方面:apply传递数组参数,所以可以借助数学内置对象求最大值 Math.max.apply(Math,arr)

var arr = [1,66,199,5,6]

//console.log(Math.max.apply(null,arr));

//严格模式,最好让thisArg指向Math

console.log(Math.max.apply(Math,arr));

//求数组最大值的其他方法

var ma = Math.max(…arr);

(es6拓展运算符…Math.max(...arr)也可以,但是不能 MAth.max(arr),因为max不接受数组,只接受一个一个的参数)

3.bind()

方法不会调用函数,但是能改变函数内部this指向

fun.bind(thisArg, arg1, arg2…)

返回指定this值和初始化参数改造的原函数拷贝

即创造新的函数 var f = fn.bind(xx)

应用方面:定时器等不想立即调用的函数(或者处理其他只能用that来暂时储存对象的情况)

//场景:点击按钮后,禁用按钮。3秒后恢复

btn.onclick = function() {

this.disabled = true;

//old way:

var that = this;

setTimeout(function() {

that.disabled = false;

}, 3000)

//new way:

setTimeout(function() {

this.disabled = false;

}.bind(this), 3000) //这个this指向btn

}

巧妙运用: 传参的时候可以传递其他对象过来

call、apply、bind总结

相同:改变函数内部的this指向。

区别

  1. call和apply会调用函数,bind不调用但返回一个改造过this的函数。

  2. call和bind传参为aru1,aru2…形式,apply必须数组形式[arg]

应用

  1. call经常做继承

  2. apply经常与数组有关系,比如借助数学对象求数组的最大值

  3. bind不调用函数,但想改变this指向,如定时器的内部this指向

8.严格模式


ie10以上版本才支持 它是让JavaScript以严格的条件下运行代码

  1. 消除了JavaScript一些语法不严谨的地方,减少怪异行为

  2. 消除代码一些不安全之处,保证代码运行的安全

  3. 提高编译器效率,增加运行速度

  4. 禁用了ECMAscript在未来版本中可能会定义的一些语法,为未来JavaScript做好铺垫,比如class、enum、super等

开启严格模式

应用到整个到整个脚本或个别函数中,因此,我们可以讲严格模式分为脚本开启严格模式为函数开启严格模式两种情况

为脚本开启严格模式:

方法二:(写在立即执行函数里的都要按照严格模式)

为函数开启严格模式:(只在此函数内部有严格模式)
变化
  1. 严格模式禁止变量为声明就赋值

  2. 严禁删除已声明的变量,比如delete x; 是错误的

  3. 在严格模式下,全局作用域中函数中的this不再是window,而是undefined(但是定时器之类的还是指向window)

  4. 严格模式下,如果构造函数不配合new来使用,this就会报错

  5. 函数不能有重名参数

  6. 函数必须声明在顶层,因为新版本的JavaScript引入了块级作用域,所以不允许在非函数代码块内声明函数

9.高阶函数


高阶函数是对其它函数进行操作的函数,它接收函数作为参数或将函数作为返回值输出,最典型的就是作为回调函数

function fn(a, b, callback) {

console.log(a + b);

callback && callback();

}

fn(1, 2, function(){

console.log(‘我是callback’);

})

10.闭包


闭包指有权访问另外一个函数作用域中变量的函数,简单理解就是一个作用域可以访问另外一个函数内部的局部变量

被访问作用域的函数就是闭包函数

//在此处fun函数作用域访问了另外一个函数fn里面的局部变量num,形成了闭包,此时fn就是一个闭包函数

function fn() {

var num = 10;

function fun() {

console.log(num);

}

fun();

}

fn();

在fn外部作用域访问fn内部局部变量(它返回了当时的作用域):

//所以闭包就是典型的高阶函数

function fn() {

var num = 10;

return function() {

console.log(num)

}

}

var f = fn();

f();

闭包的主要作用:延伸了变量的作用范围

利用闭包解决异步问题

(因为函数是一个作用域)

场景:打印li当前索引(面试可能问)

立即执行函数也成为了小闭包,因为立即执行函数里面任何一个函数都可以使用它的i变量

  • 55
  • 66
  • 77
  • 88
  • 回调函数:获取异步操作的结果

    一般情况下,把函数作为参数的目的就是为了获取函数内部的异步操作的结果

    //如果需要获取一个函数中异步操作的结果,则必须通过回调函数来获取

    function fn(callback) {

    setTimeout(function () {

    var data = ‘hello’;

    callback(data);

    }, 1000)

    }

    fn(function (data) {

    console.log(data);

    })

    11.递归


    如果一个函数在内部可以调用其本身,则这个函数是递归(俄罗斯套娃)

    但是容易发生“栈溢出”错误,所以必须加退出条件“return”

    浅拷贝和深拷贝

    (jQuery篇目有提及到($.extend([deep], target, object1, [objectN])))

    1. 浅拷贝只是拷贝一层,更深层次对象级别的只拷贝引用

    2. 深拷贝拷贝多层,每一级别的数据都会拷贝

    ES6中浅拷贝的语法糖:Object.assign(target, ...source)(把source拷贝给target)

    利用循环写浅拷贝

    var obj = {

    id: 1,

    name: ‘andy’,

    msg: {

    age: 18

    }

    };

    var o = {};

    for (var k in obj) {

    // k是属性名, obj[k]是属性值

    o[k] = obj[k];

    }

    //使用assign拷贝

    Object.assign(o,obj); 把obj拷贝给o

    利用递归写深拷贝

    var obj = {

    id: 1,

    name: ‘andy’,

    msg: {

    age: 18

    }

    };

    var o = {};

    function deepcopy(newobj, oldobj) {

    for(var k in oldobj) {

    // 获取属性值

    var item = oldobj[k];

    // 判断该值是否属于数组(数组也属于object,所以要先写)

    if(item instanceof Array) {

    newobj[k] = [];

    deepcopy(newobj[k], item);

    } else if(item instanceof Object) {

    // 判断该值是否为对象

    newobj[k] = {};

    deepcopy(newobj[k], item);

    } else {

    // 所以剩下的属于简单数据类型

    newobj[k] = item;

    }

    }

    }

    deepcopy(o, obj);

    console.log(o);

    12.正则表达式


    概述

    自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

    深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

    因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
    img
    img
    img
    img
    img
    img

    既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

    由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

    如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
    img

    分享

    CodeChina开源项目:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

    console.log(o);

    12.正则表达式


    概述

    自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

    深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

    因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
    [外链图片转存中…(img-BbjLuBnk-1711749417234)]
    [外链图片转存中…(img-DAVlMnAw-1711749417235)]
    [外链图片转存中…(img-L98mIQU8-1711749417235)]
    [外链图片转存中…(img-zqLutFdI-1711749417236)]
    [外链图片转存中…(img-zilqEe7X-1711749417236)]
    [外链图片转存中…(img-Wpm5Diac-1711749417236)]

    既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

    由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

    如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
    [外链图片转存中…(img-LvNDP2Eg-1711749417237)]

    分享

    CodeChina开源项目:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值