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

关于new需要知道的事 #2

Open
lovelmh13 opened this issue Jul 13, 2019 · 0 comments
Open

关于new需要知道的事 #2

lovelmh13 opened this issue Jul 13, 2019 · 0 comments

Comments

@lovelmh13
Copy link
Owner

lovelmh13 commented Jul 13, 2019

JavaScript中的new要区别于传统的面向对象语言的new。

我们要明确一下,在JavaScript中,构造函数是什么?

在JavaScript中的构造函数,只是写在new操作符后面的一个普通的函数,并不属于某个类,更不会实例化一个类。“构造函数“ 这个说法更确切的应该成为 “构造调用” 。后面为了习惯说法,还是称为构造函数。

new的时候,发生了什么呢?

new会劫持所有普通函数并用构造对象的形式来调用它。

function Foo() {
	console.log('rookie dog');
}
let a = new Foo();	// rookie dog
a; // {}

new通过构造函数调用,创建了的构造函数的“实例”,使其含有构造函数的属性,并且__proto__可以访问到造函数原型链中的属性:

  • 内部创建一个新的空对象
  • 把新对象的__proto__与构造函数的prototype联系上
  • 把新对象this绑定到构造函数上成为新的非空对象
  • 判断返回的新对象是简单类型还是复杂类型,复杂类型的话要返回构造函数本身(用过apply指向构造函数的那个对象),简单类型返回新的对象(__proto__与构造函数的prototype联系的对象)
    • (因为new 的时候就是这个么返回的,实例本来就是希望继承构造函数的属性,含有构造函数的原型的,并不希望得到的是构造函数的返回值)

让我们手动实现一个new

function create(Con, ...args) {
    let obj = {};
    obj.__proto__ = Con.prototype;
    let result = Con.apply(obj, args);

    if (result instanceof Object) {
        return result;
    } else {
        return obj;
    }
}

function Test(name, age) {
    this.name = name
    this.age = age
}
Test.prototype.sayName = function () {
    console.log(this.name)
}
const a = create(Test, 'rookie dog', 23);
console.log(a.name) // 'rookie dog'
console.log(a.age)  // 23
a.sayName()         // 'lmh'

注意事项

让我们看到上面new过程的第二点并联系上面的代码:将a内部的[[prototype]]连接到Test.prototype所指的对象。

在传统的面向对象的语言中,类可以被复制。但是在JavaScript中,并没有这种复制,而是通过[[prototype]]进行关联。如果要进行复制,需要使用Object.create()

Test.prototype.sayName = function () {
    console.log(this.name)
}

let a = new Test('rookie dog', 23)
a.sayName() // rookie dog

Test.prototype.sayName = function () {
    console.log(1)
}
a.sayName() // 1 --> 这是关联,而不是复制

当然,如果你改变了asayName,实际上是在a上面新加了一个sayName方法,这并不会影响到Test,因为sayName本是通过[[prototype]]来调用到的

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant