Understanding prototype and prototype chain of Javascript

Foreword

2088 word article, read it takes about 13 minutes.

All in all: with examples describes the concept and prototype prototype chain and summarizes several methods to create objects, methods prototype chain extension.

Paul impermanence home, without the blessing of the house.

text

prototype

Javascript in a word, called everything is an object, of course, this statement is not rigorous, for example null, and undefinedis not subject, except maybe Javascript can say that everything is an object. The Javascript object has called a prototype of public property, the property name is __ proto__ ** . The prototype property is a reference to another object, through this prototype ** property we can access all the other object properties and methods. such as:

let numArray = [1, 2, -8, 3, -4, 7];

Array objects have a prototype property points Array.prototype , variable numArrayinherits Array.prototype object for all properties and methods.

That's why you can call directly like sort () this way:

console.log(numArray.sort()); // -> [-4, -8, 1, 2, 3, 7]

In other words:

numArray.__proto__ === Array.prototype // true

For other objects (function) is the same (such as Date (), Function (), String (), Number () , etc.);

When a constructor is created, the constructor's prototype property inherited instance objects, this is a very important characteristic of the constructor. In Javascript used newto instantiate constructor function key. See the examples below:

const Car = function(color, model, dateManufactured) {
  this.color = color;
  this.model = model;
  this.dateManufactured = dateManufactured;
};
Car.prototype.getColor = function() {
    return this.color;
};
Car.prototype.getModel = function() {
    return this.model;
};
Car.prototype.carDate = function() {
    return `This ${this.model} was manufactured in the year ${this.dateManufactured}`
}
let firstCar = new Car('red', 'Ferrari', '1985');
console.log(firstCar);
console.log(firstCar.carDate());

In the above example, the method getColor, carDate, getModel is an object (function) Car method, the Car object instances firstCar inherit Car all methods and properties of the prototype.

Conclusion: Each instance of an object has a private attribute proto__ __ ** , pointing to its constructor prototype object ( the prototype **).

Prototype chain

在Javascript中如果访问一个对象本身不存在的属性或是方法,就首先在它的原型对象上去寻找,如果原型对象上也不存在,就继续在原型对象的原型对象上去寻找,直到找到为止。那么原型对象有尽头么?所有对象的原型尽头是Object.prototype,那么Object.prototype这个对象的**__proto__指向啥呢?答案是null。我们日常开发中用到的绝大多数对象的__proto__基本不会直接指向Object.prototype,基本都是指向另一个对象。比如所有的函数的__proto__都会指向Function.prototype,所有数组的__proto__都会指向Array.prototype**。

let protoRabbit = {
  color: 'grey',
  speak(line) {
        console.log(`The ${this.type} rabbit says ${line}`);
  }
};
let killerRabbit = Object.create(protoRabbit);
killerRabbit.type = "assassin";
killerRabbit.speak("SKREEEE!");

上面代码中变量protoRabbit设置为所有兔子对象的公有属性对象集,killerRabbit这只兔子通过Object.create方法继承了protoRabbit的所有属性和方法,然后给killerRabbit赋值了一个type属性,再看下面的代码:

let mainObject = {
    bar: 2
};
// create an object linked to `anotherObject`
let myObject = Object.create( mainObject );
for (let k in myObject) {
  console.log("found: " + k);
}
// found: bar
("bar" in myObject); 

如上变量myObject本身并没有bar属性,但这里会循着原型链一层一层往上找,直到找到或者原型链结束为止。如果到原型链尽头还是没找到该属性,那么访问该属性的时候就会返回undefined了。

使用for...in关键字对对象进行迭代的过程,和上面访问某个属性循着原型链查找类似,会去遍历所有原型链上的属性(不论属性是否可枚举)。

let protoRabbit = {
  color: 'grey',
  speak(line) {
    console.log(`The ${this.type} rabbit says ${line}`);
  }
};
let killerRabbit = Object.create(protoRabbit);
killerRabbit.type = "assassin";
killerRabbit.speak("SKREEEE!");

上面的代码中访问speak的效率很高,但如果我们想创建很多个Rabbit对象,就必须要重复写很多代码。而这正是原型和构造函数的真正用武之地。

let protoRabbit = function(color, word, type) {
  this.color = color;
  this.word = word;
  this.type = type;
};
protoRabbit.prototype.getColor = function() {
    return this.color;
}
protoRabbit.prototype.speak = function() {
    console.log(`The ${this.type} rabbit says ${this.word}`);
}
let killerRabbit = new protoRabbit('grey', 'SKREEEEE!', 'assassin');
killerRabbit.speak();

如上代码,使用构造函数的方式就可以节省很多的代码。

结论:每一个实例对象都有一个私有属性**__proto__,指向它的构造函数的原型对象(prototype)。原型对象也有自己的__proto__**,层层向上直到一个对象的原型对象为null。这一层层原型就是原型链。

附赠一张原型链的图:

创建对象的四种方法

字面量对象

这是比较常用的一种方式:

let obj = {};
构造函数创建

构造函数创建的方式更多用来在Javascript中实现继承,多态,封装等特性。

function Animal(name) {
    this.name = name;
}
let cat = new Animal('Tom');
class创建

class关键字是ES6新引入的一个特性,它其实是基于原型和原型链实现的一个语法糖。

class Animal {
  constructor(name) {
    this.name = name;
  }
}
let cat = new Animal('Tom');

扩展原型链的四种方法

构造函数创建

上面例子有用到使用构造函数创建对象的例子,我们再来看一个实际的例子:

function Animal(name) {
    this.name = name;
}
Animal.prototype = {
    run() {
    console.log('跑步');
    }
}
let cat = new Animal('Tom');
cat.__proto__ === Animal.prototype; // true
Animal.prototype.__proto__ === Object.prototype; // true

优点:支持目前以及所有可想象到的浏览器(IE5.5都可以使用). 这种方法非常快,非常符合标准,并且充分利用JIST优化。

缺点:为使用此方法,这个问题中的函数必须要被初始化。另外构造函数的初始化,可能会给生成对象带来并不想要的方法和属性。

Object.create

ECMAScript 5 中引入了一个新方法: Object.create()。可以调用这个方法来创建一个新对象。新对象的原型就是调用 create 方法时传入的第一个参数:

var a = {a: 1}; 
// a ---> Object.prototype ---> null
var b = Object.create(a);
b.__proto__ === a; // true

优点: 支持当前所有非微软版本或者 IE9 以上版本的浏览器。允许一次性地直接设置 __proto__ 属性,以便浏览器能更好地优化对象。同时允许通过 Object.create(null)来创建一个没有原型的对象。

缺点:不支持 IE8 以下的版本;这个慢对象初始化在使用第二个参数的时候有可能成为一个性能黑洞,因为每个对象的描述符属性都有自己的描述对象。当以对象的格式处理成百上千的对象描述的时候,可能会造成严重的性能问题。

Object.setPrototypeOf

语法:

Object.setPrototypeOf(obj, prototype)

参数:

参数名 含义
obj 要设置其原型的对象。
prototype 该对象的新原型(一个对象 或 null).
var a = { n: 1 };
var b = { m : 2 };
Object.setPrototypeOf(a, b);
a.__proto__ === b; // true

优点:支持所有现代浏览器和微软IE9+浏览器。允许动态操作对象的原型,甚至能强制给通过 Object.create(null)创建出来的没有原型的对象添加一个原型。

缺点:这个方式表现并不好,应该被弃用;动态设置原型会干扰浏览器对原型的优化;不支持 IE8 及以下的浏览器版本。

__proto__
var a = { n: 1 };
var b = { m : 2 };
a.__proto__ = b;
a.__proto__ === b; // true

使用**__proto__**也可以动态设置对象的原型。

优点:支持所有现代非微软版本以及 IE11 以上版本的浏览器。将 __proto__ 设置为非对象的值会静默失败,并不会抛出错误。

缺点:应该完全将其抛弃因为这个行为完全不具备性能可言;干扰浏览器对原型的优化;不支持 IE10 及以下的浏览器版本。

以上。


能力有限,水平一般,欢迎勘误,不胜感激。

订阅更多文章可关注公众号「前端进阶学习」,回复「666」,获取一揽子前端技术书籍

前端进阶学习

Guess you like

Origin www.cnblogs.com/jztan/p/12332264.html
Recommended