想写好面向对象的代码,这篇一定要看 | 重学JS

953 阅读7分钟

前言

  • 在线音乐戳我呀!
  • 音乐博客源码上线啦!
  • 浑浑噩噩在前端领域磕磕碰碰了两年多,想看看Vue源码,不知道有没有最近想看源码的猿友,如果JS不够硬,建议跟我一起来重学JS,重学完相信再去看源码,会事半功倍。
  • 接下来我们来看看JS的对象、函数知识点都可以考些什么。

面试官:我们为什么要用你呢?
你们在招聘啊!
面试官:是啊,但是有很多人来应聘。
选人不是你的工作吗?
面试官:有道理啊~

先来问自己三个面试题

访问对象内部数据可以用['属性名'],那什么时候必须使用['属性名']的方式?

如何调用(执行)函数?请举例至少三种。

如何确定this的值?

如果会了,面试官根本不是你的对手。
如果不会,我们先来理解对象、函数的概念。
只有知道问题背后的原理知识,解题必然随手拈来。

对象对象,那么什么是对象?

333aeed937da8d891fcaa8e796e28c0.png

你以为是这种?

程序员也想要甜甜的恋爱?

别想了,你就是高贵的单身猿。

进入正题。

都有变量存放数据了,为什么还要有对象?

因为对象可以统一管理多个数据。而变量只能存放一个数据。

特点

  • 对象
    • 多个数据的封装体

    • 用来保存多个数据的容器

    • 一个对象代表现实中的一个事物

组成

  • 属性:属性名(字符串)和属性值(任意)组成

  • 方法: 一种特别的属性(属性值是函数)

看下面的对象结构

var p = {
    name: '阿泽',
    setName: function(name){
        this.name = name
    }
}

不是说属性名是字符串吗?

这看起来也不像啊!

答:所谓编程,就是将看起来复杂的问题,简单化

属性名字确实是字符串,但JS作者觉得每次写属性名时都要加引号,麻烦,所以帮我们可省略不写。

当然,你也可以按规范写上引号,这没问题。

延伸出JSON,在JSON中我们不得不为对象添加属性时,属性名一定要添加引号,不然则会报错。

人家JSON作者可没有像JS作者那么友好啦。

如何访问对象内部数据?

  • .(点)属性名: 编码简单, 但有时不能用
  • ['属性名']: 编码麻烦, 能通用
var p = {
    name: '阿泽',
    setName: function(name){
        this.name = name
    }
}

console.log(p.name, ".(点)属性名")
console.log(p['age'], "['属性名']")

开启上面第一道面试题。

面试官:访问对象内部数据可以用['属性名'],那什么时候必须使用['属性名']的方式?

1. 属性名包含特殊字符: - 空格

需求:给p对象添加一个属性: content type: text/json

var p = {}

// p.content-type = 'text/json' //不能用(语法报错)
p['content-type'] = 'text/json'
console.log(p['content-type'])  // 'text/json'

2. 属性名不确定

var propName = 'myAge'
var value = 18

// p.propName = value //不能用
p[propName] = value
console.log(p[propName])  // 18 

玛卡巴卡,什么是函数?

概念

  • 实现特定功能的n条语句的封装体
  • 只有函数是可以执行的, 其它类型的数据不能执行

为什么要用函数?

  • 提高代码复用
  • 便于阅读交流

如何定义函数?

  • 函数声明
  • 表达式
//函数声明
function fn1 () { 
   console.log('fn1()')
}

//表达式
var fn2 = function () { 
   console.log('fn2()')
}

开启上面第二道面试题。

面试官:如何调用(执行)函数?请举例至少三种。

1. 直接调用

function eat () { 
   console.log('富婆,饿饿,软饭,呜呜')
}

eat()

2. 通过对象调用

let obj = {
   eat: function (){
       log('阿巴阿巴')
   }
}

obj.eat()

3. new调用

function eat () { 
   console.log('好人,点个赞吧')
}

let e = new eat()

4. call/apply调用

var obj = {}
function kiss () {
   this.you = '阿泽'
}

// 需求:我想在obj对象里面执行kiss函数,如何做?

obj.kiss()  // 不能直接调用

你™在逗我?kiss函数都不在obj里面。

那怎么办?

其实我们可以借助call/apply。

kiss.call(obj)  // 打印 '阿泽'

语句解释:相当于obj.kiss()调用,JS很强大的,
call可以让一个函数成为指定任意对象的方法进行调用。

我不信,你说kiss.call(obj)就是让kiss在obj对象里面执行了,你怎么证明?

好,如果你想要答案,你在控制台打印一下obj.you,看看是不是打印出'阿泽'

kiss.call/apply(obj): 临时让kiss成为obj的方法进行调用。

回调函数,一种特殊函数?

需要满足以下三种条件,才是回调函数

  • 你定义的
  • 你没用调用
  • 但最终它执行了(在某个时刻或某个条件下)
<button id="btn">点赞我!(疯狂暗示)</button>
document.getElementById('btn').onclick = function () { 
   alert(this.innerHTML)
}

// 你定义了的吧,但是你没有调用它
function () { 
   alert(this.innerHTML)
}

可当我点击按钮btn的时候,函数它执行了。

常见的回调函数?

1. DOM事件回调函数 ==>发生事件的DOM元素

document.getElementById('btn').onclick = function () { 
   alert(this.innerHTML)
}

2. 定时器回调函数 ===>window

// 定时器:超时定时器、循环定时器

setTimeout(function () { // 定时器回调函数
   alert('我又来了,懂的都懂')
}, 2000)

3. ajax请求回调函数

axios.then(res =>{
    console.log(res)
}).catch(err =>{
    console.log(err)
})

4. 生命周期回调函数

// 比如vue的创建create生命周期

new Vue({
    data(){},
    create(){
        console.log('创建了')
    }
})

匿名函数,也是一种特殊函数?

全称: Immediately-Invoked Function Expression,又称:立即函数。

普通函数满足不了你吗?为什么还要匿名函数?有什么用?

  • 隐藏实现
  • 不会污染外部(全局)命名空间
  • 用它来编码js模块
(function () { //匿名函数自调用
    var a = 3
    console.log(a + 3)
})()

// 直接打印6,不用谁调用,自己执行
// a变量是局部变量,并不会污染全局空间

延伸:还记得JQ时代,看过源码,有用到匿名函数,里面大概有这样子写的。

var a = 4
console.log(a)

;(function () {
    function load () {
      console.log('添加一个事件处理程序到 load 事件')
    }
    window.$ = function () { // 向外暴露一个全局函数
      return {
        load: load
      }
    }
})()

想说的一点是,为什么匿名函数前面要加分号;

假设:如果不加分号,程序最终编译成这样子:

var a = 4
console.log(a)(function () {...}

结果就会报错:Uncaught TypeError: console.log(...) is not a function

Why?

那是因为匿名函数是以括号()为开头,对于程序括号()代表函数执行,那前面应该就有函数名,编译后空格去掉就console.log(a)(...),自然报错。

这也是为什么JS语句后要加分号的原因。

那我不想在每条语句(console.log(a))后都加分号怎么办?

在女朋友面前发过誓,不在语句后面加分号的。

就需要在匿名函数前加分号,后面不加就前面加。

明白了为什么匿名函数前面要加分号了吧!

你到底指着谁?this

概念

  • 任何函数本质上都是通过某个对象来调用的,如果没有直接指定就是window

  • 所有函数内部都有一个变量this

  • 它的值是调用函数的当前对象

上面最后一道面试题。

面试官:如何确定this的值?

1. (以函数调用,this为window)全局调用 Fun(): window

function Fun(color) {
   this.color = color  // 这里的this指向的是Fun,this.color就是为Fun添加属性
}

Fun('pink'); // 这里的this是谁? 是window。全局环境中,若未直接指定则是window。

2. (以构造函数形式调用时,this就是新创建的对象)对new Kiss(): 新创建的对象

function Kiss() {}

var kiss = new Kiss(); // 这里的this是谁? 是kiss。

// new Class()赋给谁,this就是谁。

3. (方法调用,this就是调用方法的对象)kiss.getColor(): kiss

function Kiss() {
   this.color = color;
   this.getColor = function(){
       return this.color
   }
}

var kiss = new Kiss('red'); 
kiss.getColor();  // 这里的this是谁?是kiss。

// kiss对象内调用函数getColor,那this就是该对象。

4. (call通过第一个实参来指定函数中的this)kiss.call(obj): obj

function Kiss() {
   this.color = color;
   this.setColor = function(color){
        this.color = color 
   }
}

var kiss = new Kiss('red');

var obj = {};
kiss.setColor.call(obj, "black"); // 这里的this是谁? 是obj。

// kiss对象call别的对象obj的时候,那this指向别的对象obj。

看起来你好像会this的亚子,再来一道?

function fun1() {
   function fun2() {
     console.log(this);
   }

   fun2(); // this是谁? 评论区留一波
}

fun1();

最后

加薪了,终于也是月入过万的人了。

以往推荐

老湿说的万物皆对象,你也信?

Vue-Cli3搭建组件库

Vue实现动态路由(和面试官吹项目亮点)

项目中你不知道的Axios骚操作(手写核心原理、兼容性)

VuePress搭建项目组件文档

koa2+vue+nginx部署

vue-typescript-admin-template后台管理系统

原文链接

juejin.cn/post/700017…