深入浅出javaScript类型(三)

90 阅读5分钟

本文已参与『新人创作礼』活动,一起开启掘金创作之路

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第3天,点击查看活动详情

1. this

  • 当前函数的this是在被调用的时候才能确定的
  • 如果当前的执行上下文处于调用栈的栈顶,这个时候变量对象变成了活动对象,THIS指针才能确定

1.1 全局对象

  • 全局对象this指向本身
var a=1;//声明绑定变量对象,但在全局环境中,变量对象就是全局对象
this.b=2;//this绑定全局对象
c=3;//赋值操作 隐式绑定

1.1 用点调用

  • 在一个函数上下文中,this由函数的调用者提供,由调用函数的方式来决定指向
  • 如果是函数执行,如果前面有点,那么点前面是谁this就是谁
let obj = {
    getName(){
        console.log(this);
    }
};
obj.getName();

1.2 直接调用

  • 如果没有,this就是window(严格模式下是undefined),自执行函数中的this一般都是window
  • Strict_mode
let obj = {
    getName(){
        console.log(this);
    }
};
let getName = obj.getName;
getName();

1.3 绑定事件

  • 给元素绑定事件的时候,绑定的方法中的this一般是元素本身
container.addEventListener('click',function(){
    console.log(this);
});

1.4 箭头函数

  • 箭头函数没有自己的this
  • 也没有prototype
  • 也没有arguments
  • 无法创建箭头函数的实例
let fn = () => {
    console.log(this);
    console.log(arguments);//Uncaught ReferenceError: arguments is not defined
}
console.log(fn.prototype);//undefined
fn();
new fn();//VM4416:8 Uncaught TypeError: fn is not a constructor

1.5 构造函数

  • 构造函数中的THIS是当前类的实例,通过this添加的属性名和属性值都是给当前的实例添加的
  • 如果构造函数没有形参,在调用的时候可以直接省去()
  • 实例和实例比较是不相等的(因为存储空间地址不同)
  • 构造函数中this添加的属性都是私有的
  function fn(){
      this.name = "小明",
      this.age = 20,
      this.sex = "男"
  }
  var f1 = new fn()
  var f2 = new fn()

1.5.1 构造函数中的return

当return一个基本类型时,return不会发生作用,构造函数依旧返回一个实例对象。

function fn(){
      this.name = "小明",
      this.age = 20,
      this.sex = "男"
      return 'string'
  }
  var f1 = new fn()

当return一个引用类型时,return会覆盖创建实例,构造函数返回自己手写的引用类型值。

function fn(){
      this.name = "小明",
      this.age = 20,
      this.sex = "男"
      return { }
  }
  var f1 = new fn()

当只使用return时,return只会终止代码执行。依旧返回一个创建的实例

function fn(){
      this.name = "小明",
      this.age = 20,
      this.sex = "男"
      return 
      console.log('这里不会被执行')
  }
  var f1 = new fn()

构造函数一般不会写return 因为他默认会返回就是当前的实例**

1.6 call/apply/bind

  • call/apply/bind可以改变函数中this的指向
  • 第一个参数是改变this指向(非严格模式下,传递null/undefined指向也是window)
  • call参数是依次传递,apply是以数组的方式传递
!function (proto) {
    function getContext(context) {
        context = context || window;
        var type = typeof context;
        if (['number', 'string', 'boolean', 'null'].includes(type)) {
            context = new context.constructor(context);
        }
        return context;
    }
    function call(context, ...args) {
        context = getContext(context);
        context._fn = this;
        let result = context._fn(...args);
        delete context._fn;
        return result;
    }
    function apply(context, args) {
        context = getContext(context);
        context._fn = this;
        let result = context._fn(...args);
        delete context._fn;
        return result;
    }

    function bind(context, ...bindArgs) {
        return (...args) => this.call(context, ...bindArgs, ...args);
    }
    proto.call = call;
    proto.apply = apply;
    proto.bind = bind;
}(Function.prototype)

1.7

  • 默认绑定
  • 隐式绑定
  • 显式绑定
  • new绑定
  • new > 显示 > 隐式 > 默认

隐式 > 默认

function one() {
    console.log(this)
}
var obj = {
    name: "obj",
    one
}

obj.one()

显示 > 隐式

function one() {
  console.log(this)
}

var obj = {
  name: "obj",
  one: one.bind("hello")
}

obj.one()

new > 显示

function one() {
    console.log(this)
}

var helloOne = one.bind("hello")
var obj = new helloOne();
console.log(obj);

2. 面向对象

2.1 原型链

2.1.1 一切皆对象

  • 对象就是一些属性的集合
  • 方法也是一种属性
  • 一切(引用类型)都是对象,对象是属性的集合
  • 函数和数组也是对象
  • 为什么 typeof function='function'

2.1.1.1 typeof

  • 检测数据类型 typeof返回的都是字符串
  • 基本数据类型 number string boolean undefined symbol
  • 引用类型 null {} [] /&$/ Date => object
console.log(typeof a);    // undefined
console.log(typeof 1);   // number
console.log(typeof 'zhufeng'); // string
console.log(typeof true);  // boolean
console.log(typeof Symbol('a'));  // symbol

console.log(typeof function () { });  //function

console.log(typeof [1, 2, 3]);  //object
console.log(typeof { name: 'zhufeng' });  //object
console.log(typeof null);  //object
console.log(typeof new Number(1));  //object

2.1.2 函数

  • 对象是通过函数创建的
  • 批量生产对象的函数Object
  • 实现私有和公有属性的封装
let obj = new Object();
obj.name='zhufeng';
obj.age = 10;

2.1.3 隐式原型

2.1.3.1 proto
  • 每个对象都有一个proto属性,指向创建该对象的函数的prototype
  • Object.prototype__proto__指向的是null

objectprototype

object_prototypes

2.1.3.2 自定义函数的prototype
  • 自定义函数的prototypeproto指向的就是Object.prototype

customefuntionprototype

2.1.3.3 自定义函数
  • 自定义函数Foo.proto指向Function.prototype
  • Function的prototype和proto都指向Function.prototype
let add = new Function('a','b','return a+b');
console.log(add(1,2));

2functionprotype

3functionprotype

2.1.4 instanceof

  • instanceof运算符的第一个参数是一个对象,第二个参数一般是一个函数
  • instanceof的判断规则是: 沿着对象的__proto__这条链来向上查找找,如果能找到函数的prototype则返回true,否则 返回false

prototypechain

2.2 批量创建对象

  • 通过new来调用一个函数,这个函数就成为了构造函数,构造函数里可以对例对象的私有属性赋值
  • 每个函数会有一个prototype属性,此原型对象上存放所有实例的公有方法
  • 若new的构造函数自己返回引用值,则以自己返回的为主,否则 返回创建的实例
  • create
function Person(name) {
    this.name = name;
}
Person.prototype.getName = function () {
    console.log(this.name);
}
let person = new Person('zhufeng');
person.getName();
Object.create = function (proto) {
    function F() {}
    F.prototype = proto;
    return new F();
};
function _new(clazz, ...args) {
    let _this = Object.create(clazz.prototype);
    let result = clazz.call(_this, ...args);
    if ((result != null && typeof result === 'object') || typeof result === 'function') {
        return result;
    }
    return _this;
}

2.3 继承

class Father {
    static staticFatherName = "FatherName"
    static staticGetFatherName = function () {
        console.log(Father.staticFatherName);  // ?
    }
    constructor(public name) {
        this.name = name;
    }
    getName() {
        console.log(this.name);  // ?
    }
}
class Child extends Father {
    static staticChildName = "ChildName"
    static staticGetChildName = function () {
        console.log(Child.staticChildName);  // ?
    }
    constructor(public name, public age) {
        super(name);
        this.age = age;
    }
    getAge() {
        console.log(this.age); // ?
    }
}
let child = new Child('zhufeng', 10);
child.getName();
child.getAge();
Child.staticGetFatherName();
Child.staticGetChildName();

知道答案或者文章有遗漏地方的小伙伴可以在评论区评论哦~~