构造函数 constructor 原型prototype 隐式原型链_proto_

778 阅读3分钟

1、fuction和Object原型链

juejin.cn/post/684490…

  • 总结:先有Object.prototype(原型链顶端),Function.prototype继承Object.prototype而产生,最后,Function和Object和其它构造函数继承Function.prototype而产生。

// 创建了一个能返回两个参数和的函数
const adder = new Function("a", "b", "return a + b");

// 调用函数
adder(2, 6);

2、JS中一切函数都是Function构造函数创造的吗?

2、使用new关键字实例化的时候发生了什么?

3、JS 手撕new:

  • 1.创建空对象
  • 2.this指向新对象,执行构造函数的代码
  • 3.设置原型链,新对象的__proto__指向构造函数的prototype对象
  • 4.判断:如果传入对象的类型是一个对象,返回新对象;反之,直接返回
/**
 * 
 1、创建一个空对象
 2、this指向新对象,执行构造函数的代码
 3、设置原型链,新对象的_proto_指向构造函数的prototype对象
 4、判断:如果传入对象的类型是一个对象,返回新对象;反之,直接返回
 */

function myNew(){
  debugger
  var obj = new Object();
  var Constructor = [].shift.call(arguments)
  var result = Constructor.apply(obj,arguments)
  obj._proto_ = Constructor.prototype;
  return typeof result === 'object' ? result:obj
}

function F(){
   console.log('F----')
}
let f = myNew(F) 
console.log(f)

3、隐式原型属性_proto_

function A() {}
A.prototype.n = 1
//隐式原型属性
var b = new A();

A.prototype = {
  n: 2,
  m: 3
}
var c = new A();

console.log(b.n, b.m, c.n, c.m)

4、构造函数 constructor

let f = new Funtion('x', 'return x')
class _Function {
  constructor (param, expression) {
    this.param = param
    this.expression = expression
  }
}

let _f = new _Function('x', 'return x')

console.log(_Function.prototype) // _Function {}
console.log(_Function.prototype.prototype) // undefined
console.log(_Function.prototype.__proto__) // {}

console.log(Function.prototype) // [Function]
console.log(Function.prototype.prototype) // undefined
console.log(Function.prototype.__proto__) // {}

4.1、构造函数写法

// 定义构造函数
// 这里遵循一个常见的编程约定:从某种意义上讲,定义构造函数既是定义类,并且类名首字母要大写。
function People(name, age) {
    this.name = name;
    this.age = age;
};
People.prototype.showName = function () {
    console.log(this.name);
};

// 使用构造函数
var p1 = new People('wqh', 18);
p1.showName();
var p2 = new People('w', 19);
var p3 = new People('q', 20);
console.log(p1, p2, p3);

  • new出的不同实例的_ _ proto _ _都指向了同一个原型。
  • 原型上的constructor都指向了同一个构造函数People。
  • People构造函数prototype原型上写的方法,被实例对象‘继承’了。
  • 只有写在prototype原型上的属性才会被‘继承’(共有属性),其它地方是私有属性

4.2、prototype被重写

function People(name, age) {
    this.name = name;
    this.age = age;
};
People.prototype = {
    showName: function () {
        console.log(this.name);
    }
}

// 使用构造函数
var p1 = new People('wqh', 18);
p1.showName();
var p2 = new People('w', 19);
var p3 = new People('q', 20);
console.log(p1, p2, p3);

  • 当prototype重定义为一个对象时,这个新定义的原型对象不含有constructor属性,因此类的实例也不含有constructor属性。
function People(name, age) {
  this.name = name;
  this.age = age;
};
People.prototype.showName = function () {
  console.log(this.name);
};

// 使用构造函数
var p1 = new People('wqh', 18);

// p1.prototype.say = function () {
//   console.log(this);
// }; // undefined
p1.say = function () {
  debugger
  console.log(this);// undefined
};

4.3、prototype被重写的解决方案

function People(name, age) {
    this.name = name;
    this.age = age;
};
People.prototype = {
    constructor: People,
    showName: function () {
        console.log(this.name);
    }
}

// 使用构造函数
var p1 = new People('wqh', 18);
p1.showName();
var p2 = new People('w', 19);
var p3 = new People('q', 20);
console.log(p1, p2, p3);![](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/56d0841f13b44ff1b8fb5af660176fa6~tplv-k3u1fbpfcp-watermark.image)

  • 显式给原型添加一个构造函数

5、class

5.1 class写法

class People {
    constructor (name, age) {
        this.name = name;
        this.age = age;    
    }
    
    showName () {
        console.log(this.name);
    }
};

// 使用构造函数
var p1 = new People('wqh', 18);
p1.showName();
var p2 = new People('w', 19);
var p3 = new People('q', 20);
console.log(p1, p2, p3);

class People {
  constructor() {
    // ...
  }
  showName() {
    // ...
  }
}

// 等同于
People.prototype = {
  constructor() {},
  showName() {},
};

6、原型prototype

  • 每个函数都有一个prototype属性,一般情况下,fn.prototype都是对象,但有个特例Function.prototype

7、隐式原型链_proto_

var F = function(){}

Object.prototype.a =function(){}
Function.prototype.b =function(){}

var f = new F()

8、Function构造函数 vs 函数声明 vs函数表达式

  • Function构造函数
var multiply = new Function('x', 'y', 'return x * y');
  • 函数声明
function multiply(x, y) {
   return x * y;
} // 没有分号
  • 函数表达式
var multiply = function(x, y) {
   return x * y;
 };

9、函数属性和方法

  • 因为函数是javascript中的特殊对象,所以它们也可以拥有属性和方法。

9.1. length属性

  • 函数的length属性是只读属性,他代表函数实参的数量。

9.2. prototype属性

  • 每一个函数都包含一个prototype属性,这个属性是指向一个对象的引用,这个对象叫‘原型对象’(prototype object)。
  • 每一个函数都包含不同的原型对象。
  • 当将函数用作构造函数的时候,新创建的对象会从原型对象上继承属性。

9.3. call()方法和apply方法()

9.4. bind()方法

9.4. toString()方法

  • 方法返回一个字符串,这个字符串和函数声明语句的语法有关,大多数(非全部)的toString()方法的实现都返回函数的完整源码。