2016-12-16 4 views
0

Ниже приведены два способа определения методов для объектов, созданных с помощью ключевого слова new. Я пытаюсь сравнить действия и эффекты каждого из них.Как работает fun.call, когда значение thisArg, предоставленное для вызова развлечения, является объектом Function.prototype?

1) Определен функциональный микс asCircle. Затем .call вводит смесь в Circle.prototype делегацией. Эффект состоит в том, что экземпляры new Circle теперь имеют такие методы, как .area размешивали.

var asCircle = function() { 
 
     this.area = function() { 
 
     return Math.PI * this.radius * this.radius; 
 
     }; 
 
     this.grow = function() { 
 
     this.radius++; 
 
     }; 
 
     this.shrink = function() { 
 
     this.radius--; 
 
     }; 
 
     return this; 
 
    }; 
 
     
 
    var Circle = function(radius) { 
 
     this.radius = radius; 
 
    }; 
 
    asCircle.call(Circle.prototype); 
 
    var circle1 = new Circle(5); 
 
    var circle2 = new Circle(6); 
 

 
    console.log(circle1.area());

2) Circle функция определяется как конструктор с radius собственности. Затем функции назначаются Circle.prototype свойствам. Фактически любые экземпляры new Circle теперь могут вызывать эти методы, например .area().

var Circle = function(radius) { 
 
    this.radius = radius; 
 
    }; 
 
    Circle.prototype.area = function() { 
 
    return Math.PI * this.radius * this.radius; 
 
    }; 
 
    Circle.prototype.grow = function() { 
 
    this.radius++; 
 
    }; 
 
    Circle.prototype.shrink = function() { 
 
    this.radius--; 
 
    }; 
 

 
    var circle1 = new Circle(5); 
 
    var circle2 = new Circle(6); 
 

 
    console.log(circle1.area());

Увидав реализацию 1 я опешил, видя, что .area может быть использован на любом новом Круге просто путем вызова функции asCircle с Circle.prototype как thisArg.

Почему эффект от использования .call в реализации 1 так же, как определить эти методы непосредственно на Circle.prototype как в реализации 2?

ответ

1

В первом фрагменте кода

1 .'Call»изменяет контекст 'это'. Когда вы звоните asCircle.call (Circle.prototype), asCircle вызывается с «этим» будучи Circle.prototype

2.Вс область/методы расти и сжиматься добавляются к прототипу, который отнесен к такой же эффект, как ваш второго фрагмент кода

Надеется, что это помогает

1

Почему эффект от использования .call в реализации-так же, как определить эти методы непосредственно на Circle.prototype как в реализации 2?

Function.prototype.call позволяет установить значение this в первый аргумент.

asCircle.call(Circle.prototype) установит this в asCircle на Circle.prototype.

// so now when you see ... 
this.area = function() { 
    return Math.PI * this.radius * this.radius; 
}; 

// it's the same as ... 
Circle.prototype.area = function() { 
    return Math.PI * this.radius * this.radius; 
} 

Но this внутри функции area является другой this, потому что внутри новой функции.Значение этого this определяется, когда эта функция вызывается: Например, circle1.area(); устанавливает значение this в area к circle1

// so now when you see ... 
return Math.PI * this.radius * this.radius; 

// it's the same as ... 
return Math.PI * circle1.radius * circle1.radius 

Замечания

И теперь вы научились чтобы написать код, который вы никогда не должны использовать. Вот разумное внедрение Circle с использованием двух методов

класс ES6 (это по сути то же самое, что ваш метод 2)

class Circle { 
    constructor(radius) { 
    this.radius = radius 
    } 
    area() { 
    return Math.PI * this.radius * this.radius 
    } 
    grow() { 
    this.radius++ 
    } 
    shrink() { 
    this.radius-- 
    } 
} 

Или функциональный способ, с помощью абстракции данных. Обратите внимание на отсутствие и насколько проще ваша жизнь из-за этого.

const makeCircle = r => ({radius: r}) 
const circleRadius = c => c.radius 
const circleArea = c => Math.PI * circleRadius(c) * circleRadius(c) 
const circleGrow = c => makeCircle(circleRadius(c) + 1) 
const circleShrink = c => makeCircle(circleRadius(c) - 1)) 
0

Принимая во внимание следующие объекты:

o = {}; 
f = function() { 
    this.s = "hello"; 
}; 

f.call(o) означает call f with this = o. Таким образом, f.call(o) точно такой же, как o.s = "hello". Эффект обеих реализаций тот же, потому что и o - это то же самое, это просто: -P

Фактический вопрос: какова магия, лежащая в основе прототипального наследования? Простыми словами, почему функция, принадлежащая прототипу Circle, может быть вызвана из экземпляра Circle?

Это связано с тем, что JavaScript (фактически любой объектно-ориентированный язык, обеспечивающий наследование во время выполнения) реализует так называемый механизм . Когда метод не найден в объекте, JavaScript будет продолжать поиск в прототипе этого объекта, затем в прототипе своего прототипа и так далее, до конца цепочки.

// Person is the parent class of President 
Person = function (name) { this.name = name; }; 
Person.prototype.iam = function() { return this.name; }; 

// President is a subclass of Person 
President = function() { Person.apply(this, arguments); }; 
President.prototype = new Person(); 

// trump is an instance of President and Person 
trump = new President("Donald"); 
trump.iam(); // "Donald" (ok) 
trump.hasOwnProperty("iam"); // false (wtf!) 
President.prototype.hasOwnProperty("iam"); // false (WTF!!) 
Person.prototype.hasOwnProperty("iam"); // true (finally...) 

Bonus (Object является родительским классом всего):

Object.prototype.hasOwnProperty("hasOwnProperty"); // true