New
- new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。
new 关键字会进行如下的操作:
-
- 创建一个空的简单JavaScript对象(即{});
-
- 链接该对象(设置该对象的constructor)到另一个对象; (为创建的对象添加属性和方法)
-
- 将步骤1新创建的对象作为this的上下文 ;(构造函数的this指向新对象)
-
- 如果该函数没有返回对象,则返回this。
-
// 若构造函数中返回this或返回值是基本类型(number、string、boolean、null、undefined)的值,则返回新实例对象;
-
// 若返回值是引用类型的值,则实际返回值为这个引用类型。
-
- var obj = {};
-
- 设置新对象的constructor属性为构造函数的名称,设置新对象的__proto__属性指向构造函数的prototype对象;
- obj.proto = functionNmae.prototype;
-
- 使用新对象调用函数,函数中的this被指向新实例对象;
- functionNmae.call(obj); //{}.构造函数();
-
- 将初始化完毕的新对象地址,保存到等号左边的变量中;
function Foo(){}
var o = new Object();
o.[[Prototype]] = Foo.prototype; // o.__proto__ = Foo.prototype;
Foo.call(o);
js实现new操作符
function New(func) {
var res = {};
if (func.prototype !== null) {
res.__proto__ = func.prototype;
}
var ret = func.apply(res, Array.prototype.slice.call(arguments, 1));
if ((typeof ret === "object" || typeof ret === "function") && ret !== null) {
return ret;
}
return res;
}
var obj = New(A, 1, 2);
// <=>
var obj = new A(1,2);
function Car() {}
car1 = new Car();
car2 = new Car();
console.log(car1.color); // undefined
Car.prototype.color = "original color";
console.log(car1.color); // original color
car1.color = 'black';
console.log(car1.color); // black
console.log(car1.__proto__.color) // original color
console.log(car2.__proto__.color) // original color
console.log(car1.color) // black
console.log(car2.color) // original color
- 显式return一个非对象的值,得到的是创建出的对象实例
function ori() {
this.name = "A";
return;
}
const obj = new ori();
console.info("", obj);
// ori { name: 'A’ }
// 并没有返回值(相当于undefined),得到的是对象实例。这里return数值类型和字符串的话,构造函数的结果都是对象实例
- return一个对象,得到的就是该对象,相应的this也指向这个对象
function ori() {
this.name = "A";
const inner = {
name: "B",
};
return inner;
}
const obj = new ori();
console.info("", obj);
// { name: 'B’ }
// 这时的返回的对象已经是inner对象。所以,构造函数中的返回对象的this也是要视具体的return来决定的
var f = new function(){
return "猜猜我能打印出来么";
}
console.log(f); // {}
alert(f); // [object object]
var h = new function(){
return new String("猜猜我能打印出来么");
}
console.log(h); // String {"猜猜我能打印出来么”}
console.log(typeof h); // object
alert(h); // 猜猜我能打印出来么 alert会默认执行toString()方法
var d = function(){
return "猜猜我能打印出来么"
}();
console.log(d); // 猜猜我能打印出来么
alert(d); // 猜猜我能打印出来么
var F = function () {};
Object.prototype.a = function () {
console.log('aa')
}
Function.prototype.b = function () {
console.log('bb')
}
var f = new F();
console.log(typeof F);
console.log(typeof f);
f.a(); // aa
// f.b(); // f.b is not a function
F.a(); // aa
F.b(); // bb
function foo() {
this.some = '222';
let ccc = 'ccc';
foo.name = 'SeriousLose';
foo.name1 = 'SeriousLose1';
foo.prototype.a = 'aaa';
}
foo.food = '扣肉';
foo.prototype.test = 'test';
let foo1 = new foo(); // `foo1`上有哪些属性,这些属性分别挂载在哪个地方
foo.prototype.test = 'test2'; // 重新赋值
// 1.this.some: foo1对象的属性
// 通过构造调用 foo的 this指向 foo1,所以 this.some挂载在 foo1对象下。
// 属性查找: foo1.some
// foo1.some直接读取 foo1的属性
// 2.foo1.test、 foo1.a: foo1对象的原型
// 根据上文提到的:构造/new调用函数的时候会创建一个新对象( foo1),自动将 foo1的原型( Object.getPrototypeOf(foo1))指向构造函数的prototype对象。
// 构造调用会执行函数,所以 foo.prototype.a='aaaaa'也会执行,单就赋值这个层面来说写在 foo外面和写在 foo里面是一样的。
// 属性查找:foo1.test、 foo1.a
// foo1本身没有找到,继续查找
// foo1的原型 Object.getPrototypeOf(foo1)上找到了 a和 test,返回它们,停止查找
// foo1.food和 foo1.name1:返回undefined
// 静态属性: foo.food、 foo.name1
// 两个属性跟 foo1没有关系,它是对象 foo上的两个属性(类似函数的: arguments/ prototype/ length等属性),称为静态属性。
// 只能通过 foo.food和 foo.name1来访问