Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

兑吧: prototype 和 proto 区别(一面) #13

Open
YuShengHou opened this issue Apr 30, 2019 · 1 comment
Open

兑吧: prototype 和 proto 区别(一面) #13

YuShengHou opened this issue Apr 30, 2019 · 1 comment
Assignees
Milestone

Comments

@YuShengHou
Copy link

YuShengHou commented Apr 30, 2019

To:
@hys1440248234

面试公司:
兑吧

面试环节:
未知

问题:
prototype 和 proto 区别

@YuShengHou
Copy link
Author

YuShengHou commented Apr 30, 2019

prototype 和 proto 区别

先看一看图一,不根据图一讲。


图一  原型链

每个 JavaScript 对象一定对应一个原型对象,并从原型对象继承属性和方法。

对象 __proto__ 属性的值就是它所对应的原型对象:

var one = {x: 1};
var two = new Object();
one.__proto__ === Object.prototype // true
two.__proto__ === Object.prototype // true
one.toString === one.__proto__.toString // true

首先来说说 prototype 属性,不像每个对象都有 __proto__ 属性来标识自己所继承的原型,只有函数才有 prototype 属性。

函数在 JavaScript 中很特殊,是所谓的“一等公民”。JavaScript 不像其它面向对象的语言,它没有类(虽然 ES6 引进了 class 关键字,但更多是语法糖)的概念。

JavaScript 通过函数来模拟类。当你创建函数时,JavaScript 会为这个函数自动添加 prototype 属性,值是一个有 constructor 属性的对象,不是空对象(如图二)。

image.png
图二  two 对象

你把函数当作构造器(constructor)调用(即通过 new 关键字调用),那么 JavaScript 就会帮你创建该构造函数的实例,实例继承构造函数 prototype 的所有属性和方法(实例通过设置自己的  __proto__ 指向承构造函数的 prototype 来实现这种继承)。

补充:原型问题

在不同的编程语言中,设计者利用不同的语言特征来描述对象。一种是基于类的方式描述对象,如 C++、Java 等。一种是基于原型描述对象,如 JavaScript。

JavaScript 的原型

原型系统概况起来,如下:

  • 如果所有对象都有私有字段 [[prototype]] ,就是对象的原型。
  • 对一个属性,如果对象本身没有,则会继续访问对象的原型,直到原型为空或者找到为止。

ES6+ 提供了一系列内置函数,以便直接操控原型:

  • Object.create:根据指定的原型创建新的对象,原型可以是 null
  • Object.getPrototypeOf:获得一个对象的原型
  • Object.setPrototypeOf:设置一个对象的原型
var cat = {
    say(){
        console.log("meow~");
    },
    jump(){
        console.log("jump");
    }
}

var tiger = Object.create(cat,  {
    say:{
        writable:true,
        configurable:true,
        enumerable:true,
        value:function(){
            console.log("roar!");
        }
    }
})

var anotherCat = Object.create(cat);
anotherCat.say();
var anotherTiger = Object.create(tiger);
anotherTiger.say();

早期版本的类与原型

new 运算接受一个构造器和一组调用参数,实际上做了几件事:

  • 以构造器的 prototype 属性为原型,创建新对象
  • 将 this 和调用参数传给构造器,执行
  • 如果构造器返回的是对象,则返回,否则返回第一步创建的对象

构造器模拟类的两种方法:一是在构造器中添加属性,二是在构造器的 prototype 属性上添加属性。

function c1(){
    this.p1 = 1;
    this.p2 = function(){
        console.log(this.p1);
    }
} 
var o1 = new c1;
o1.p2();

function c2(){
}
c2.prototype.p1 = 1;
c2.prototype.p2 = function(){
    console.log(this.p1);
}

var o2 = new c2;
o2.p2();

使用构造器实现一个不完整的 pollyfill

Object.create = function(prototype){
    var cls = function(){}
    cls.prototype = prototype;
    return new cls;
}

ES6 中的类

优先使用 ES6 语法定义类。

class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
  // Getter
  get area() {
    return this.calcArea();
  }
  // Method
  calcArea() {
    return this.height * this.width;
  }
}

类的继承

class Animal { 
  constructor(name) {
    this.name = name;
  }
  
  speak() {
    console.log(this.name + ' makes a noise.');
  }
}

class Dog extends Animal {
  constructor(name) {
    super(name); // call the super class constructor and pass in the name parameter
  }

  speak() {
    console.log(this.name + ' barks.');
  }
}

let d = new Dog('Mitzie');
d.speak(); // Mitzie barks.

@acodercc acodercc changed the title To Main侯: prototype 和 proto 区别(兑吧) To hys1440248234: prototype 和 proto 区别(兑吧) Apr 30, 2019
@acodercc acodercc added this to the 已回答 milestone Apr 30, 2019
@acodercc acodercc changed the title To hys1440248234: prototype 和 proto 区别(兑吧) 兑吧: prototype 和 proto 区别(一面) May 6, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants