about 7 years ago

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 with new:

( 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

 
about 7 years ago

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).

 
about 7 years ago

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".

 
about 7 years ago
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.

 
over 7 years ago

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 keyword delete
  • you cannot change the property enumerable
  • you CAN change the property writable from true to false but not the other way around
  • you cannot change configurable to true if its current state is false
 
over 7 years ago

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.

 
over 7 years ago

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.

 
over 7 years ago

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 &quot;. 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 staffusers 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 = [{&quot;email&quot;: &quot;test@test.com&quot;}, ...]

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.

 
over 7 years ago

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
 
over 7 years ago

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