Originally, I thought there is only one prototype
property per function until I read about __proto__
. Take a look here:
function Person(){
this.name = 'John';
}
Person.prototype // Object{}
// > constructor: function Person()
// > __proto__: Object
Person.__proto__ // function() {}
I was totally confused until I read this stackoverflow post. First of all, this graph helps to clarify things a bit:
The accept answer nails it:
__proto__
is the actual object that is used in the lookup chain to resolve methods, etc.prototype
is the object that is used to build__proto__
when you create an object withnew
:
( new Foo ).__proto__ === Foo.prototype
( new Foo ).prototype === undefined
As one of the users commented:
Ah! So prototype is not available on the instances themselves, but only on the constructor functions.
Here is a table to summarize the idea, considering the code blow:
var obj = {}
function Person(){
}
var p1 = new Person()
__proto__ | prototype | |
---|---|---|
obj | Object | undefined |
Person() | Function |
Object { constructor: function Person() __proto__: Object } |
p1 |
Object { constructor: function Person() __proto__: Object } |
undefined |
Note: obj.__proto__
is the Object.prototype and Person._proto__
is Function.prototype
The value of this
depends on how the function is called. There are four ways to call a function:
- function invocation
- method invocation
- constructor invocation
- apply/call invocation
Function Invocation
function add(){
console.log(this); // Window object
}
add(); // function invocation
In this case, this
inside the function add
is always bound to the global variable of the environment. (It is the Window object in this case because I run the code inside a browser)
A special case of function invocation is closure:
function add(){
function plus(){
console.log(this); // Window object
}
plus(); // function invocation
}
add(); // function invocation
It is tempting to think the this
value inside the plus()
function is tied to add
. However, that is not the case as it is explained in this post. plus
is still triggered via function invocation, so this
still points to the global variable.
Method Invocation
var person = {
name: 'John',
sayName: function(){
console.log(this.name);
}
}
person.sayName(); // Method invocation, which output "John"
When ever the dot notation is used, a method invocation happens. In this case, the value of this
equals to the object before the dot. So in this case, this == person
. Because person.name = "John"
, this.name == "John"
.
A special case is nested objects:
var foo = {
bar: {
sayName: function() {...}
}
}
foo.bar.sayName(); // this == bar not foo
whoever is closest to the function call is the value of this
.
Constructor Invocation
function Person(){
this.name = 'John'
}
console.log((new Person()).name); // Constructor invocation, outputs "John"
In this case, a new object has been created. The keyword this points to the newly created object. The function setName()
is equivelent to the following code:
function Person() {
var this = {}; // this is not valid, just for illustration
this.__proto__ = Person.prototype;
this.name = 'John’
return this;
}
Apply/Call Invocation
By using Apply
or Call
(or bind
), you can specify the value of this
:
function setName() {
this.name = "John";
}
setName(); // function invocaiton
console.log(this.name); // John
console.log(window.name); // John
var p1 = {};
setName.apply(p1); // apply invocation
console.log(p1.name); // John
When setName()
is called the first time, name
is created on the window
object. If we want to attach the name property to a different object, we can use apply or call (or bind).
Found a really good example that explains the differences among bind
, call
and apply
.
Both call
and apply
attaches this into function and executes the function immediately:
var person = {
name: "James Smith",
hello: function(thing) {
console.log(this.name + " says hello " + thing);
}
}
person.hello.call(person, "world"); // output: "James Smith says hello world"
The difference is that apply
can take in an array as the parameters but call has to list them individually:
call(obj, 'arg1', 'arg2', 'arg3');
var args = ['arg1', 'arg2', 'arg3'];
apply(obj, args);
bind
only attaches this with a function but id does not execute the function:
var person = {
name: "James Smith",
hello: function(thing) {
console.log(this.name + " says hello " + thing);
}
}
var helloFunc = person.hello.bind(person);
helloFunc("world"); // output: "James Smith says hello world"
You can also pass parameters to bind
:
bind(obj, arg1, arg2 ,arg3);
bind
is often used to express the intention of "this function is invoked with a particular this".
function test() {
console.log(this); // window
function inner(){
console.log(this); // window
}
inner();
}
The this
keyword inside the inner()
function also refers to the Window
object. This is because:
When a function is invoked as a function rather than as a method, the this keyword refers to the global object. Confusingly, this is true even when a nested function is invoked (as a function) within a containing method that was invoked as a method: the this keyword has one value in the containing function but (counterintuitively) refers to the global object within the body of the nested function.
To understand what configurable does, I did a little experiement:
var obj = {};
obj.name = 'cheng';
console.log(obj.name); // cheng
Object.defineProperty(obj, 'name', {configurable: false});
var des = Object.getOwnPropertyDescriptor(obj, 'name');
console.log('Writable: ' + des.writable); // true
console.log('Configurable: ' + des.configurable); // false
console.log('Enumerable: ' + des.enumerable); // true
delete obj.name; // the delete operation returns false
console.log(obj.name); // prints cheng
Object.defineProperty(obj, 'name', {writable: false});
des = Object.getOwnPropertyDescriptor(obj, 'name');
console.log('Writable: ' + des.writable); // false, so it is ok to change writable to false
Object.defineProperty(obj, 'name', {enumerable: false}); // "TypeError: Cannot redefine property: name, which means enumerable cannot be changed if configurable is set to false
I wonder if I can change those properties to true
if they started as false
:
var obj = {};
Object.defineProperty(obj, 'name', {configurable: false, writable:false, enumerable: false, value:'cheng'});
var des = Object.getOwnPropertyDescriptor(obj, 'name');
console.log('Writable: ' + des.writable); // false
console.log('Configurable: ' + des.configurable); // false
console.log('Enumerable: ' + des.enumerable); // false
Object.defineProperty(obj, 'name', {configurable: true}); // "TypeError: Cannot redefine property: name
Object.defineProperty(obj, 'name', {writable: true}); // "TypeError: Cannot redefine property: name
Object.defineProperty(obj, 'name', {enumerable: true}); // "TypeError: Cannot redefine property: name
Conclusion
When configurable is set fo false
:
- you cannot
delete
the property by using the keyworddelete
- you cannot change the property
enumerable
- you CAN change the property
writable
fromtrue to false
but not the other way around - you cannot change
configurable
totrue
if its current state isfalse
I did a little experiment just want to see what's the difference between defining object properties "normally" vs defining them using defineProperty
:
var obj = {};
Object.defineProperty(obj, 'name', {value: 'cheng'} );
console.log(obj.name);
var des = Object.getOwnPropertyDescriptor(obj, 'name');
console.log('Writable: ' + des.writable);
console.log('Configurable: ' + des.configurable);
console.log('Enumerable: ' + des.enumerable);
console.log('getter: ' + des.getter);
console.log('setter: ' + des.setter);
obj.name = 'test';
console.log(obj.name);
var obj2 = { name: 'cheng'};
var des2 = Object.getOwnPropertyDescriptor(obj2, 'name');
console.log('Writable: ' + des2.writable);
console.log('Configurable: ' + des2.configurable);
console.log('Enumerable: ' + des2.enumerable);
console.log('getter: ' + des2.getter);
console.log('setter: ' + des2.setter);
obj2.name = 'test';
console.log(obj2.name);
Here is the output:
"cheng"
"Writable: false"
"Configurable: false"
"Enumerable: false"
"getter: undefined"
"setter: undefined"
"cheng"
"Writable: true"
"Configurable: true"
"Enumerable: true"
"getter: undefined"
"setter: undefined"
"test"
Conclusion
When using defineProperty
, you have to define all of the properties by yourself, otherwise they are default to false
. But if the properties are define normally, then configurable
, enumerable
and writable
are all default to true
.
I had a local postfix mail server setup and trying to send an email with the following setting:
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_USE_TLS = False
EMAIL_HOST = 'localhost'
EMAIL_PORT = 25
DEFAULT_FROM_EMAIL = 'TEST <test@blah.com>'
Here is the code responsible for sending the email:
email = EmailMessage(
subject=subject,
body=message,
from_email='test@blah.com',
to=uers,
cc=applicants + cc_email,
reply_to=uers,
)
email.content_subtype = 'html'
try:
email.send(fail_silently=False)
Because the mail server is setup locally, there is no need to supply any user name or password. So I didn't bother to specify them in the settings.py. When I had the server running, here is the error that I encountered:
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/home/cheng/.virtualenvs/diandi/lib/python2.7/site-packages/django/core/mail/__init__.py", line 61, in send_mail
return mail.send()
File "/home/cheng/.virtualenvs/diandi/lib/python2.7/site-packages/django/core/mail/message.py", line 292, in send
return self.get_connection(fail_silently).send_messages([self])
File "/home/cheng/.virtualenvs/diandi/lib/python2.7/site-packages/django/core/mail/backends/smtp.py", line 100, in send_messages
new_conn_created = self.open()
File "/home/cheng/.virtualenvs/diandi/lib/python2.7/site-packages/django/core/mail/backends/smtp.py", line 67, in open
self.connection.login(self.username, self.password)
File "/usr/local/lib/python2.7.10/lib/python2.7/smtplib.py", line 585, in login
raise SMTPException("SMTP AUTH extension not supported by server.")
SMTPException: SMTP AUTH extension not supported by server.
The error message is very misleading, but this particular caught my eyes:
self.connection.login(self.username, self.password)
I didn't specify any username and password because I don't think I need them. Maybe I should put them back in? So I added the following lines:
EMAIL_HOST_USER = ''
EMAIL_HOST_PASSWORD = ''
Wholah, it worked! But why? So I looked under the hood:
self.username = settings.EMAIL_HOST_USER if username is None else username
self.password = settings.EMAIL_HOST_PASSWORD if password is None else password
When using the EmailBackend
class, a username and password can be passed in as parameters. I didn't pass either of them in my view function. Thus, Django defaults them to settings.EMAIL_HOST_USER
and settings.EMAIL_HOST_PASSWORD
. However, EMAIL_HOST_USER
and EMAIL_HOST_PASSWORD
are not defined in the settings file. So by the time self.connection.login(self.username, self.password)
is called, both username and password are None.
The error message SMTP AUTH extension not supported by server
is generated by python's own smtp library. I guess Django can throw a more meaningful error before this to make this error more apparent.
When django template renders parameters passed from views, it auto escapes characters that are considered as HTML entities.In English, that means characters like the double quote is convereted to "
. This default behavior may not be what you want so it is important to know how to turn it off.
Here is a situation that I encountered while working on a project. I need to pull all of the staff
users out of the database and then put their email addresses in the following format:
[{'email': 'user1@blah.com'}, {'email': 'user2@blah.com'}, ...]
In the view function, I pull the email addresses out of the database and converted them into JSON format:
def a_view_handler(request):
contacts = User.objects.get(is_staff=True)
email_list = []
for c in contacts:
if c.email:
email_list.append({'email': c.email})
return render(request, 'contacts.html', {'email_list': json.dumps(email_list)}
Then, in the template:
emails = {{ email_list }}
When I tested the page, this is what I see:
emails = [{"email": "test@test.com"}, ...]
This happened because when python converts the email_list
to json, it added double quotes around the key and value pairs. When Django template renders it, it auto escaped
the double quote character (meaning convert it to #quot;). To stop Django from doing that:
{% autoescape off %}
emails = {{ email_list }}
{% endautoescape %}
The autoescape block controls whether the content inside of it should be auto escaped or not. So use it when you dont want to see those HTML entities.
The common command line arguments that I use with the netstat
command:
-t: display tcp connections
-u: display udp connections
-l: display ports that are in LISTEN state
-p: display process id
-n: display ip addresses instead of host names
To see if a port has been occupied:
> netstat -tulpn | grep :port_number
I was trying to start a Postfix mail server on a Ubuntu 12.4:
> service postfix start
* Starting Postfix Mail Transport Agent postfix [ OK ]
> telnet localhost 25
Trying 127.0.0.1...
telnet: Unable to connect to remote host: Connection refused
What? I just started the service and it should be running on port 25 but telnet won't connect, so I had to dig more:
> netstat -tulpn | grep :25 | LISTEN
Nothing?! After some Google search, I located the log file at /var/log/mail.err
:
> less /var/log/mail.err
fatal: open lock file /var/lib/postfix/master.lock: cannot open file: Permission denied
No Permission? Ok, let's give it the permission:
> chown postfix.postfix -R /var/lib/postfix
> service postfix start
* Starting Postfix Mail Transport Agent postfix
...done.
> netstat -tulpn | grep :25 | grep LISTEN
tcp 0 0 0.0.0.0:25 0.0.0.0:* LISTEN 22166/master
Great, it worked!
P.S. chown postfix.postfix
= chown postfix:postfix
= chown owner_name:group_name